What It Does
A workspace can be described entirely in YAML and loaded with one call —load_config in Python, loadWorkspaceConfigFile in TypeScript. This page is the key-by-key reference. Both languages read the same document and refuse the same things: an unknown key is an error, not a warning, so a typo fails loudly at load rather than silently doing nothing.
Top level
Mount block
The read policy
read: bounded serves cached bytes without asking the backend, for as long as ttl: allows. read: fresh revalidates against the backend’s content token before serving a cached copy, at the cost of one backend stat per file read.
fresh is refused at mount time on a backend that cannot honour it, rather than quietly behaving as bounded:
- the backend does not cache reads at all, so the check has no gate to run at (
ram,disk,redis,postgres,mongodb,chroma,qdrant); - or it caches reads but stamps no token the check can compare, because its
statand its read return different kinds of value, or its read stamps nothing.
fresh today.
The bound
ttl: lives only in a mount block. At the top level it would sit beside index: {ttl: ...} and mean a different thing, so the workspace-level default is read: alone and a workspace-level bounded takes 600 seconds — the same default the index uses, so bodies and listings expire together.
Two shapes are refused, because a read/ttl pair that disagrees is almost always a typo:
ttl:with noread:— the bound pins nothing.read: boundedwritten out with nottl:— an explicit policy with an implicit bound.
read: is a different thing and is fine: it takes the default.
Across a snapshot
A snapshot records each mount’s policy and bound, and a restore keeps them — but only for a mount the loader rebuilds from the saved state itself. A mount handed back throughmounts= takes the default (bounded, 600s) instead.
That is deliberate: a mount saved with redacted credentials has to be handed
back, and what comes back may be a different backend entirely. Replaying a saved
fresh onto one that cannot revalidate would refuse a restore that had nothing
wrong with it. The saved policy still has to be a policy mirage knows — a
snapshot naming an unknown one is refused whether or not the mount is overridden.
Declare read: again on an overridden mount if you want it back.
What the bound promises
The bound is stamped on a cache entry when that entry is written, and the store expires it from there. So the bound that applies to an entry is the one the mount that wrote it declared, not the one the mount reading it declares. Within a workspace those are the same mount, sottl: means what it says.
They can differ in three situations, and in each the older bound wins until the
entry expires on its own:
- two workspaces sharing one Redis cache declare different
ttl:for the same prefix; ttl:is lowered and the process restarts against a surviving shared cache;- a snapshot is restored into a mount whose
ttl:differs from the one that took the snapshot.
ttl: should agree
across the workspaces that use it.
Not yet accepted
read: pinned is refused, naming the layer it needs: pinning reads to the content a commit records requires a version layer mirage does not have. There is no write: key yet. Both are reserved rather than silently ignored, so a config that names one fails at load instead of appearing to work.