deepseek-harness/docs/capability-seams.md

249 lines
18 KiB
Markdown
Raw Normal View History

<!-- Generated by scripts/gen-doc-graphs.ts - do not edit by hand.
Run `pnpm run gen-doc-graphs` to regenerate. -->
# Capability Seams And Core Services
A service can be a core spine service, a swappable capability seam, or a bundle/composition point. The graph shows the package that owns the service declaration, known implementation packages, and packages that consume the service directly.
```mermaid
flowchart LR
pkg_llm["llm"]
svc_llm["ctx.llm<br/>LLM adapter registry"]
pkg_llm_deepseek["llm-deepseek"]
pkg_llm_pi_ai["llm-pi-ai"]
pkg_llm_replay["llm-replay"]
pkg_agent_loop["agent-loop"]
pkg_compact_basic["compact-basic"]
pkg_token_meter["token-meter"]
svc_tokenMeter["ctx.tokenMeter<br/>Replay token measurement"]
pkg_compact_tool_result_prune["compact-tool-result-prune"]
svc_toolResultPrune["ctx.toolResultPrune<br/>Model-free tool-result pruning"]
pkg_session["session"]
svc_sessions["ctx.sessions<br/>In-memory session store"]
pkg_agent["agent"]
2026-07-15 21:21:24 +08:00
pkg_cli_demo["cli-demo"]
pkg_session_persistence["session-persistence"]
pkg_session_query["session-query"]
pkg_subagent_inprocess["subagent-inprocess"]
pkg_invariants["invariants"]
svc_sessionPersistence["ctx.sessionPersistence<br/>Durable session persistence seam"]
pkg_session_persistence_jsonl["session-persistence-jsonl"]
pkg_session_persistence_sqlite["session-persistence-sqlite"]
pkg_tool_bash["tool-bash"]
pkg_hooks_claude["hooks-claude"]
pkg_hooks_codex["hooks-codex"]
pkg_acp["acp"]
svc_sessionQuery["ctx.sessionQuery<br/>Exact session-history reads and traces"]
pkg_system_prompt["system-prompt"]
svc_systemPrompt["ctx.systemPrompt<br/>System prompt assembly registry"]
pkg_tools["tools"]
pkg_tool_fs["tool-fs"]
pkg_tool_web["tool-web"]
2026-07-11 22:55:40 +08:00
svc_tools["ctx.tools<br/>Tool registry and guarded execution pipeline"]
pkg_tool_ask_user["tool-ask-user"]
pkg_tool_cordis["tool-cordis"]
pkg_tool_skill["tool-skill"]
pkg_tool_subagent["tool-subagent"]
pkg_tool_todo["tool-todo"]
pkg_user_interaction["user-interaction"]
svc_userInteraction["ctx.userInteraction<br/>Human question/answer seam"]
2026-07-20 19:26:04 +08:00
pkg_tui["tui"]
pkg_skill["skill"]
2026-07-08 15:50:38 +08:00
svc_skills["ctx.skills<br/>Skill provider registry"]
pkg_skill_local["skill-local"]
svc_agents["ctx.agents<br/>Agent service"]
2026-07-20 19:26:04 +08:00
pkg_tui_demo["tui-demo"]
svc_agentLoop["ctx.agentLoop<br/>Concrete loop driver"]
pkg_agent_spine_demo["agent-spine-demo"]
pkg_bash["bash"]
svc_bash["ctx.bash<br/>Bash executor seam"]
pkg_bash_local["bash-local"]
pkg_bash_sandbox["bash-sandbox"]
svc_bashEnv["ctx.bashEnv<br/>Managed bash environment registry"]
pkg_sandbox["sandbox"]
svc_sandbox["ctx.sandbox<br/>Process-sandbox seam"]
pkg_sandbox_local["sandbox-local"]
pkg_sandbox_policy["sandbox-policy"]
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox RFC's deferred cross-family phase. - dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the deployment default mode + workspaceRoot and the per-session override event, renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter. Decouples the bash seam from dsh-session. - dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences write/edit by the per-call mode (read-only denies, workspace-write contains to the workspace + temp roots via the shared writableRoots, danger passes through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent re-canonicalization. A policy fence in trusted code, not a kernel boundary. - dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider ladder, denial/hint markers, approveEscalation) both tool families use; approveEscalation takes a structural approver so dsh-sandbox gains no approval/agent dependency, and both tools stay duplication-free. - tool-fs: write/edit advertise sandbox_permissions/justification under a confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker, and resolve the same one-approved-wider retry. - examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating that disabled the fs stack under confined modes. RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
svc_sandboxPolicy["ctx.sandboxPolicy<br/>Sandbox policy home"]
pkg_fs_sandbox["fs-sandbox"]
pkg_approval["approval"]
svc_approval["ctx.approval<br/>Approval seam"]
feat(permission): user-facing permission presets — one Permissions select over the two knobs A preset names a bundle of the two mechanism knobs — request = workspace-write + ask, yolo = danger-full-access + never — so the editor shows ONE 'Permissions' select where the sandbox-mode and approval-policy tiers stay orthogonal capabilities (the Codex /approvals shape: presets over two dials). ctx.permission (dsh-permission) owns the config-defined table, validates the default preset's bundle against the composed knob defaults at load (fails loud), and writes a switch THROUGH: one log-only permission/preset event (the audit fact reverse-mapping cannot recover — the planned 'agent' preset shares request's knob values and differs only in composed policy) plus each knob event via its own setter, deduped — a net-zero switch appends nothing. Every knob consumer keeps reading its own fold, untouched. The current preset DERIVES from the effective knob values — the fold breaks bundle ties, a knob state outside the table is the reserved 'custom' value (a state, not an error: shown while it holds, switchable FROM, never a target), and defaultPreset disappears (zero-event state reverse-maps from the composition defaults). The ACP bridge drops the two per-knob selects for the one preset select (advertised only when ctx.permission is composed); pending/anchor/no-op semantics carry over unchanged, with the no-op echo acknowledged before vocabulary validation so a client re-pushing a derived 'custom' current never errors. The sandbox variant example composes the service with a workspace-write default; the permission-switching, escalation-approved and escalation-rejected scenarios are re-recorded under it (escalations now target an outside-workspace /tmp path under danger-full-access, self-cleaning) and config-options is re-authored on the single-select wire.
2026-07-12 21:03:41 +08:00
pkg_permission["permission"]
svc_permission["ctx.permission<br/>Permission presets"]
pkg_code_runtime["code-runtime"]
svc_codeRuntime["ctx.codeRuntime<br/>Code-execution seam"]
pkg_code_runtime_worker["code-runtime-worker"]
pkg_fs["fs"]
svc_fs["ctx.fs<br/>Filesystem provider seam"]
pkg_fs_local["fs-local"]
pkg_fs_policy["fs-policy"]
pkg_compact["compact"]
svc_compact["ctx.compact<br/>Compaction seam"]
pkg_subagent["subagent"]
svc_subagents["ctx.subagents<br/>Subagent provider registry"]
pkg_subagent_spawn["subagent-spawn"]
pkg_subagent_fork["subagent-fork"]
pkg_subagent_acp["subagent-acp"]
pkg_tasks["tasks"]
svc_tasks["ctx.tasks<br/>Background task registry"]
pkg_tool_tasks["tool-tasks"]
pkg_web["web"]
svc_web["ctx.web<br/>Web access provider registry"]
pkg_web_search_exa["web-search-exa"]
pkg_web_search_perplexity["web-search-perplexity"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_fetch_local["web-fetch-local"]
pkg_spill["spill"]
svc_spillStore["ctx.spillStore<br/>Spill storage seam"]
pkg_spill_local["spill-local"]
pkg_spill_policy["spill-policy"]
Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows Beyond the mechanical conflicts (provider capability lines vs master's new inheritsParentContext field; generated catalogs regenerated rather than hand-merged; knip/lockfile), three master-side reworks required semantic adaptation of this branch: - The persona rework removed AgentOptions.systemPrompt, which was the structured-output instruction's channel. The instruction now rides the SAME final-request enforcement listener that injects the schema'd tool: appended per request to final.system (per-request wire state, not agent prompt state). Tests assert the wire request (adapter.requests) instead of child.options; the bare-direct-dispatch test pins the no-system arm. - Tool guidance moved out of deployment prompts into per-tool prompt sections; the examples' workflow paragraph became a tool:<toolName> section contributed by dsh-tool-workflow (explicit-ask-only policy), and both example personas resolve to master's minimal identity+behavior form. tool-workflow gains inject: systemPrompt (+ peer dep, tsconfig ref); the export-shape guard updated. - The uniform-RFC-format gate: the dynamic-workflows RFC restructured to the implemented/ skeleton (bare Status line; Proposal -> Decision; What-was-rejected -> Alternatives considered; new Consequences), and the overall-run-timeout deferral is now recorded in the RFC's Deferred list. The doc-graphs atlas classification gains the workflows seam (workflow-vm implementation, tool-workflow consumer). Master's harness-identity section made "empty assembled prompt" states unreachable through the loop, so the instruction-append is a plain undefined-ternary and the structured tests assert append-not-replace. All snapshot goldens (including workflow-run) replay unchanged. Full local CI-equivalent gate sequence green on the merged tree.
2026-07-06 03:14:07 +08:00
pkg_workflow["workflow"]
svc_workflows["ctx.workflows<br/>Workflow script engine"]
pkg_workflow_workerthread["workflow-workerthread"]
Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows Beyond the mechanical conflicts (provider capability lines vs master's new inheritsParentContext field; generated catalogs regenerated rather than hand-merged; knip/lockfile), three master-side reworks required semantic adaptation of this branch: - The persona rework removed AgentOptions.systemPrompt, which was the structured-output instruction's channel. The instruction now rides the SAME final-request enforcement listener that injects the schema'd tool: appended per request to final.system (per-request wire state, not agent prompt state). Tests assert the wire request (adapter.requests) instead of child.options; the bare-direct-dispatch test pins the no-system arm. - Tool guidance moved out of deployment prompts into per-tool prompt sections; the examples' workflow paragraph became a tool:<toolName> section contributed by dsh-tool-workflow (explicit-ask-only policy), and both example personas resolve to master's minimal identity+behavior form. tool-workflow gains inject: systemPrompt (+ peer dep, tsconfig ref); the export-shape guard updated. - The uniform-RFC-format gate: the dynamic-workflows RFC restructured to the implemented/ skeleton (bare Status line; Proposal -> Decision; What-was-rejected -> Alternatives considered; new Consequences), and the overall-run-timeout deferral is now recorded in the RFC's Deferred list. The doc-graphs atlas classification gains the workflows seam (workflow-vm implementation, tool-workflow consumer). Master's harness-identity section made "empty assembled prompt" states unreachable through the loop, so the instruction-append is a plain undefined-ternary and the structured tests assert append-not-replace. All snapshot goldens (including workflow-run) replay unchanged. Full local CI-equivalent gate sequence green on the merged tree.
2026-07-06 03:14:07 +08:00
pkg_tool_workflow["tool-workflow"]
pkg_acp --> svc_approval
pkg_acp --> svc_userInteraction
pkg_agent --> svc_agents
pkg_agent_loop --> svc_agentLoop
pkg_approval --> svc_approval
pkg_bash --> svc_bash
pkg_bash_local --> svc_bash
pkg_bash_sandbox --> svc_bash
pkg_code_runtime --> svc_codeRuntime
pkg_code_runtime_worker --> svc_codeRuntime
pkg_compact --> svc_compact
pkg_compact_basic --> svc_compact
pkg_compact_tool_result_prune --> svc_toolResultPrune
pkg_fs --> svc_fs
pkg_fs_local --> svc_fs
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox RFC's deferred cross-family phase. - dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the deployment default mode + workspaceRoot and the per-session override event, renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter. Decouples the bash seam from dsh-session. - dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences write/edit by the per-call mode (read-only denies, workspace-write contains to the workspace + temp roots via the shared writableRoots, danger passes through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent re-canonicalization. A policy fence in trusted code, not a kernel boundary. - dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider ladder, denial/hint markers, approveEscalation) both tool families use; approveEscalation takes a structural approver so dsh-sandbox gains no approval/agent dependency, and both tools stay duplication-free. - tool-fs: write/edit advertise sandbox_permissions/justification under a confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker, and resolve the same one-approved-wider retry. - examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating that disabled the fs stack under confined modes. RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
pkg_fs_sandbox --> svc_fs
pkg_llm --> svc_llm
pkg_llm_deepseek --> svc_llm
pkg_llm_pi_ai --> svc_llm
pkg_llm_replay --> svc_llm
feat(permission): user-facing permission presets — one Permissions select over the two knobs A preset names a bundle of the two mechanism knobs — request = workspace-write + ask, yolo = danger-full-access + never — so the editor shows ONE 'Permissions' select where the sandbox-mode and approval-policy tiers stay orthogonal capabilities (the Codex /approvals shape: presets over two dials). ctx.permission (dsh-permission) owns the config-defined table, validates the default preset's bundle against the composed knob defaults at load (fails loud), and writes a switch THROUGH: one log-only permission/preset event (the audit fact reverse-mapping cannot recover — the planned 'agent' preset shares request's knob values and differs only in composed policy) plus each knob event via its own setter, deduped — a net-zero switch appends nothing. Every knob consumer keeps reading its own fold, untouched. The current preset DERIVES from the effective knob values — the fold breaks bundle ties, a knob state outside the table is the reserved 'custom' value (a state, not an error: shown while it holds, switchable FROM, never a target), and defaultPreset disappears (zero-event state reverse-maps from the composition defaults). The ACP bridge drops the two per-knob selects for the one preset select (advertised only when ctx.permission is composed); pending/anchor/no-op semantics carry over unchanged, with the no-op echo acknowledged before vocabulary validation so a client re-pushing a derived 'custom' current never errors. The sandbox variant example composes the service with a workspace-write default; the permission-switching, escalation-approved and escalation-rejected scenarios are re-recorded under it (escalations now target an outside-workspace /tmp path under danger-full-access, self-cleaning) and config-options is re-authored on the single-select wire.
2026-07-12 21:03:41 +08:00
pkg_permission --> svc_permission
pkg_sandbox --> svc_sandbox
pkg_sandbox_local --> svc_sandbox
pkg_sandbox_policy --> svc_sandboxPolicy
pkg_session --> svc_sessions
pkg_session_persistence --> svc_sessionPersistence
pkg_session_persistence_jsonl --> svc_sessionPersistence
pkg_session_persistence_sqlite --> svc_sessionPersistence
pkg_session_query --> svc_sessionQuery
pkg_skill --> svc_skills
pkg_skill_local --> svc_skills
pkg_spill --> svc_spillStore
pkg_spill_local --> svc_spillStore
pkg_subagent --> svc_subagents
pkg_subagent_acp --> svc_subagents
pkg_subagent_fork --> svc_subagents
pkg_subagent_spawn --> svc_subagents
pkg_system_prompt --> svc_systemPrompt
pkg_tasks --> svc_tasks
pkg_token_meter --> svc_tokenMeter
pkg_tool_bash --> svc_bashEnv
pkg_tools --> svc_tools
2026-07-20 19:26:04 +08:00
pkg_tui --> svc_userInteraction
pkg_user_interaction --> svc_userInteraction
pkg_web --> svc_web
pkg_web_fetch_local --> svc_web
pkg_web_search_deepseek --> svc_web
pkg_web_search_exa --> svc_web
pkg_web_search_perplexity --> svc_web
Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows Beyond the mechanical conflicts (provider capability lines vs master's new inheritsParentContext field; generated catalogs regenerated rather than hand-merged; knip/lockfile), three master-side reworks required semantic adaptation of this branch: - The persona rework removed AgentOptions.systemPrompt, which was the structured-output instruction's channel. The instruction now rides the SAME final-request enforcement listener that injects the schema'd tool: appended per request to final.system (per-request wire state, not agent prompt state). Tests assert the wire request (adapter.requests) instead of child.options; the bare-direct-dispatch test pins the no-system arm. - Tool guidance moved out of deployment prompts into per-tool prompt sections; the examples' workflow paragraph became a tool:<toolName> section contributed by dsh-tool-workflow (explicit-ask-only policy), and both example personas resolve to master's minimal identity+behavior form. tool-workflow gains inject: systemPrompt (+ peer dep, tsconfig ref); the export-shape guard updated. - The uniform-RFC-format gate: the dynamic-workflows RFC restructured to the implemented/ skeleton (bare Status line; Proposal -> Decision; What-was-rejected -> Alternatives considered; new Consequences), and the overall-run-timeout deferral is now recorded in the RFC's Deferred list. The doc-graphs atlas classification gains the workflows seam (workflow-vm implementation, tool-workflow consumer). Master's harness-identity section made "empty assembled prompt" states unreachable through the loop, so the instruction-append is a plain undefined-ternary and the structured tests assert append-not-replace. All snapshot goldens (including workflow-run) replay unchanged. Full local CI-equivalent gate sequence green on the merged tree.
2026-07-06 03:14:07 +08:00
pkg_workflow --> svc_workflows
pkg_workflow_workerthread --> svc_workflows
svc_agentLoop --> pkg_agent_spine_demo
svc_agents --> pkg_acp
svc_agents --> pkg_agent_loop
2026-07-15 21:21:24 +08:00
svc_agents --> pkg_cli_demo
svc_agents --> pkg_invariants
svc_agents --> pkg_subagent_inprocess
2026-07-20 19:26:04 +08:00
svc_agents --> pkg_tui_demo
svc_approval --> pkg_tool_bash
svc_approval --> pkg_tools
svc_bash --> pkg_hooks_claude
svc_bash --> pkg_hooks_codex
svc_bash --> pkg_tool_bash
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge The dsh-tools half of the Code Mode RFC (its fourth, final change): the registry gains its first config — mode: native | code | both — and OWNS how its tools reach the model. 'code' contributes exactly one wire tool, run_code, plus a lazy tools:sdk prompt section declaring every other tool as a generated TypeScript API (jsonSchemaToTs: total over the defineTool subset, unknown degradation, lexicographic byte-identical rendering); 'both' ships both representations; 'native' is byte-for-byte the old behavior. Non-native modes fail every assembly loudly without a typescript-language ctx.codeRuntime. run_code's dispatch bridge: JSON-normalizes each binding argument before dispatch (what dispatches is what the tool/code-dispatch event logs — the append can never fail on payload shape; BigInt/circulars reject that one call), serializes all program tool calls through a per-run queue (even Promise.all — no concurrency-safety metadata yet), routes every sub-call through tools/pre-execute → tools/post-execute (a deny rejects the program-side promise), drops sub-call additionalContext (no safe outlet mid-run; pinned), owns a run-scoped abort that follows the outer signal in and fires on settlement (in-flight sub-dispatch aborted, queued abandoned, queue drained before returning), and converts a failed run into CodeRunFailedError → a structured isError carrying kind + captured logs. tool/code-dispatch joins SessionEventMap by declaration merging (log-only; deriveMessages ignores it). The composed surface: the tools config forwards through agent-core and both app packages; examples/code-agent + demo:code run the worker runtime under mode code (keyless boot smoke + a with-key e2e proving the collapsed [run_code] header, the dispatch events, and the file the program wrote); two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK section, collapsed header, dispatch events, and result card — each its own header-pinning class (the harness gains per-scenario config overlays and per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the RFC (moved to implemented/, restructured to decision-era headings) updated in the same change.
2026-07-08 12:58:23 +08:00
svc_codeRuntime --> pkg_tools
svc_compact --> pkg_compact_basic
svc_fs --> pkg_tool_fs
svc_llm --> pkg_agent_loop
svc_llm --> pkg_compact_basic
feat(permission): user-facing permission presets — one Permissions select over the two knobs A preset names a bundle of the two mechanism knobs — request = workspace-write + ask, yolo = danger-full-access + never — so the editor shows ONE 'Permissions' select where the sandbox-mode and approval-policy tiers stay orthogonal capabilities (the Codex /approvals shape: presets over two dials). ctx.permission (dsh-permission) owns the config-defined table, validates the default preset's bundle against the composed knob defaults at load (fails loud), and writes a switch THROUGH: one log-only permission/preset event (the audit fact reverse-mapping cannot recover — the planned 'agent' preset shares request's knob values and differs only in composed policy) plus each knob event via its own setter, deduped — a net-zero switch appends nothing. Every knob consumer keeps reading its own fold, untouched. The current preset DERIVES from the effective knob values — the fold breaks bundle ties, a knob state outside the table is the reserved 'custom' value (a state, not an error: shown while it holds, switchable FROM, never a target), and defaultPreset disappears (zero-event state reverse-maps from the composition defaults). The ACP bridge drops the two per-knob selects for the one preset select (advertised only when ctx.permission is composed); pending/anchor/no-op semantics carry over unchanged, with the no-op echo acknowledged before vocabulary validation so a client re-pushing a derived 'custom' current never errors. The sandbox variant example composes the service with a workspace-write default; the permission-switching, escalation-approved and escalation-rejected scenarios are re-recorded under it (escalations now target an outside-workspace /tmp path under danger-full-access, self-cleaning) and config-options is re-authored on the single-select wire.
2026-07-12 21:03:41 +08:00
svc_permission --> pkg_acp
svc_sandbox --> pkg_bash_sandbox
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox RFC's deferred cross-family phase. - dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the deployment default mode + workspaceRoot and the per-session override event, renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter. Decouples the bash seam from dsh-session. - dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences write/edit by the per-call mode (read-only denies, workspace-write contains to the workspace + temp roots via the shared writableRoots, danger passes through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent re-canonicalization. A policy fence in trusted code, not a kernel boundary. - dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider ladder, denial/hint markers, approveEscalation) both tool families use; approveEscalation takes a structural approver so dsh-sandbox gains no approval/agent dependency, and both tools stay duplication-free. - tool-fs: write/edit advertise sandbox_permissions/justification under a confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker, and resolve the same one-approved-wider retry. - examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating that disabled the fs stack under confined modes. RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
svc_sandboxPolicy --> pkg_bash_sandbox
svc_sandboxPolicy --> pkg_fs_sandbox
svc_sessionPersistence --> pkg_acp
svc_sessionPersistence --> pkg_agent_loop
svc_sessionPersistence --> pkg_hooks_claude
svc_sessionPersistence --> pkg_hooks_codex
svc_sessionPersistence --> pkg_session_query
svc_sessionPersistence --> pkg_tool_bash
svc_sessions --> pkg_agent
svc_sessions --> pkg_agent_loop
2026-07-15 21:21:24 +08:00
svc_sessions --> pkg_cli_demo
svc_sessions --> pkg_invariants
svc_sessions --> pkg_session_persistence
svc_sessions --> pkg_session_query
svc_sessions --> pkg_subagent_inprocess
svc_skills --> pkg_tool_skill
svc_spillStore --> pkg_spill_policy
svc_subagents --> pkg_tool_subagent
svc_systemPrompt --> pkg_agent_loop
svc_systemPrompt --> pkg_tool_fs
svc_systemPrompt --> pkg_tool_web
svc_systemPrompt --> pkg_tools
svc_tasks --> pkg_tool_bash
svc_tasks --> pkg_tool_subagent
svc_tasks --> pkg_tool_tasks
svc_tokenMeter --> pkg_compact_basic
svc_toolResultPrune --> pkg_compact_basic
svc_tools --> pkg_acp
svc_tools --> pkg_agent_loop
svc_tools --> pkg_tool_ask_user
svc_tools --> pkg_tool_bash
svc_tools --> pkg_tool_cordis
svc_tools --> pkg_tool_fs
svc_tools --> pkg_tool_skill
svc_tools --> pkg_tool_subagent
svc_tools --> pkg_tool_todo
svc_tools --> pkg_tool_web
svc_userInteraction --> pkg_acp
svc_userInteraction --> pkg_tool_ask_user
2026-07-20 19:26:04 +08:00
svc_userInteraction --> pkg_tui
svc_web --> pkg_tool_web
Merge remote-tracking branch 'origin/master' into worktree-dynamic-workflows Beyond the mechanical conflicts (provider capability lines vs master's new inheritsParentContext field; generated catalogs regenerated rather than hand-merged; knip/lockfile), three master-side reworks required semantic adaptation of this branch: - The persona rework removed AgentOptions.systemPrompt, which was the structured-output instruction's channel. The instruction now rides the SAME final-request enforcement listener that injects the schema'd tool: appended per request to final.system (per-request wire state, not agent prompt state). Tests assert the wire request (adapter.requests) instead of child.options; the bare-direct-dispatch test pins the no-system arm. - Tool guidance moved out of deployment prompts into per-tool prompt sections; the examples' workflow paragraph became a tool:<toolName> section contributed by dsh-tool-workflow (explicit-ask-only policy), and both example personas resolve to master's minimal identity+behavior form. tool-workflow gains inject: systemPrompt (+ peer dep, tsconfig ref); the export-shape guard updated. - The uniform-RFC-format gate: the dynamic-workflows RFC restructured to the implemented/ skeleton (bare Status line; Proposal -> Decision; What-was-rejected -> Alternatives considered; new Consequences), and the overall-run-timeout deferral is now recorded in the RFC's Deferred list. The doc-graphs atlas classification gains the workflows seam (workflow-vm implementation, tool-workflow consumer). Master's harness-identity section made "empty assembled prompt" states unreachable through the loop, so the instruction-append is a plain undefined-ternary and the structured tests assert append-not-replace. All snapshot goldens (including workflow-run) replay unchanged. Full local CI-equivalent gate sequence green on the merged tree.
2026-07-06 03:14:07 +08:00
svc_workflows --> pkg_tool_workflow
svc_fs -. event gate .-> pkg_fs_policy
```
| ctx key | Role | Owner | Implementations | Direct consumers | Companion plugins | Note |
| --- | --- | --- | --- | --- | --- | --- |
2026-07-05 01:25:58 +08:00
| `ctx.llm` | `seam` | [`llm`](../packages/llm/llm) | [`llm-deepseek`](../packages/llm/llm-deepseek), [`llm-pi-ai`](../packages/llm/llm-pi-ai), [`llm-replay`](../packages/support/llm-replay) | [`agent-loop`](../packages/core/agent-loop), [`compact-basic`](../packages/compact/compact-basic) | - | Adapters register provider implementations; the loop and compaction call the provider-neutral stream service. |
| `ctx.tokenMeter` | `core` | [`token-meter`](../packages/llm/token-meter) | - | [`compact-basic`](../packages/compact/compact-basic) | - | Owns isolated per-session replay folds; pressure consumers share immutable revisioned measurements. |
| `ctx.toolResultPrune` | `core` | [`compact-tool-result-prune`](../packages/compact/compact-tool-result-prune) | - | [`compact-basic`](../packages/compact/compact-basic) | - | Rewrites oversized current tool results through replayable single-node surface replacements before summary compaction. |
2026-07-15 21:21:24 +08:00
| `ctx.sessions` | `core` | [`session`](../packages/core/session) | - | [`agent-loop`](../packages/core/agent-loop), [`agent`](../packages/core/agent), [`cli-demo`](../packages/examples/cli-demo), [`session-persistence`](../packages/session-persistence/session-persistence), [`session-query`](../packages/session-query/session-query), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`invariants`](../packages/support/invariants) | - | Owns append-only Session instances and emits the durable session event feed. |
| `ctx.sessionPersistence` | `seam` | [`session-persistence`](../packages/session-persistence/session-persistence) | [`session-persistence-jsonl`](../packages/session-persistence/session-persistence-jsonl), [`session-persistence-sqlite`](../packages/session-persistence/session-persistence-sqlite) | [`agent-loop`](../packages/core/agent-loop), [`tool-bash`](../packages/bash/tool-bash), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex), [`acp`](../packages/ui/acp), [`session-query`](../packages/session-query/session-query) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. |
| `ctx.sessionQuery` | `seam` | [`session-query`](../packages/session-query/session-query) | - | - | - | Resolves live and optional persisted logs into one logical corpus for exact reads and relationship traces. |
2026-07-05 01:25:58 +08:00
| `ctx.systemPrompt` | `core` | [`system-prompt`](../packages/core/system-prompt) | - | [`agent-loop`](../packages/core/agent-loop), [`tools`](../packages/core/tools), [`tool-fs`](../packages/fs/tool-fs), [`tool-web`](../packages/web/tool-web) | - | Collects prompt sections and model-facing tool schemas for each step. |
| `ctx.tools` | `core` | [`tools`](../packages/core/tools) | - | [`agent-loop`](../packages/core/agent-loop), [`tool-ask-user`](../packages/ui/tool-ask-user), [`tool-bash`](../packages/bash/tool-bash), [`tool-cordis`](../packages/cordis/tool-cordis), [`tool-fs`](../packages/fs/tool-fs), [`tool-skill`](../packages/skill/tool-skill), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-todo`](../packages/todo/tool-todo), [`tool-web`](../packages/web/tool-web), [`acp`](../packages/ui/acp) | - | Registers capabilities, owns Code Mode transport, and routes calls through pre-policy, monotonic guards, around dispatch, post-policy, and final-result observation. |
2026-07-20 19:26:04 +08:00
| `ctx.userInteraction` | `seam` | [`user-interaction`](../packages/ui/user-interaction) | [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | [`tool-ask-user`](../packages/ui/tool-ask-user), [`tui`](../packages/ui/tui), [`acp`](../packages/ui/acp) | - | UI front doors provide the active human-answer provider; tool-ask-user pauses a tool call on the provider-neutral ask() promise. |
| `ctx.skills` | `seam` | [`skill`](../packages/skill/skill) | [`skill-local`](../packages/skill/skill-local) | [`tool-skill`](../packages/skill/tool-skill) | - | Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies. |
2026-07-20 19:26:04 +08:00
| `ctx.agents` | `core` | [`agent`](../packages/core/agent) | - | [`agent-loop`](../packages/core/agent-loop), [`acp`](../packages/ui/acp), [`cli-demo`](../packages/examples/cli-demo), [`subagent-inprocess`](../packages/subagent/subagent-inprocess), [`tui-demo`](../packages/examples/tui-demo), [`invariants`](../packages/support/invariants) | - | Owns live Agent handles, the create/resume factory seam, and process-local initiator propagation. |
| `ctx.agentLoop` | `bundle` | [`agent-loop`](../packages/core/agent-loop) | - | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | - | The one concrete loop plugin; extension packages depend on dsh-agent events and services, not on this package. |
| `ctx.bash` | `seam` | [`bash`](../packages/bash/bash) | [`bash-local`](../packages/bash/bash-local), [`bash-sandbox`](../packages/bash/bash-sandbox) | [`tool-bash`](../packages/bash/tool-bash), [`hooks-claude`](../packages/hooks/hooks-claude), [`hooks-codex`](../packages/hooks/hooks-codex) | - | The model-facing bash tools and hook bridges consume this seam; sandboxed or remote executors replace bash-local without touching them. |
| `ctx.bashEnv` | `core` | [`tool-bash`](../packages/bash/tool-bash) | - | - | - | Plugins declare effect-scoped DSH_* facts; tool-bash collects one trusted snapshot per execution and the executor rebuilds the namespace. |
| `ctx.sandbox` | `seam` | [`sandbox`](../packages/sandbox/sandbox) | [`sandbox-local`](../packages/sandbox/sandbox-local) | [`bash-sandbox`](../packages/bash/bash-sandbox) | - | Consumers hand over the exact argv they are about to spawn; same-world backends wrap it under a per-call policy and report enforcement. |
| `ctx.sandboxPolicy` | `core` | [`sandbox-policy`](../packages/sandbox/sandbox-policy) | - | [`bash-sandbox`](../packages/bash/bash-sandbox), [`fs-sandbox`](../packages/fs/fs-sandbox) | - | The one home for the deployment default mode + workspace root; only the sandboxed executor and provider read the service (the tool layers use the pure `sandbox/mode` fold it also exports). Both enforcing families read it so bash and fs cannot confine to different roots. |
| `ctx.approval` | `seam` | `approval` | [`acp`](../packages/ui/acp) | [`tools`](../packages/core/tools), [`tool-bash`](../packages/bash/tool-bash) | - | One-shot permission decisions dispatched over the `approval/request` waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to `unavailable`. |
| `ctx.permission` | `core` | [`permission`](../packages/ui/permission) | - | [`acp`](../packages/ui/acp) | - | User-facing preset table (`workspace-write`/`danger-full-access`) bundling the sandbox-mode and approval-policy knobs; a switch writes one `permission/preset` event through to both knob events. |
feat: Code Mode — the registry's mode config, the SDK codegen, and the run_code bridge The dsh-tools half of the Code Mode RFC (its fourth, final change): the registry gains its first config — mode: native | code | both — and OWNS how its tools reach the model. 'code' contributes exactly one wire tool, run_code, plus a lazy tools:sdk prompt section declaring every other tool as a generated TypeScript API (jsonSchemaToTs: total over the defineTool subset, unknown degradation, lexicographic byte-identical rendering); 'both' ships both representations; 'native' is byte-for-byte the old behavior. Non-native modes fail every assembly loudly without a typescript-language ctx.codeRuntime. run_code's dispatch bridge: JSON-normalizes each binding argument before dispatch (what dispatches is what the tool/code-dispatch event logs — the append can never fail on payload shape; BigInt/circulars reject that one call), serializes all program tool calls through a per-run queue (even Promise.all — no concurrency-safety metadata yet), routes every sub-call through tools/pre-execute → tools/post-execute (a deny rejects the program-side promise), drops sub-call additionalContext (no safe outlet mid-run; pinned), owns a run-scoped abort that follows the outer signal in and fires on settlement (in-flight sub-dispatch aborted, queued abandoned, queue drained before returning), and converts a failed run into CodeRunFailedError → a structured isError carrying kind + captured logs. tool/code-dispatch joins SessionEventMap by declaration merging (log-only; deriveMessages ignores it). The composed surface: the tools config forwards through agent-core and both app packages; examples/code-agent + demo:code run the worker runtime under mode code (keyless boot smoke + a with-key e2e proving the collapsed [run_code] header, the dispatch events, and the file the program wrote); two new snapshot scenarios (code-mode-turn, both-mode-turn) record the SDK section, collapsed header, dispatch events, and result card — each its own header-pinning class (the harness gains per-scenario config overlays and per-class pins). Catalogs, graphs, cookbook, hooks-bridge notes, and the RFC (moved to implemented/, restructured to decision-era headings) updated in the same change.
2026-07-08 12:58:23 +08:00
| `ctx.codeRuntime` | `seam` | [`code-runtime`](../packages/code-runtime/code-runtime) | [`code-runtime-worker`](../packages/code-runtime/code-runtime-worker) | [`tools`](../packages/core/tools) | - | Runs one model-written program against host-provided async bindings; backends differ by substrate and language (the tool registry consumes it for Code Mode). |
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox RFC's deferred cross-family phase. - dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the deployment default mode + workspaceRoot and the per-session override event, renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter. Decouples the bash seam from dsh-session. - dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences write/edit by the per-call mode (read-only denies, workspace-write contains to the workspace + temp roots via the shared writableRoots, danger passes through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent re-canonicalization. A policy fence in trusted code, not a kernel boundary. - dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider ladder, denial/hint markers, approveEscalation) both tool families use; approveEscalation takes a structural approver so dsh-sandbox gains no approval/agent dependency, and both tools stay duplication-free. - tool-fs: write/edit advertise sandbox_permissions/justification under a confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker, and resolve the same one-approved-wider retry. - examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating that disabled the fs stack under confined modes. RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
| `ctx.fs` | `seam` | [`fs`](../packages/fs/fs) | [`fs-local`](../packages/fs/fs-local), [`fs-sandbox`](../packages/fs/fs-sandbox) | [`tool-fs`](../packages/fs/tool-fs) | [`fs-policy`](../packages/fs/fs-policy) | tool-fs executes read/write/edit through ctx.fs; fs-sandbox fences mutations by the shared sandbox mode; fs-policy contributes observed-state checks through the fs/* event gate. |
| `ctx.compact` | `seam` | [`compact`](../packages/compact/compact) | [`compact-basic`](../packages/compact/compact-basic) | [`compact-basic`](../packages/compact/compact-basic) | - | The basic backend consumes post-step pressure and request-error recovery events; a model-facing compact tool remains deferred. |
| `ctx.subagents` | `seam` | [`subagent`](../packages/subagent/subagent) | [`subagent-spawn`](../packages/subagent/subagent-spawn), [`subagent-fork`](../packages/subagent/subagent-fork), [`subagent-acp`](../packages/subagent/subagent-acp) | [`tool-subagent`](../packages/subagent/tool-subagent) | - | Providers implement transports; tool-subagent exposes one configured provider as a model-facing tool name. |
| `ctx.tasks` | `core` | [`tasks`](../packages/tasks/tasks) | - | [`tool-bash`](../packages/bash/tool-bash), [`tool-subagent`](../packages/subagent/tool-subagent), [`tool-tasks`](../packages/tasks/tool-tasks) | - | Producers (tool-bash background commands, tool-subagent background delegations) register running work; tool-tasks is the model-facing control surface that reads, lists, and kills it. |
2026-07-05 01:25:58 +08:00
| `ctx.web` | `seam` | [`web`](../packages/web/web) | [`web-search-exa`](../packages/web/web-search-exa), [`web-search-perplexity`](../packages/web/web-search-perplexity), [`web-search-deepseek`](../packages/web/web-search-deepseek), [`web-fetch-local`](../packages/web/web-fetch-local) | [`tool-web`](../packages/web/tool-web) | - | Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names. |
| `ctx.spillStore` | `seam` | [`spill`](../packages/spill/spill) | [`spill-local`](../packages/spill/spill-local) | [`spill-policy`](../packages/spill/spill-policy) | - | The backend saves oversized tool text and returns a model-facing locator plus retrieval hint; spill-policy is the tools/post-execute consumer that decides when to spill. |
| `ctx.workflows` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-workerthread`](../packages/workflow/workflow-workerthread) | [`tool-workflow`](../packages/workflow/tool-workflow) | - | One engine per context (bash shape, no named-provider registry); the worker-thread engine fans agent() calls out through ctx.subagents. |
2026-07-05 02:54:01 +08:00
Maintenance mode: hybrid: services are discovered from Cordis declarations; interface/implementation/consumer roles are classified in `scripts/gen-doc-graphs.ts` with a completeness guard.