# Conflicts: # apps/cli/cordis.yml # apps/cli/package.json # apps/cli/tests/tui-keyless-smoke.e2e.ts # apps/web/tests/details-session-lifecycle.e2e.ts # apps/web/tests/snapshots/code-mode-round/ui.expected.md # apps/web/tests/snapshots/cordis-tool-round/ui.expected.md # apps/web/tests/snapshots/fresh-round-trip/ui.expected.md # apps/web/tests/snapshots/lifecycle-chrome/hero.expected.md # apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md # apps/web/tests/snapshots/live-interactions/cancel.expected.md # apps/web/tests/snapshots/live-interactions/error-auth.expected.md # apps/web/tests/snapshots/live-interactions/retry.expected.md # apps/web/tests/snapshots/message-actions/ui.expected.md # apps/web/tests/snapshots/question-composer/answered.expected.md # apps/web/tests/snapshots/seeded-history/ui.expected.md # apps/web/tests/snapshots/steering/mid-steer.expected.md # apps/web/tests/snapshots/steering/settled.expected.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/event-producer-consumer.md # docs/user/guide/config.i18n.yaml # docs/user/guide/config.md # docs/user/guide/config.zh.md # docs/user/guide/index.i18n.yaml # docs/user/guide/index.md # docs/user/guide/index.zh.md # examples/acp-agent/tests/snapshots/subagent-fork/session.1.jsonl # examples/acp-agent/tests/snapshots/subagent-mixed/session.2.jsonl # examples/cordis-agent/cordis.yml # examples/cordis-agent/tests/cordis-tools.e2e.ts # examples/headless-agent/tests/semantic-checkpoint-snapshots/tool-outcome-unknown/session.expected.jsonl # examples/headless-agent/tests/subagent-inheritance-snapshots/parent-override/parent.expected.jsonl # examples/tui-agent/code-mode.cordis.yml # examples/tui-agent/cordis.yml # packages/examples/tui-demo/README.md # packages/examples/tui-demo/README.zh.md # packages/host/apiproxy/README.i18n.yaml # packages/pty/tool-bash-persistent/README.i18n.yaml # packages/ui/tui/tests/snapshots/status-diagnostics-narrow.expected.txt # packages/ui/tui/tests/snapshots/status-diagnostics.expected.txt # pnpm-lock.yaml # scripts/snapshots/python-sdk-single-exe/advanced/result.json # scripts/snapshots/python-sdk-single-exe/advanced/session.1.jsonl # scripts/snapshots/python-sdk-single-exe/advanced/session.2.jsonl # scripts/snapshots/python-sdk-single-exe/advanced/session.jsonl
fs/ - filesystem capability family
English | 中文
The filesystem stack: a provider seam (text IO + atomic mutation with an optional version guard), a local implementation, a policy gate plugin (observed-state + read-before-edit + version-guarded write/edit), the model-facing file tools + executor, and the bash-backed discovery tools. All product packages.
| Package | Role | ctx key |
|---|---|---|
fs/ |
Provider seam: text IO + atomic mutation primitives (optional version guard); owns the fs/* policy events |
ctx.fs |
fs-local/ |
Local-filesystem FileSystem implementation |
(registers ctx.fs) |
fs-sandbox/ |
Sandbox-enforcing FileSystem: extends fs-local and fences write/edit by the per-call mode + workspace root policy (read-only denies, workspace-write contains to the session workspace + temp roots), reads pass through |
(registers ctx.fs) |
fs-policy/ |
Policy gate plugin: observed-state + read-before-edit + version-guarded write/edit, via the fs/* event gate |
(no service — fs/* listeners) |
tool-fs/ |
Model-facing read/write/edit tools AND the executor (reads via ctx.fs, owns read windowing, dispatches fs/*); preserves filesystem semantics for session-cwd-relative paths and advertises sandbox escalation fields when the mounted ctx.fs confines |
(registers on ctx.tools) |
tool-fs-search/ |
Model-facing glob/grep discovery tools when rg is available on the bash executor PATH, backed by fixed ripgrep commands through ctx.bash, NOT by ctx.fs provider methods |
(registers on ctx.tools) |
tool-str-replace-editor/ |
Model-facing str_replace_editor with view/create/unique literal replace/line insert operations over ctx.fs |
(registers on ctx.tools) |
The interface lives at fs/fs/. A sandboxed, remote, or project-scoped filesystem backend can replace fs-local without touching the seam, the policy gate, or the model-facing tool schemas — fs-sandbox is the first such replacement (an in-process path fence over the shared sandbox mode; see the cross-family fs sandbox Agent Note). The policy (fs-policy/) is a plugin that participates only through the fs/* event gate, not a service the tool injects — so dropping it gracefully loses the policy and leaves the unconstrained bare provider rather than breaking the tool. A deployment that loads tool-fs/ is expected to also load it. The mode fence and the read-before-edit gate are orthogonal and compose. Discovery (tool-fs-search/) deliberately does NOT extend the provider seam: search is a process-backed rg workflow on the bash executor, so filesystem backends stay free of a universal search contract; its tools register only when that executor can find rg, and its results are follow-up-readable when the bash workdir and the read root are the same workspace (the co-located deployment its README documents).
No timeouts on file IO
read/write/edit take no timeoutMs, and the provider seam arms no deadline — unlike bash and web (which consume @deepseek-ai/dsh-timeout) and the bash-backed glob/grep (whose declared timeoutMs is enforced by @deepseek-ai/dsh-timeout-policy): those are process-backed, where a deadline can really kill the work. A local syscall is best-effort-abortable at most: a timeout could not force an in-progress fsync/rename to stop, so a deadline here would be a knob that cannot deliver on its promise. Adding one would also be an implicit default in the exact place explicit-over-implicit forbids. Both reference agents (Claude Code, Codex) leave file IO untimed for the same reason; cancellation still propagates through the tool-execution signal for best-effort abort at syscall boundaries.