Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4928a63
feat(workspace): a read-only direct mount, its tools reading disk as …
Oct 19, 2026
6aadccb
Merge main (76623a39) into the direct mount, taking #547's drafts spe…
Oct 19, 2026
42e0533
fix(workspace): the direct mount's first review round, Esther-2584's …
Oct 19, 2026
e566cc6
Merge main (6345d27d) into the direct mount
Oct 19, 2026
da45fa7
fix(workspace): every mount's path parse stays as it was; the direct …
Oct 19, 2026
a25a425
fix(workspace): the direct mount's second review round
Oct 19, 2026
dac5bf4
fix(workspace): the direct mount's third review round
Oct 19, 2026
6c6cef4
test(workspace): the 16-at-a-time test holds the files' calls until s…
Oct 19, 2026
996d11f
Merge main into the direct mount, with #463
Oct 19, 2026
6c52d76
fix(workspace): a direct mount whose root has moved nests what lies b…
Oct 19, 2026
395e1fd
Merge main into the direct mount, with #576
Oct 19, 2026
678066b
Merge main into the direct mount, with #536
Oct 19, 2026
50e8fb7
fix(workspace): a direct mount's checks read disk beneath the root th…
Oct 19, 2026
09ccb5e
test(workspace): a moved direct root nests a mount its real root alon…
Oct 19, 2026
e07eb6b
fix(workspace): a moved direct root nests a configured mount beneath …
Oct 19, 2026
c5eb97e
refactor(workspace): a start and a moved direct root place a mount wi…
Oct 19, 2026
4d182eb
docs(workspace): say what a moved direct root resolves, and the race …
Oct 19, 2026
10089c1
test(workspace): the gone-file test finds the listing's look at its f…
Oct 20, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions changelog.d/workspace-direct-mount.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
- **A direct workspace mount, for a checkout an agent reads:** a mount whose config sets `backend: 'direct'` (the default is `'chronicle'`, the store-backed kind every mount has been) is read straight from disk. `read`, `read_image`, `ls`, `glob` and `grep` give its files as they are when they run, with no scan, watcher or pass, so no call waits behind one, and none of its files go into the store. It's read-only: the workspace refuses a direct mount with any `mode` but `'read-only'`, and one that sets `watch` other than `'never'`, `watchDebounceMs`, `watchRootPollMs`, a `wakeOnChange` that would wake, or `autoMaterialize: true`, since none of them would ever act there. Its paths, links, `include`, other mounts' directories, size limit and walk cap hold as on a store-backed mount. Where it differs:
- **What its listings say:** each file with its `size`, and no state or MIME type, or, for a link the mount doesn't follow or another entry it doesn't take, with why as `note`. A listing looks at each entry with `lstat`, so it lists a file it can't open with its size, and reading that file says why. `grep`'s results say `version: 'disk'`, and it lists under `skipped` a binary file, one over the size limit and one it doesn't read, each with why. `read` refuses a binary file and one over the size limit, as a store-backed mount's `read` refuses one it never took in from disk.
- **Its ignore list:** with none in its config, it takes `node_modules`, `dist`, `.git`, `build`, `coverage`, `target`, `__pycache__` and `.venv`. Walks of the whole mount pass over what the list covers, and a path a listing, glob or grep names, or its pattern's directory, is walked all the same, as a sync naming a path walks it on a store-backed mount. `ls` without a path, and `status`, give a mount configured direct its `backend`, as it runs this session, and the list it goes by. A direct mount's `status` gives only its `path`, `mode`, `backend` and `ignore`, since it keeps nothing to count.
- **Its root:** it reads beneath whatever directory is at its path now, with no check against the one a store-backed run of it last agreed with. Where its root now lies elsewhere than the last start placed it, as when a link it's configured through is repointed, it nests what a start would nest there now: a mount configured beneath its path, where that path leads, and a mount whose root the last start placed beneath where its root lies now, or whose configured path lies beneath a directory that start found there. Their files are those mounts'. A mount configured elsewhere whose own root has moved since, and the other mounts' own placements, wait for the next start, so a direct root moved into another mount's directory is still that mount's directory too.
- **`sync`:** passes over it, listing it under `skipped`. `materialize` passes over it too, naming it under `skipped`, as it does any read-only mount.
- **A mount the store holds changes on that disk lacks** (a draft, a workspace deletion, a conflict, or an intent it can't read, on the branch selected at a start, where its `include` covers it) runs store-backed from that start, so they stay in view. It runs unwatched, and with the direct default ignore list where its config names none. The workspace says so on stderr and in one ops alert (`workspace-mount-not-direct`). The alert first gives the two ways to start such a mount direct: give each change up with a sync of its path, or configure the mount `'chronicle'` and read-write, materialize it, follow materialize's answer, and restore its direct config; its next start then runs it direct. Where an intent it can't read is held, it says to sync that path. Then it names every such mount and what's held there, counting an intent it can't read as one. A mount that ran direct and runs store-backed again takes in what disk changed meanwhile as its listings, searches and syncs reach it, as an unwatched store-backed mount does.
- **Tool descriptions:** `ls`, `glob`, `grep` and `sync` gain a sentence about the direct kind only on a host with a mount that runs direct; elsewhere they're unchanged.
Loading
Loading