Local Caching
Musher tools cache pulled bundles on disk so that subsequent pulls skip redundant downloads. The CLI, Python SDK, and TypeScript SDK all share the same content-addressable cache layout.
Cache location
| Platform | Default path |
|---|---|
| Linux | ~/.cache/musher |
| macOS | ~/Library/Caches/musher |
| Windows | %LOCALAPPDATA%\musher\cache |
Override the location with environment variables:
# Set a custom cache directory
export MUSHER_CACHE_HOME=/path/to/custom/cache
# Or set an umbrella directory (cache, config, and data)
export MUSHER_HOME=/path/to/musherIn the Python SDK you can retrieve the active cache path programmatically with musher.cache_path().
Cache structure
All Musher tools (CLI, Python SDK, TypeScript SDK) use an identical content-addressable layout. Assets are stored as SHA-256-addressed blobs, so identical content across different bundles is stored only once.
~/.cache/musher/
├── CACHEDIR.TAG
├── blobs/
│ └── sha256/
│ └── a1/
│ └── a1b2c3d4e5f6... # Full SHA-256 digest as filename
├── manifests/
│ └── api.musher.dev/
│ └── acme/
│ └── code-review/
│ ├── 1.0.0.json # Cached manifest
│ └── 1.0.0.meta.json # Metadata (fetchedAt, TTL, digest)
└── refs/
└── api.musher.dev/
└── acme/
└── code-review/
└── latest.json # Mutable ref → resolved version- blobs/ — Content-addressable storage. Each file is named by its SHA-256 digest, grouped by a two-character prefix for filesystem performance.
- manifests/ — Cached bundle manifests with a sidecar
.meta.jsonfile tracking when the manifest was fetched and its TTL. - refs/ — Maps mutable tags (like
latest) to resolved versions. These expire quickly to reflect newly published versions. - CACHEDIR.TAG — Standard marker file that tells backup tools (like
resticorborgbackup) to skip this directory.
Cache freshness
| What | TTL | Applies to |
|---|---|---|
| Bundle manifests | 24 hours | CLI, Python SDK, TypeScript SDK |
Mutable refs (e.g. latest) | 5 minutes | CLI, Python SDK, TypeScript SDK |
Integrity verification
All Musher tools compute a SHA-256 checksum for every downloaded asset and compare it against the digest in the bundle manifest. If a checksum does not match, the pull fails with an integrity error.
Verification is enabled by default. In the Python SDK you can control it with the verify_checksums configuration option.
Managing the cache
Inspect the cache
See what bundles are cached and how much space they use:
musher cache infoimport musher
info = musher.cache_info()
print(f"Cache: {info.path}")
print(f"Size: {info.total_size_bytes} bytes across {info.bundle_count} bundles")
for bundle in info.bundles:
for version in bundle.versions:
status = "fresh" if version.is_fresh else "stale"
print(f" {bundle.namespace}/{bundle.slug} v{version.version} ({status})")import { MusherClient } from "@musher-dev/musher-sdk";
const client = new MusherClient();
// Aggregate statistics
const stats = await client.cache.stats();
console.log(`${stats.entryCount} entries (${stats.freshCount} fresh, ${stats.staleCount} stale)`);
console.log(`${stats.blobCount} blobs, ${stats.blobSizeBytes} bytes on disk`);
// List individual entries
for (const entry of await client.cache.list()) {
const status = entry.fresh ? "fresh" : "stale";
console.log(` ${entry.namespace}/${entry.slug}@${entry.version} (${status})`);
}List cached bundles
List all bundles in the local cache:
musher cache list
# Structured output for scripting
musher cache list --jsonForce re-download
musher load acme/code-review --forceimport musher
# Remove the cached version, then pull fresh
musher.cache_remove("acme/code-review")
bundle = musher.pull("acme/code-review")import { MusherClient } from "@musher-dev/musher-sdk";
const client = new MusherClient();
// Remove the cached version, then pull fresh
await client.cache.remove("acme", "code-review");
const bundle = await client.pull("acme/code-review");Clean expired entries
Remove expired manifests and refs, then garbage-collect unreferenced blobs:
musher cache cleanimport musher
musher.cache_clean()import { MusherClient } from "@musher-dev/musher-sdk";
const client = new MusherClient();
await client.cache.clean();Clear everything
Remove all cached data. The CLI prunes unreferenced entries while the SDKs delete the entire cache directory:
musher cache pruneimport musher
musher.cache_clear()import { MusherClient } from "@musher-dev/musher-sdk";
const client = new MusherClient();
await client.cache.purge();