Skip to content

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.

~/.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.parquet

Per-file write is atomic via filelock + rename — concurrent writers can’t corrupt the cache.

RuntimeBackendLocation
BrowserIndexedDBmostlyright-cache-v1 database
Node.jsFS$HOME/.mostlyright/cache-ts/
Workers / no-FSIn-memory Mapper-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 MemoryStore

Override per-call:

import os
os.environ["MOSTLYRIGHT_CACHE_DIR"] = "/tmp/mostlyright-cache"
# …or pass a directory to the cache module directly:
from mostlyright.weather.cache import set_cache_root
set_cache_root("/tmp/mostlyright-cache")

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:

SourceSkip condition
ObservationsCurrent LST month for the station (incomplete data)
ClimateCurrent UTC year (NWS CLI publishes incrementally)
ForecastsCurrent 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.

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.

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");

Pre-v1.0 the directory was ~/.tradewinds/; v1.0 moved to ~/.mostlyright/. If you have an old cache, see Migration → Cache directory.

Terminal window
# Python — list cached files
find ~/.mostlyright/cache -name '*.parquet' | head -20
# Disk usage
du -sh ~/.mostlyright/cache/{observations,climate,forecasts}/
// TypeScript — list cached keys
import { defaultCacheStore } from "@mostlyrightmd/core/internal/cache";
const cache = await defaultCacheStore();
for await (const key of cache.keys()) {
console.log(key);
}
Terminal window
# Python (full nuke)
rm -rf ~/.mostlyright/cache
# Or per-station
rm -rf ~/.mostlyright/cache/observations/KNYC
// TypeScript
const cache = await defaultCacheStore();
await cache.clear();
  • Python: per-file filelock. Two research() calls racing to write 2024/01.parquet for 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).

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.