Docs
The four states
The manifest maps every path in the repository to one of four states. On the person's side, one component answers every file operation from the table below. Nothing else in the runtime decides.
Per operation
| Operation | Visible | Read-only | Occluded | Absent |
|---|---|---|---|---|
lookup, stat | Real | Real | ENOENT, logged | ENOENT, and the request is held for a named approver |
| Listing the parent directory | Listed | Listed | Not listed | Not listed |
open for reading, read | Passthrough | Passthrough | ENOENT | ENOENT |
write, truncate, rename, unlink | Passthrough | EACCES, logged | ENOENT | ENOENT |
| Create a new path | Allowed where the new path resolves Visible | EACCES | ENOENT for the parent | ENOENT for the parent |
| Language server | Full | Full | A declaration stub, for modules a visible file imports | Nothing |
| File-change events | Delivered | Delivered | Never | Never |
| On the build's side | Present | Present | Present | Never mounted |
Silent and held
Two behaviours, deliberately different. Occluded is silent: the file must not be known to exist, so the process gets ENOENT and the attempt goes on the record. Absent is held: asking for credentials or a customer data seed is a decision someone must make. The request is surfaced inline on the door, an agent run pauses, and the named approver is asked. Approval amends the grant, and the workspace reloads with the path mounted.
What happens on an attempt is an attribute of each rule: on_attempt: silent or on_attempt: held. The defaults are silent for Occluded and held for Absent. An admin may mark an Absent compartment silent, for export-controlled source whose existence must not be acknowledged, or an Occluded file held. Four states decide mounting and reading; one attribute decides what a probe does.
Rules beyond the table
- A directory whose children are all Occluded is itself
ENOENT. A mixed directory lists only its permitted children. - File metadata carries neither the real link count nor the real child count, so a listing does not reveal how much is missing.
- A lookup of an Occluded file takes as long as a lookup of a file that does not exist.
- Moving a visible file into an Occluded directory resolves at the destination, like a new file, and gets
ENOENT. - When a reload lowers a path's state, open handles on that path are checked again: further reads fail. What an editor already holds in its own memory remains, as a person's memory does.
Never in the view, by default
| Path class | State | Why |
|---|---|---|
.git/** | Absent from the person's side, present on the build's side | History holds every version of every Occluded file. Git runs on the build's side, as named verbs |
Build output: dist/**, build/**, .next/**, coverage/**, *.map | Occluded | Bundles and coverage carry Occluded code. The preview is served from the build's side |
Package manifests and lockfiles: package.json, tsconfig*.json, pyproject.toml, Makefile | Read-only for contractor profiles | Whoever edits scripts defines what the build runs. An admin may grant Visible per profile |
Secrets and seeds: .env*, **/secrets/**, db/seeds/** | Absent | Never in the workspace's memory |
node_modules/**, .venv/** | Read-only | The language server needs their types; nobody needs to edit a dependency |
Resolution and attempts
Every Occluded lookup is logged, but not every lookup is an attempt. Editors and build tools look for files as a matter of course while resolving imports; those lookups are recorded as resolution and never alert. A shell cat, an editor open, an agent's read_file or a script's read of an Occluded path is an attempt, and alerts. See The ledger.