vx cache clean
vx cache clean evicts old or oversized cache entries, or with no
bound clears the cache. It operates on the entries and
<hash>.tar.zst artifacts of the store the workspace’s index records
(~/.vx/<id>/cache, shared by every checkout of the repository), or of
<cacheDir> itself when the workspace names one (cache.dir,
VX_CACHE_DIR, --cache-dir).
vx cache clean --older-than <duration> # Drop entries last used before now - duration (up to 1h slack).vx cache clean --max-size <size> # After age-based pruning, evict LRU until under <size>.vx cache clean ... --dry-run # Say what either policy would reap; delete nothing.vx cache clean ... --format json # { dryRun, evicted, bytesFreed, orphans, orphanBytes }vx cache clean ... --cache-dir <path> # The cache a run with the same flag uses.vx cache clean # No bound: clear the whole cache (below).vx cache clean --global # Also clear every other repository's store.Examples
Section titled “Examples”$ vx cache clean --older-than 30d✓ vx cache clean freed 1.3 GB
42 entries
$ vx cache clean --older-than 30d # after a SCHEMA_VERSION bump✓ vx cache clean freed 1.3 GB
42 orphaned artifacts
$ vx cache clean --older-than 30d --dry-run› vx cache clean would free 1.3 GB (dry run)
42 entries · 3 orphaned artifactsOptions
Section titled “Options”| Option | Meaning |
|---|---|
--older-than <duration> |
drop entries last used before now minus the duration |
--max-size <size> |
then evict the least recently used until under the size |
--dry-run |
say what would go; delete nothing |
--global |
with no bound, also clear every other repository’s store |
--format json |
the result as one object |
--cache-dir <path> |
the cache a run with the same flag uses |
Both bounds may be combined: age-based eviction runs first, then LRU eviction if the total is still over the size cap. No run evicts anything: to bound the cache, run this from a schedule or CI.
A clean with a bound also drops run history and hash memos older than 30 days; a run never does.
Both flags take either form: --older-than 30d or --older-than=30d.
Duration units: s, m, h, d, case-insensitive. Examples:
30d, 24h, 60m, 30s, 30D.
Size units: K, M, G, T (powers of 1024), case-insensitive, with an optional B or iB (512MB, 32KiB).
Optional B suffix is accepted. Examples: 500M, 1G, 100K, 2T,
500MB, 1gb. A bare number is refused here: --max-size 10 would
read as ten bytes and evict nearly everything, and nobody means that —
write 10G, or 10B when bytes really are the unit.
A zero bound is rejected. --max-size 0 and --older-than 0d would
evict every entry in the cache, which is far more often a
computed-to-zero retention than an intent. vx cache clean with no
bound clears the whole cache when that is really what you want.
Orphans
Section titled “Orphans”After eviction, prune sweeps the cache directory for orphans: an
artifact (a <hash>.tree directory, or a <hash>.tar.zst) the index
has no row for (a SCHEMA_VERSION bump drops every table and leaves
the artifacts behind, as a deleted cache.db does) and a
<hash>.tree.tmp-* or <hash>.tar.zst.tmp-* a save that crashed never
renamed. A run that asks for an orphan’s key indexes it again from its
bytes and hits; one no task asks for again is only reclaimed here. The
policy judges a row-less artifact as it judges an entry, by its file
time plus an hour (a hit renews a file time over an hour old): another
vx version sharing the store may still use it. A temp goes once it is an
hour old; nothing younger than an hour is taken. Only the names vx writes are taken:
<hash> is the key’s 16 lowercase hex digits and the temp suffix is
the one a save makes, so a release.tar.zst beside the index in a
cache.dir you share is never touched (item 968). The converse, an
index row whose artifact is gone (deleted by hand), is dropped by the
same prune, and its bytes count toward neither --max-size nor the
evicted total: they are on no disk, and counting them evicted real
entries to make room for them (item 975). A row used within the hour
is kept until a later prune, but its bytes are left out all the same
(item 1081). The sweep runs on every prune, under
either flag, and reports separately from the policy’s evictions.
--dry-run
Section titled “--dry-run”--dry-run picks the victims under the same policy and counts the
orphans the sweep would take, then returns without touching the index
or the directory; the real prune with the same flags reaps exactly what
it named (an in-flight save aside). On an index an earlier vx wrote,
which the real prune resets first, it reads the index as that reset
leaves it: the shared store’s entries still face the policy, and every
artifact in the workspace’s own directory is row-less, judged by the
policy on its file time (item 1083).
Concurrent runs
Section titled “Concurrent runs”A prune that deletes waits for a vx run on the same workspace to
finish first (the run’s lock; it says [vx] waiting for another vx run (pid N) on this workspace to finish… after a second), so it never
evicts what that run is restoring. One started by a task of that run
is refused instead: the run holds the lock until the task ends. A run it cannot see — another
workspace sharing the --cache-dir — survives a prune anyway: an
artifact that vanishes before its restore is a miss, and the task runs
(caching).
Which cache
Section titled “Which cache”vx cache clean resolves the workspace root from cwd and honors a
defineWorkspace({ cache: { dir } }) override — it prunes the same
directory a run would use. --cache-dir <path> (cwd-relative, as on
vx run) names another one, so a run that wrote elsewhere can be
pruned there.
Other subcommands
Section titled “Other subcommands”clean is the only vx cache subcommand: the statistics other runners
put under a cache verb — the directory, the entry count, the size —
are part of vx info, and vx cache stats, list, ls,
gc and their neighbours say so (list also names vx last --list;
clear, purge, reset and wipe name a bare vx cache clean) rather than printing a bare “unknown subcommand”.
With no bound: clear the cache
Section titled “With no bound: clear the cache”vx cache clean with neither --older-than nor --max-size clears
the whole cache: the cache directory (.vx/cache, or cache.dir /
--cache-dir: the index and this workspace’s run history, so vx last
and vx why start over) and the store its index names, where the
entries live (~/.vx/<id>/cache, shared by this repository’s
checkouts, so their entries go too). --global also clears every other
repository’s store under ~/.vx (~/.vx/*/cache); it takes no bound
and no --cache-dir. .vx/workspace.ts, the lock and .vx/.gitignore
sit outside them and stay; a cache.dir that holds them (.vx, the
workspace root) is refused. A cache.dir you named may be shared
(build/, ~/.cache), so there only what vx wrote goes (the index,
its artifacts, run history, its * .gitignore); your own files stay,
and the directory goes only if that empties it. A directory with no
cache.db is not a vx cache and is left alone, and the store an index
names goes only if it is one (.vx/<id>/cache holding a store.db): the
index is a file in the checkout, which a commit or a restored CI cache
could point at any directory. A workspace that never ran says
› vx cache clean nothing to free. The next run misses every task once
and saves again.
$ vx cache clean✓ vx cache clean freed 1.4 GB
.vx/cache /home/me/.vx/3f2a9c01b4d5e6f7/cache
$ vx cache clean --global --dry-run› vx cache clean would free 3.1 GB (dry run)
.vx/cache /home/me/.vx/3f2a9c01b4d5e6f7/cache /home/me/.vx/9b8e7d6c5a4f3e2d/cacheIt waits for a vx run on this workspace to finish first (the run’s
lock), as a trim does. With --format json it prints
{ dryRun, cleared, bytesFreed } (schemas/cache.json), cleared
listing the directories.
Exit codes
Section titled “Exit codes”| Code | When |
|---|---|
0 |
pruning completed (zero or more entries evicted). A workspace that never ran has no cache: › vx cache clean nothing to free, and nothing is created |
1 |
parse error, missing policy, or workspace-discovery error |