Files
deepseek-harness/packages/cordis/tool-cordis
kingwl 1f38b211be Merge origin/master (generic task runtime #219, single-exe closure, package renames)
Semantic resolutions beyond line merges:
- The bash seam keeps resolveMode + the bash/resolve-mode waterfall on
  master's task-free BashExecutor (run/start/resolve only; BashProcess
  handles); tool-bash consults it at its stamping site and escalation
  baseline on master's render/background split, with a waterfall test on
  the recording executor.
- dsh-mode's BASH_FAMILY narrows to ['bash']: bash_output/bash_kill are
  replaced by the kind-generic task_output/task_kill, which span every
  task kind and only observe or stop work, so the access cap withholds
  only the starter it can reason about.
- The plan-mode snapshot suite adopts master's pin grammar (tool-schema
  sidecars; the expectedHeaderSnapshots extension is gone — the exit
  transition deltas, and entering-before-turn-1 needs no second
  snapshot); modes-advertise joins the plan header class (no-model, so
  membership is vacuous). Fixtures re-recorded on the acp-demo bin;
  the replay overlay gains the passthrough sandbox runner.
- examples/plan-acp-agent rewires to @deepseek-ai/dsh-acp-demo and drops
  its tool-bash entry (the spine bundle now composes it); dsh-stdio (the
  renamed stdio-chat home) keeps its /mode command and gains the dsh-mode
  peer edge; the acp bridge keeps the modes surface beside master's
  permission presets.
- mode README gains the Model Experience / Known Limitations sections the
  new README gates require; AGENTS.md ceiling 1370 → 1440 for the kept
  mode/ layout line and Agent efficiency section.
2026-07-15 23:17:18 +08:00
..
2026-07-15 11:28:45 +08:00

@deepseek-ai/dsh-tool-cordis

The self-referential cordis toolset: three model-facing tools over the live runtime the agent runs inside. Design home — sandbox semantics, mount lifecycle, cross-mount composition, the generated API catalog, standing decisions: the toolset RFC.

What it does

  • cordis_inspect — read-only report over the runtime: services, the loaded-plugin list, registered tools, the dynamic-mount table, and the catalog-backed api / events references.
  • cordis_mount — evaluates model-written JavaScript (the body of an async function) in a node:vm sandbox; the code must return a cordis plugin, which is mounted under the cordis-dynamic group fiber and tracked as dyn-<n>.
  • cordis_unmount — disposes one mount by id, returning only after quiescence.

Exact model-facing schemas: the generated tool catalog.

Trust stance

The sandbox isolates globals but is not a security boundary. Node globals are absent or redirect to Cordis services such as ctx.fs, ctx.web, and ctx.bash, and writes to globalThis stay local, but host-realm helpers make escape possible. Mounted plugins receive a façade without framework internals, yet its allowed services affect the live runtime. Treat this toolset like bash access; see the design and trust stance.

Config

Field Default Meaning
vmTimeoutMs 5000 Bound on the SYNCHRONOUS portion of mount-code evaluation; an async body escapes it

The generated API catalog

src/api-catalog.ts is generated by scripts/gen-cordis-api.ts from the same AST walk as docs/cordis-catalog and freshness-gated by pnpm run verify-cordis-api (in doc-sync) — never edit it by hand. cordis_inspect intersects it with the live service store at call time.

Rendering

All three tools render generic cards (read / execute / delete); cordis_mount carries the mount code as rawInput. Presenters are pure functions of the args; results keep the default text rendering.

Export shape

Namespace plugin: named exports name / inject / Config / apply, no default export (docs/postmortem/0001).

Model Experience

Tool schemas

What the model sees: The conversation model sees the generated cordis_inspect, cordis_mount, and cordis_unmount schemas whenever this plugin is visible.

Token effect: Fixed schema cost on every request in that tool view.

Tool-call history and results

What the model sees: Inspect joins selected sections exactly as ## <section> then a newline and the data-dependent body, with one blank line between sections. Mount returns mounted <id> (plugin "<name>", state: <state>), optionally inserting — waiting for service(s): <names> (activates when provided) before the closing parenthesis. Unmount returns unmounted <id> (plugin "<name>"); an unknown id becomes Error: no dynamic plugin with id "<id>" (list mounts with cordis_inspect what:"dynamic"). The submitted mount program remains in the assistant tool-call history.

Token effect: Inspect output and mount code are data-dependent and resent until compaction; lifecycle acknowledgements are small.

Later requests after a mount

What the model sees: A mounted plugin may register tools, prompt contributions, or listeners that change later requests for the scopes it targets; unmount removes those contributions after quiescence.

Token effect: Indirect token impact equals the mounted plugin's contributions and lasts only for the mount lifetime.

Known Limitations and Deferred Work

  • The sandbox is containment for honest code, not a security boundary — host-realm helpers on the sandbox global are reachable, so mount code can reach Node; load this plugin as deliberately as you would grant a bash tool (see § Trust stance).
  • The ctx façade exposes no effect() — mount code cannot register a bespoke disposer; on/provide/tools.register cover every mount seen so far, and a guarded effect waits on a real need (FIXME(sandbox-effect)).
  • vmTimeoutMs bounds only synchronous evaluation — an async mount body escapes it; there is no async budget on mount code.