Guides
Cache
Mostly Right is local-first. Every call writes back-of-tape to a cache so subsequent calls in the same window are local-only. The Python SDK uses parquet under ~/.mostlyright/; the TypeScript SDK auto-detects IndexedDB (browser) → Node FS → in-memory.
Layout (Python)
Section titled “Layout (Python)”~/.mostlyright/cache/├── observations/│ ├── KNYC/│ │ ├── 2024/│ │ │ ├── 01.parquet ← per-month files│ │ │ ├── 02.parquet│ │ │ └── ...│ │ └── 2025/│ │ └── ...│ └── KLAX/├── climate/│ └── KNYC/│ ├── 2024.parquet ← per-year files (NWS CLI cadence)│ └── 2025.parquet└── forecasts/ └── iem_mos/ └── KNYC/ └── 2026/ └── 05.parquetPer-file write is atomic via filelock + rename — concurrent writers can’t corrupt the cache.
Layout (TypeScript)
Section titled “Layout (TypeScript)”| Runtime | Backend | Location |
|---|---|---|
| Browser | IndexedDB | mostlyright-cache-v1 database |
| Node.js | FS | $HOME/.mostlyright/cache-ts/ |
| Workers / no-FS | In-memory Map | per-process; lost on restart |
Auto-detection picks the right store:
import { defaultCacheStore } from "@mostlyrightmd/core/internal/cache";
const cache = await defaultCacheStore(); // IndexedDB OR FsStore OR MemoryStoreOverride per-call:
import osos.environ["MOSTLYRIGHT_CACHE_DIR"] = "/tmp/mostlyright-cache"
# …or pass a directory to the cache module directly:from mostlyright.weather.cache import set_cache_rootset_cache_root("/tmp/mostlyright-cache")import { research } from "mostlyright";import { MemoryStore } from "@mostlyrightmd/core/internal/cache";
// Ephemeral cache for testsconst cache = new MemoryStore();await research("KNYC", "2025-01-06", "2025-01-12", { cache });
// Opt out entirelyawait research("KNYC", "2025-01-06", "2025-01-12", { cache: null });Skip rules — when the cache does NOT write
Section titled “Skip rules — when the cache does NOT write”The cache deliberately skips writes for volatile windows — months that aren’t yet stable:
| Source | Skip condition |
|---|---|
| Observations | Current LST month for the station (incomplete data) |
| Climate | Current UTC year (NWS CLI publishes incrementally) |
| Forecasts | Current LST month |
This matches the parity invariant: a backtest from 2020-01-01 to 2024-12-31, run on 2025-03-15, gets stable data. A backtest run on 2024-12-15 also gets stable data — the incomplete 2024-12 window is fetched fresh every time, never cached.
What is “current LST month”?
Section titled “What is “current LST month”?”LST (Local Standard Time) — never daylight-savings shifted. The cache uses the station’s IANA tz from the registry to compute LST. KNYC is America/New_York (UTC−5); KLAX is America/Los_Angeles (UTC−8).
A query at 2025-03-15T07:00:00Z for KNYC resolves to LST 2025-03-15T02:00 → current LST month 2025-03. The 2025/03.parquet file is fetched fresh; 2025/02.parquet is cached.
Schema-version invalidation
Section titled “Schema-version invalidation”The TS cache stamps every entry with _cache_schema_version (matching Python’s parquet kv_metadata). When a Phase-18-class fix changes wire shapes (e.g. ASOS integer-°F precision), the new SDK version bumps the schema-version string and silently re-fetches every stale entry on next call.
Pre-bump cached values are invalidated automatically — no manual cache clears needed.
import { versionedCacheStore } from "@mostlyrightmd/core/internal/cache";
// Pass-through if you build your own cache; the default already wraps.const versioned = versionedCacheStore(myCache, "v2-phase18-integer-f");Cache-directory migration
Section titled “Cache-directory migration”Pre-v1.0 the directory was ~/.tradewinds/; v1.0 moved to ~/.mostlyright/. If you have an old cache, see Migration → Cache directory.
Inspecting the cache
Section titled “Inspecting the cache”# Python — list cached filesfind ~/.mostlyright/cache -name '*.parquet' | head -20
# Disk usagedu -sh ~/.mostlyright/cache/{observations,climate,forecasts}/// TypeScript — list cached keysimport { defaultCacheStore } from "@mostlyrightmd/core/internal/cache";
const cache = await defaultCacheStore();for await (const key of cache.keys()) { console.log(key);}Wiping the cache
Section titled “Wiping the cache”# Python (full nuke)rm -rf ~/.mostlyright/cache
# Or per-stationrm -rf ~/.mostlyright/cache/observations/KNYC// TypeScriptconst cache = await defaultCacheStore();await cache.clear();Concurrency safety
Section titled “Concurrency safety”- Python: per-file
filelock. Tworesearch()calls racing to write2024/01.parquetfor the same station serialize. Reads are lock-free (parquet is immutable post-rename). - TypeScript: IndexedDB is transactional. The FS store uses temp-file + atomic-rename. In-memory store is single-process (use a real store for multi-process).
Cross-language compatibility
Section titled “Cross-language compatibility”Python and TypeScript caches do not share files. Python writes parquet; TS writes JSON. The caches live in different directories (cache/ vs cache-ts/) and use different schema-version tags. Cross-language read compatibility is not on the roadmap — each SDK manages its own back-of-tape.
See also
Section titled “See also”- Migration → Cache directory —
~/.tradewinds/→~/.mostlyright/rename - Ingest strategies —
exact_windowvswarm_cachevshosted - Browser integration — IndexedDB quotas and CORS
- API reference:
mostlyright.weather.cache(Python) ·@mostlyrightmd/core/internal/cache(TS)