Merge origin/master and refresh doc graphs

This commit is contained in:
Tianyi Cui
2026-07-04 12:50:06 +08:00
354 changed files with 27627 additions and 1433 deletions

View File

@@ -5,37 +5,45 @@
Maintenance mode: curated Mermaid sequence; exact event signatures live in the generated Cordis catalog.
This sequence is the visual companion to [architecture.md](../architecture.md#loop-lifecycle-session--turn--step). It shows the durable session event path separately from live `agent/*` notifications.
This sequence is the visual companion to [architecture.md](../architecture.md#loop-lifecycle-session--turn--step). It keeps durable replay facts on `session/event` and live control/status on `agent/*`.
```mermaid
sequenceDiagram
participant User
participant Agent
participant Driver
participant Hooks as hook listeners
participant Prompt as ctx.systemPrompt
participant LLM as ctx.llm
participant Tools as ctx.tools
participant Session
participant Persistence
participant SDK as UI or SDK listener
User->>Agent: send(content)
Agent-->>SDK: agent/queued
Agent->>Driver: queued work wakes driver
Driver->>Session: turn/start + user/message
Driver-->>User: agent/turn-start
Driver-->>SDK: agent/status running
Driver->>Session: turn/start
Driver->>Hooks: agent/prompt-submit waterfall
Hooks-->>Driver: allow, block, or add context
Driver->>Session: user/message or rejected turn/end
Driver->>Prompt: system-prompt/assemble waterfall
Driver-->>Driver: agent/pre-step serial checkpoint
Driver->>Session: step/start
Driver->>LLM: agent/request waterfall, then llm/stream waterfall
LLM-->>Driver: StreamChunk*
Driver->>Session: assistant/chunk*
Driver-->>User: agent/stream-chunk* (master live mirror)
Session-->>SDK: session/event assistant/chunk*
Driver->>Hooks: agent/step-result waterfall
Driver->>Session: assistant/message
Driver->>Tools: tools/execute waterfall for each tool-call
Driver->>Session: tool/call
Driver->>Tools: execute through pre and post waterfalls
Tools-->>Session: tool-owned events when applicable
Driver->>Session: tool/result
Driver-->>Driver: agent/turn-continuation waterfall
Driver->>Session: tool/result and step/end
Driver->>Hooks: agent/turn-continuation waterfall
Driver->>Session: turn/end
Driver->>Persistence: session/flush parallel checkpoint
Driver-->>User: agent/status idle
Driver-->>SDK: agent/status idle
```
Future pressure from the hooks stack: PR #129 removes the live `agent/stream-chunk` mirror and leaves durable `assistant/chunk` on `session/event` as the authoritative token stream. Consumers that need replayable transcript data should already treat `session/event` as the load-bearing path.
SDK users that need replayable transcript data should consume `session/event`; `agent/*` is the live coordination surface for queue/status, prompt interception, request shaping, steering, continuation, and errors.

View File

@@ -48,6 +48,12 @@ flowchart LR
cfg_coding --> plugin_coding_tool_subagent_fork
plugin_coding_tool_todo["tool-todo<br/>@deepseek-ai/dsh-tool-todo"]
cfg_coding --> plugin_coding_tool_todo
plugin_coding_fs_local["fs-local<br/>@deepseek-ai/dsh-fs-local"]
cfg_coding --> plugin_coding_fs_local
plugin_coding_fs_policy["fs-policy<br/>@deepseek-ai/dsh-fs-policy"]
cfg_coding --> plugin_coding_fs_policy
plugin_coding_tool_fs["tool-fs<br/>@deepseek-ai/dsh-tool-fs"]
cfg_coding --> plugin_coding_tool_fs
end
subgraph example_acp["examples/acp-agent"]
cfg_acp["cordis.yml"]
@@ -70,6 +76,16 @@ flowchart LR
cfg_acp --> plugin_acp_tool_subagent_fork
plugin_acp_tool_todo["tool-todo<br/>@deepseek-ai/dsh-tool-todo"]
cfg_acp --> plugin_acp_tool_todo
plugin_acp_fs_local["fs-local<br/>@deepseek-ai/dsh-fs-local"]
cfg_acp --> plugin_acp_fs_local
plugin_acp_fs_policy["fs-policy<br/>@deepseek-ai/dsh-fs-policy"]
cfg_acp --> plugin_acp_fs_policy
plugin_acp_tool_fs["tool-fs<br/>@deepseek-ai/dsh-tool-fs"]
cfg_acp --> plugin_acp_tool_fs
plugin_acp_hooks_claude["hooks-claude<br/>@deepseek-ai/dsh-hooks-claude"]
cfg_acp --> plugin_acp_hooks_claude
plugin_acp_hooks_codex["hooks-codex<br/>@deepseek-ai/dsh-hooks-codex"]
cfg_acp --> plugin_acp_hooks_codex
end
bundle_stdio["@deepseek-ai/dsh-stdio-agent"] --> bundle_agent_core["@deepseek-ai/dsh-agent-core"]
bundle_stdio --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
@@ -86,5 +102,5 @@ flowchart LR
| Example | Parsed plugin ids | Config |
| --- | --- | --- |
| `examples/echo-agent` | `hmr`, `mock-llm`, `echo-tool`, `bash`, `stdio-agent` | [`examples/echo-agent/cordis.yml`](../../examples/echo-agent/cordis.yml) |
| `examples/coding-agent` | `hmr`, `llm-deepseek`, `bash`, `stdio-agent`, `compact-basic`, `subagent`, `subagent-spawn`, `subagent-fork`, `tool-subagent`, `tool-subagent-fork`, `tool-todo` | [`examples/coding-agent/cordis.yml`](../../examples/coding-agent/cordis.yml) |
| `examples/acp-agent` | `llm-deepseek`, `bash`, `acp-agent`, `subagent`, `subagent-spawn`, `subagent-fork`, `tool-subagent`, `tool-subagent-fork`, `tool-todo` | [`examples/acp-agent/cordis.yml`](../../examples/acp-agent/cordis.yml) |
| `examples/coding-agent` | `hmr`, `llm-deepseek`, `bash`, `stdio-agent`, `compact-basic`, `subagent`, `subagent-spawn`, `subagent-fork`, `tool-subagent`, `tool-subagent-fork`, `tool-todo`, `fs-local`, `fs-policy`, `tool-fs` | [`examples/coding-agent/cordis.yml`](../../examples/coding-agent/cordis.yml) |
| `examples/acp-agent` | `llm-deepseek`, `bash`, `acp-agent`, `subagent`, `subagent-spawn`, `subagent-fork`, `tool-subagent`, `tool-subagent-fork`, `tool-todo`, `fs-local`, `fs-policy`, `tool-fs`, `hooks-claude`, `hooks-codex` | [`examples/acp-agent/cordis.yml`](../../examples/acp-agent/cordis.yml) |

View File

@@ -29,6 +29,8 @@ flowchart LR
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"]
svc_tools["ctx.tools<br/>Tool registry and execution waterfall"]
pkg_tool_bash["tool-bash"]
pkg_tool_subagent["tool-subagent"]
@@ -40,6 +42,12 @@ flowchart LR
pkg_bash["bash"]
svc_bash["ctx.bash<br/>Bash executor seam"]
pkg_bash_local["bash-local"]
pkg_hooks_claude["hooks-claude"]
pkg_hooks_codex["hooks-codex"]
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"]
@@ -48,12 +56,20 @@ flowchart LR
pkg_subagent_fork["subagent-fork"]
pkg_subagent_acp["subagent-acp"]
pkg_subagent_mock["subagent-mock"]
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_agent --> svc_agents
pkg_agent_loop --> svc_agentLoop
pkg_bash --> svc_bash
pkg_bash_local --> svc_bash
pkg_compact --> svc_compact
pkg_compact_basic --> svc_compact
pkg_fs --> svc_fs
pkg_fs_local --> svc_fs
pkg_llm --> svc_llm
pkg_llm_deepseek --> svc_llm
pkg_llm_pi_ai --> svc_llm
@@ -69,14 +85,22 @@ flowchart LR
pkg_subagent_spawn --> svc_subagents
pkg_system_prompt --> svc_systemPrompt
pkg_tools --> svc_tools
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
svc_agentLoop --> pkg_agent_core
svc_agents --> pkg_acp
svc_agents --> pkg_agent_loop
svc_agents --> pkg_invariants
svc_agents --> pkg_stdio_agent
svc_agents --> pkg_subagent_inprocess
svc_bash --> pkg_hooks_claude
svc_bash --> pkg_hooks_codex
svc_bash --> pkg_tool_bash
svc_compact --> pkg_compact_basic
svc_fs --> pkg_tool_fs
svc_llm --> pkg_agent_loop
svc_llm --> pkg_compact_basic
svc_sessionPersistence --> pkg_acp
@@ -88,23 +112,31 @@ flowchart LR
svc_sessions --> pkg_subagent_inprocess
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_tools --> pkg_acp
svc_tools --> pkg_agent_loop
svc_tools --> pkg_tool_bash
svc_tools --> pkg_tool_fs
svc_tools --> pkg_tool_subagent
svc_tools --> pkg_tool_todo
svc_tools --> pkg_tool_web
svc_web --> pkg_tool_web
svc_fs -. event gate .-> pkg_fs_policy
```
| ctx key | Role | Owner | Implementations | Direct consumers | Note |
| --- | --- | --- | --- | --- | --- |
| `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.sessions` | `core` | [`session`](../../packages/core/session) | - | [`agent-loop`](../../packages/core/agent-loop), [`agent`](../../packages/core/agent), [`session-persistence`](../../packages/session-persistence/session-persistence), [`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), [`acp`](../../packages/ui/acp) | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. |
| `ctx.systemPrompt` | `core` | [`system-prompt`](../../packages/core/system-prompt) | - | [`agent-loop`](../../packages/core/agent-loop), [`tools`](../../packages/core/tools) | 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-bash`](../../packages/bash/tool-bash), [`tool-subagent`](../../packages/subagent/tool-subagent), [`tool-todo`](../../packages/todo/tool-todo), [`acp`](../../packages/ui/acp) | Registers tool definitions, exposes schemas to the prompt, and routes calls through tools/execute. |
| `ctx.agents` | `core` | [`agent`](../../packages/core/agent) | - | [`agent-loop`](../../packages/core/agent-loop), [`acp`](../../packages/ui/acp), [`subagent-inprocess`](../../packages/subagent/subagent-inprocess), [`stdio-agent`](../../packages/ui/stdio-agent), [`invariants`](../../packages/support/invariants) | Owns live Agent handles and the create/resume factory seam. |
| `ctx.agentLoop` | `bundle` | [`agent-loop`](../../packages/core/agent-loop) | - | [`agent-core`](../../packages/core/agent-core) | 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) | [`tool-bash`](../../packages/bash/tool-bash) | The model-facing bash tools consume this seam; sandboxed or remote executors can replace bash-local. |
| `ctx.compact` | `seam` | [`compact`](../../packages/compact/compact) | [`compact-basic`](../../packages/compact/compact-basic) | [`compact-basic`](../../packages/compact/compact-basic) | The basic backend currently consumes the pre-step event directly; 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), [`subagent-mock`](../../packages/support/subagent-mock) | [`tool-subagent`](../../packages/subagent/tool-subagent) | Providers implement transports; tool-subagent exposes one configured provider as a model-facing tool name. |
| ctx key | Role | Owner | Implementations | Direct consumers | Companion plugins | Note |
| --- | --- | --- | --- | --- | --- | --- |
| `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.sessions` | `core` | [`session`](../../packages/core/session) | - | [`agent-loop`](../../packages/core/agent-loop), [`agent`](../../packages/core/agent), [`session-persistence`](../../packages/session-persistence/session-persistence), [`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), [`acp`](../../packages/ui/acp) | - | Backends persist the same SessionEvent vocabulary; apps choose a backend at composition time. |
| `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-bash`](../../packages/bash/tool-bash), [`tool-fs`](../../packages/fs/tool-fs), [`tool-subagent`](../../packages/subagent/tool-subagent), [`tool-todo`](../../packages/todo/tool-todo), [`tool-web`](../../packages/web/tool-web), [`acp`](../../packages/ui/acp) | - | Registers tool definitions, exposes schemas to the prompt, and routes calls through tools/pre-execute and tools/post-execute. |
| `ctx.agents` | `core` | [`agent`](../../packages/core/agent) | - | [`agent-loop`](../../packages/core/agent-loop), [`acp`](../../packages/ui/acp), [`subagent-inprocess`](../../packages/subagent/subagent-inprocess), [`stdio-agent`](../../packages/ui/stdio-agent), [`invariants`](../../packages/support/invariants) | - | Owns live Agent handles and the create/resume factory seam. |
| `ctx.agentLoop` | `bundle` | [`agent-loop`](../../packages/core/agent-loop) | - | [`agent-core`](../../packages/core/agent-core) | - | 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) | [`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 can replace bash-local. |
| `ctx.fs` | `seam` | [`fs`](../../packages/fs/fs) | [`fs-local`](../../packages/fs/fs-local) | [`tool-fs`](../../packages/fs/tool-fs) | [`fs-policy`](../../packages/fs/fs-policy) | tool-fs executes read/write/edit through ctx.fs; 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 currently consumes the pre-step event directly; 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), [`subagent-mock`](../../packages/support/subagent-mock) | [`tool-subagent`](../../packages/subagent/tool-subagent) | - | Providers implement transports; tool-subagent exposes one configured provider as a model-facing tool name. |
| `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. |

View File

@@ -9,28 +9,30 @@ This matrix shows which packages dispatch each harness-owned event and which pac
| Event | Mode | Declared in | Dispatchers | Listeners |
| --- | --- | --- | --- | --- |
| `agent/created` | `emit` | [`packages/core/agent/src/types.ts:137`](../../packages/core/agent/src/types.ts) | [`agent`](../../packages/core/agent) (`emit`) | - |
| `agent/disposed` | `emit` | [`packages/core/agent/src/types.ts:143`](../../packages/core/agent/src/types.ts) | [`agent`](../../packages/core/agent) (`emit`) | - |
| `agent/error` | `emit` | [`packages/core/agent/src/types.ts:254`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/pre-step` | `serial` | [`packages/core/agent/src/types.ts:214`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`serial`) | [`compact-basic`](../../packages/compact/compact-basic) |
| `agent/queued` | `emit` | [`packages/core/agent/src/types.ts:156`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/request` | `waterfall` | [`packages/core/agent/src/types.ts:223`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`), [`compact-basic`](../../packages/compact/compact-basic) (`waterfall`) | - |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:150`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`acp`](../../packages/ui/acp), [`invariants`](../../packages/support/invariants), [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/steering` | `emit` | [`packages/core/agent/src/types.ts:248`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/step-end` | `emit` | [`packages/core/agent/src/types.ts:180`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/step-result` | `waterfall` | [`packages/core/agent/src/types.ts:229`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`) | - |
| `agent/step-start` | `emit` | [`packages/core/agent/src/types.ts:175`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/stream-chunk` | `emit` | [`packages/core/agent/src/types.ts:243`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/turn-continuation` | `waterfall` | [`packages/core/agent/src/types.ts:236`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`) | - |
| `agent/turn-end` | `emit` | [`packages/core/agent/src/types.ts:169`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/turn-start` | `emit` | [`packages/core/agent/src/types.ts:163`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/created` | `emit` | [`packages/core/agent/src/types.ts:233`](../../packages/core/agent/src/types.ts) | [`agent`](../../packages/core/agent) (`emit`) | [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/disposed` | `emit` | [`packages/core/agent/src/types.ts:239`](../../packages/core/agent/src/types.ts) | [`agent`](../../packages/core/agent) (`emit`) | [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/error` | `emit` | [`packages/core/agent/src/types.ts:353`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/pre-step` | `serial` | [`packages/core/agent/src/types.ts:305`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`serial`) | [`compact-basic`](../../packages/compact/compact-basic) |
| `agent/prompt-submit` | `waterfall` | [`packages/core/agent/src/types.ts:315`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`) | [`hooks-claude`](../../packages/hooks/hooks-claude), [`hooks-codex`](../../packages/hooks/hooks-codex) |
| `agent/queued` | `emit` | [`packages/core/agent/src/types.ts:252`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/request` | `waterfall` | [`packages/core/agent/src/types.ts:324`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`), [`compact-basic`](../../packages/compact/compact-basic) (`waterfall`) | - |
| `agent/session-start` | `emit` | [`packages/core/agent/src/types.ts:265`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`hooks-claude`](../../packages/hooks/hooks-claude), [`hooks-codex`](../../packages/hooks/hooks-codex) |
| `agent/status` | `emit` | [`packages/core/agent/src/types.ts:246`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | [`acp`](../../packages/ui/acp), [`invariants`](../../packages/support/invariants), [`ui-stdio`](../../packages/support/ui-stdio) |
| `agent/steering` | `emit` | [`packages/core/agent/src/types.ts:347`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`emit`) | - |
| `agent/step-result` | `waterfall` | [`packages/core/agent/src/types.ts:330`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`) | - |
| `agent/turn-continuation` | `waterfall` | [`packages/core/agent/src/types.ts:340`](../../packages/core/agent/src/types.ts) | [`agent-loop`](../../packages/core/agent-loop) (`waterfall`) | [`hooks-claude`](../../packages/hooks/hooks-claude), [`hooks-codex`](../../packages/hooks/hooks-codex) |
| `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:119`](../../packages/fs/fs/src/index.ts) | [`tool-fs`](../../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../../packages/fs/fs-policy) |
| `fs/observed` | `emit` | [`packages/fs/fs/src/index.ts:131`](../../packages/fs/fs/src/index.ts) | [`tool-fs`](../../packages/fs/tool-fs) (`emit`) | [`fs-policy`](../../packages/fs/fs-policy) |
| `fs/write-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:107`](../../packages/fs/fs/src/index.ts) | [`tool-fs`](../../packages/fs/tool-fs) (`waterfall`) | [`fs-policy`](../../packages/fs/fs-policy) |
| `llm/stream` | `waterfall` | [`packages/llm/llm/src/index.ts:31`](../../packages/llm/llm/src/index.ts) | [`llm`](../../packages/llm/llm) (`waterfall`) | [`llm-replay`](../../packages/support/llm-replay) |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:34`](../../packages/core/session/src/index.ts) | [`session`](../../packages/core/session) (`emit`) | [`invariants`](../../packages/support/invariants), [`session-persistence`](../../packages/session-persistence/session-persistence) |
| `session/event` | `emit` | [`packages/core/session/src/index.ts:40`](../../packages/core/session/src/index.ts) | [`session`](../../packages/core/session) (`emit`) | [`acp`](../../packages/ui/acp), [`invariants`](../../packages/support/invariants), [`session-persistence`](../../packages/session-persistence/session-persistence), [`ui-stdio`](../../packages/support/ui-stdio) |
| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:49`](../../packages/core/session/src/index.ts) | [`agent-loop`](../../packages/core/agent-loop) (`parallel`) | [`session-persistence`](../../packages/session-persistence/session-persistence) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:65`](../../packages/subagent/subagent/src/index.ts) | [`subagent`](../../packages/subagent/subagent) (`events.dispatch`) | - |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:59`](../../packages/subagent/subagent/src/index.ts) | [`subagent`](../../packages/subagent/subagent) (`events.dispatch`) | - |
| `session/created` | `emit` | [`packages/core/session/src/index.ts:35`](../../packages/core/session/src/index.ts) | [`session`](../../packages/core/session) (`emit`) | [`invariants`](../../packages/support/invariants), [`session-persistence`](../../packages/session-persistence/session-persistence) |
| `session/event` | `emit` | [`packages/core/session/src/index.ts:41`](../../packages/core/session/src/index.ts) | [`session`](../../packages/core/session) (`emit`) | [`acp`](../../packages/ui/acp), [`invariants`](../../packages/support/invariants), [`session-persistence`](../../packages/session-persistence/session-persistence), [`ui-stdio`](../../packages/support/ui-stdio) |
| `session/flush` | `parallel` | [`packages/core/session/src/index.ts:50`](../../packages/core/session/src/index.ts) | [`agent-loop`](../../packages/core/agent-loop) (`parallel`) | [`session-persistence`](../../packages/session-persistence/session-persistence) |
| `subagent/end` | `emit` | [`packages/subagent/subagent/src/index.ts:75`](../../packages/subagent/subagent/src/index.ts) | [`subagent`](../../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../../packages/hooks/hooks-claude) |
| `subagent/start` | `emit` | [`packages/subagent/subagent/src/index.ts:69`](../../packages/subagent/subagent/src/index.ts) | [`subagent`](../../packages/subagent/subagent) (`events.dispatch`) | [`hooks-claude`](../../packages/hooks/hooks-claude) |
| `system-prompt/assemble` | `waterfall` | [`packages/core/system-prompt/src/index.ts:24`](../../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../../packages/core/system-prompt) (`waterfall`) | - |
| `system-prompt/change` | `emit` | [`packages/core/system-prompt/src/index.ts:30`](../../packages/core/system-prompt/src/index.ts) | [`system-prompt`](../../packages/core/system-prompt) (`emit`) | - |
| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:48`](../../packages/core/tools/src/index.ts) | [`tools`](../../packages/core/tools) (`emit`) | - |
| `tools/execute` | `waterfall` | [`packages/core/tools/src/index.ts:43`](../../packages/core/tools/src/index.ts) | [`tools`](../../packages/core/tools) (`waterfall`) | - |
| `tools/change` | `emit` | [`packages/core/tools/src/index.ts:84`](../../packages/core/tools/src/index.ts) | [`tools`](../../packages/core/tools) (`emit`) | - |
| `tools/post-execute` | `waterfall` | [`packages/core/tools/src/index.ts:79`](../../packages/core/tools/src/index.ts) | [`tools`](../../packages/core/tools) (`waterfall`) | [`hooks-claude`](../../packages/hooks/hooks-claude), [`hooks-codex`](../../packages/hooks/hooks-codex) |
| `tools/pre-execute` | `waterfall` | [`packages/core/tools/src/index.ts:65`](../../packages/core/tools/src/index.ts) | [`tools`](../../packages/core/tools) (`waterfall`) | [`hooks-claude`](../../packages/hooks/hooks-claude), [`hooks-codex`](../../packages/hooks/hooks-codex) |
| `web/providers-change` | `emit` | [`packages/web/web/src/index.ts:65`](../../packages/web/web/src/index.ts) | [`web`](../../packages/web/web) (`emit`) | - |

View File

@@ -30,6 +30,12 @@ flowchart TD
pkg_bash_local["bash-local"]
pkg_tool_bash["tool-bash"]
end
subgraph group_fs["packages/fs"]
pkg_fs["fs"]
pkg_fs_local["fs-local"]
pkg_fs_policy["fs-policy"]
pkg_tool_fs["tool-fs"]
end
subgraph group_compact["packages/compact"]
pkg_compact["compact"]
pkg_compact_basic["compact-basic"]
@@ -42,14 +48,27 @@ flowchart TD
pkg_subagent_spawn["subagent-spawn"]
pkg_tool_subagent["tool-subagent"]
end
subgraph group_web["packages/web"]
pkg_tool_web["tool-web"]
pkg_web["web"]
pkg_web_fetch_local["web-fetch-local"]
pkg_web_search_deepseek["web-search-deepseek"]
pkg_web_search_exa["web-search-exa"]
pkg_web_search_perplexity["web-search-perplexity"]
end
subgraph group_todo["packages/todo"]
pkg_tool_todo["tool-todo"]
end
subgraph group_hooks["packages/hooks"]
pkg_hook_protocol["hook-protocol"]
pkg_hooks_claude["hooks-claude"]
pkg_hooks_codex["hooks-codex"]
end
subgraph group_session_persistence["packages/session-persistence"]
pkg_session_persistence["session-persistence"]
pkg_session_persistence_jsonl["session-persistence-jsonl"]
pkg_session_persistence_sqlite["session-persistence-sqlite"]
end
subgraph group_todo["packages/todo"]
pkg_tool_todo["tool-todo"]
end
subgraph group_support["packages/support"]
pkg_invariants["invariants"]
pkg_llm_replay["llm-replay"]
@@ -69,11 +88,22 @@ flowchart TD
pkg_session --> pkg_llm
pkg_system_prompt --> pkg_llm
pkg_bash_local --> pkg_bash
pkg_fs --> pkg_brand
pkg_fs --> pkg_llm
pkg_web --> pkg_llm
pkg_agent --> pkg_brand
pkg_agent --> pkg_llm
pkg_agent --> pkg_session
pkg_fs_local --> pkg_fs
pkg_fs_policy --> pkg_fs
pkg_compact --> pkg_llm
pkg_compact --> pkg_session
pkg_web_fetch_local --> pkg_web
pkg_web_search_deepseek --> pkg_web
pkg_web_search_exa --> pkg_web
pkg_web_search_perplexity --> pkg_web
pkg_hook_protocol --> pkg_bash
pkg_hook_protocol --> pkg_session
pkg_session_persistence --> pkg_session
pkg_llm_replay --> pkg_llm
pkg_llm_replay --> pkg_session
@@ -104,12 +134,26 @@ flowchart TD
pkg_tool_bash --> pkg_bash
pkg_tool_bash --> pkg_llm
pkg_tool_bash --> pkg_tools
pkg_tool_fs --> pkg_fs
pkg_tool_fs --> pkg_llm
pkg_tool_fs --> pkg_session
pkg_tool_fs --> pkg_system_prompt
pkg_tool_fs --> pkg_tools
pkg_subagent --> pkg_agent
pkg_subagent --> pkg_llm
pkg_subagent --> pkg_tools
pkg_tool_web --> pkg_llm
pkg_tool_web --> pkg_system_prompt
pkg_tool_web --> pkg_tools
pkg_tool_web --> pkg_web
pkg_tool_todo --> pkg_agent
pkg_tool_todo --> pkg_session
pkg_tool_todo --> pkg_tools
pkg_hooks_codex --> pkg_agent
pkg_hooks_codex --> pkg_hook_protocol
pkg_hooks_codex --> pkg_llm
pkg_hooks_codex --> pkg_session
pkg_hooks_codex --> pkg_tools
pkg_acp --> pkg_agent
pkg_acp --> pkg_llm
pkg_acp --> pkg_session
@@ -134,6 +178,12 @@ flowchart TD
pkg_tool_subagent --> pkg_llm
pkg_tool_subagent --> pkg_subagent
pkg_tool_subagent --> pkg_tools
pkg_hooks_claude --> pkg_agent
pkg_hooks_claude --> pkg_hook_protocol
pkg_hooks_claude --> pkg_llm
pkg_hooks_claude --> pkg_session
pkg_hooks_claude --> pkg_subagent
pkg_hooks_claude --> pkg_tools
pkg_subagent_mock --> pkg_agent
pkg_subagent_mock --> pkg_llm
pkg_subagent_mock --> pkg_subagent
@@ -163,8 +213,17 @@ flowchart TD
| [`session`](../../packages/core/session) | `core` | [`brand`](../../packages/util/brand), [`llm`](../../packages/llm/llm) |
| [`system-prompt`](../../packages/core/system-prompt) | `core` | [`llm`](../../packages/llm/llm) |
| [`bash-local`](../../packages/bash/bash-local) | `bash` | [`bash`](../../packages/bash/bash) |
| [`fs`](../../packages/fs/fs) | `fs` | [`brand`](../../packages/util/brand), [`llm`](../../packages/llm/llm) |
| [`web`](../../packages/web/web) | `web` | [`llm`](../../packages/llm/llm) |
| [`agent`](../../packages/core/agent) | `core` | [`brand`](../../packages/util/brand), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session) |
| [`fs-local`](../../packages/fs/fs-local) | `fs` | [`fs`](../../packages/fs/fs) |
| [`fs-policy`](../../packages/fs/fs-policy) | `fs` | [`fs`](../../packages/fs/fs) |
| [`compact`](../../packages/compact/compact) | `compact` | [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session) |
| [`web-fetch-local`](../../packages/web/web-fetch-local) | `web` | [`web`](../../packages/web/web) |
| [`web-search-deepseek`](../../packages/web/web-search-deepseek) | `web` | [`web`](../../packages/web/web) |
| [`web-search-exa`](../../packages/web/web-search-exa) | `web` | [`web`](../../packages/web/web) |
| [`web-search-perplexity`](../../packages/web/web-search-perplexity) | `web` | [`web`](../../packages/web/web) |
| [`hook-protocol`](../../packages/hooks/hook-protocol) | `hooks` | [`bash`](../../packages/bash/bash), [`session`](../../packages/core/session) |
| [`session-persistence`](../../packages/session-persistence/session-persistence) | `session-persistence` | [`session`](../../packages/core/session) |
| [`llm-replay`](../../packages/support/llm-replay) | `support` | [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session) |
| [`tools`](../../packages/core/tools) | `core` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`system-prompt`](../../packages/core/system-prompt) |
@@ -175,13 +234,17 @@ flowchart TD
| [`ui-stdio`](../../packages/support/ui-stdio) | `support` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session) |
| [`agent-loop`](../../packages/core/agent-loop) | `core` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`session-persistence`](../../packages/session-persistence/session-persistence), [`system-prompt`](../../packages/core/system-prompt), [`tools`](../../packages/core/tools) |
| [`tool-bash`](../../packages/bash/tool-bash) | `bash` | [`agent`](../../packages/core/agent), [`bash`](../../packages/bash/bash), [`llm`](../../packages/llm/llm), [`tools`](../../packages/core/tools) |
| [`tool-fs`](../../packages/fs/tool-fs) | `fs` | [`fs`](../../packages/fs/fs), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`system-prompt`](../../packages/core/system-prompt), [`tools`](../../packages/core/tools) |
| [`subagent`](../../packages/subagent/subagent) | `subagent` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`tools`](../../packages/core/tools) |
| [`tool-web`](../../packages/web/tool-web) | `web` | [`llm`](../../packages/llm/llm), [`system-prompt`](../../packages/core/system-prompt), [`tools`](../../packages/core/tools), [`web`](../../packages/web/web) |
| [`tool-todo`](../../packages/todo/tool-todo) | `todo` | [`agent`](../../packages/core/agent), [`session`](../../packages/core/session), [`tools`](../../packages/core/tools) |
| [`hooks-codex`](../../packages/hooks/hooks-codex) | `hooks` | [`agent`](../../packages/core/agent), [`hook-protocol`](../../packages/hooks/hook-protocol), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`tools`](../../packages/core/tools) |
| [`acp`](../../packages/ui/acp) | `ui` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`session-persistence`](../../packages/session-persistence/session-persistence), [`tools`](../../packages/core/tools) |
| [`agent-core`](../../packages/core/agent-core) | `core` | [`agent`](../../packages/core/agent), [`agent-loop`](../../packages/core/agent-loop), [`invariants`](../../packages/support/invariants), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`system-prompt`](../../packages/core/system-prompt), [`tool-bash`](../../packages/bash/tool-bash), [`tools`](../../packages/core/tools) |
| [`subagent-acp`](../../packages/subagent/subagent-acp) | `subagent` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`subagent`](../../packages/subagent/subagent) |
| [`subagent-inprocess`](../../packages/subagent/subagent-inprocess) | `subagent` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`subagent`](../../packages/subagent/subagent) |
| [`tool-subagent`](../../packages/subagent/tool-subagent) | `subagent` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`subagent`](../../packages/subagent/subagent), [`tools`](../../packages/core/tools) |
| [`hooks-claude`](../../packages/hooks/hooks-claude) | `hooks` | [`agent`](../../packages/core/agent), [`hook-protocol`](../../packages/hooks/hook-protocol), [`llm`](../../packages/llm/llm), [`session`](../../packages/core/session), [`subagent`](../../packages/subagent/subagent), [`tools`](../../packages/core/tools) |
| [`subagent-mock`](../../packages/support/subagent-mock) | `support` | [`agent`](../../packages/core/agent), [`llm`](../../packages/llm/llm), [`subagent`](../../packages/subagent/subagent) |
| [`subagent-fork`](../../packages/subagent/subagent-fork) | `subagent` | [`agent`](../../packages/core/agent), [`session`](../../packages/core/session), [`subagent`](../../packages/subagent/subagent), [`subagent-inprocess`](../../packages/subagent/subagent-inprocess) |
| [`subagent-spawn`](../../packages/subagent/subagent-spawn) | `subagent` | [`subagent`](../../packages/subagent/subagent), [`subagent-inprocess`](../../packages/subagent/subagent-inprocess) |

View File

@@ -5,20 +5,23 @@
Maintenance mode: curated Mermaid sequence based on the snapshot test harness.
This graph explains what a snapshot scenario proves: recorded real-model session logs are replayed keylessly, then ACP stdout is normalized and diffed.
This graph explains what a snapshot scenario proves: recorded real-model session logs are replayed keylessly, ACP stdout is normalized and diffed, and scenario workspaces preserve tool side effects that the UI stream alone cannot prove.
```mermaid
sequenceDiagram
participant Recorder as Real API recording
participant Fixture as snapshot fixture
participant Workspace
participant Replay as llm-replay adapter
participant ACP as acp-agent subprocess
participant Golden as stdout golden
Recorder->>Fixture: session.jsonl + workspace inputs
Fixture->>Workspace: seed files and hook configs
Fixture->>Replay: recorded StreamChunk script
Replay->>ACP: deterministic llm/stream chunks
ACP->>Workspace: bash, fs, and hook side effects
ACP->>Golden: normalized sessionUpdate stream
Golden-->>ACP: diff must be empty
```
Future pressure from the fs stack: policy rejection scenarios are valuable because they prove both world state and failed tool-card rendering, not just that replay returns text.
The fs and hook snapshot matrix is valuable because it proves world state, hook decisions, and failed tool-card rendering, not just that replay returns text.

View File

@@ -16,6 +16,13 @@ flowchart LR
toolpkg__deepseek_ai_dsh_tool_bash --> requires_ctx_tools
requires_ctx_bash["ctx.bash"]
toolpkg__deepseek_ai_dsh_tool_bash --> requires_ctx_bash
toolpkg__deepseek_ai_dsh_tool_fs["tool-fs<br/>edit, read, write"]
model --> toolpkg__deepseek_ai_dsh_tool_fs
toolpkg__deepseek_ai_dsh_tool_fs --> requires_ctx_tools
requires_ctx_fs["ctx.fs"]
toolpkg__deepseek_ai_dsh_tool_fs --> requires_ctx_fs
requires_ctx_systemPrompt["ctx.systemPrompt"]
toolpkg__deepseek_ai_dsh_tool_fs --> requires_ctx_systemPrompt
toolpkg__deepseek_ai_dsh_tool_subagent["tool-subagent<br/>subagent"]
model --> toolpkg__deepseek_ai_dsh_tool_subagent
toolpkg__deepseek_ai_dsh_tool_subagent --> requires_ctx_tools
@@ -26,10 +33,18 @@ flowchart LR
toolpkg__deepseek_ai_dsh_tool_todo --> requires_ctx_tools
requires_owning_Agent_session["owning Agent session"]
toolpkg__deepseek_ai_dsh_tool_todo --> requires_owning_Agent_session
toolpkg__deepseek_ai_dsh_tool_web["tool-web<br/>web_fetch, web_search"]
model --> toolpkg__deepseek_ai_dsh_tool_web
toolpkg__deepseek_ai_dsh_tool_web --> requires_ctx_tools
requires_ctx_web["ctx.web"]
toolpkg__deepseek_ai_dsh_tool_web --> requires_ctx_web
toolpkg__deepseek_ai_dsh_tool_web --> requires_ctx_systemPrompt
```
| Tool package | Model-visible names | Requires | Writes / affects | Shipped aliases | Note |
| --- | --- | --- | --- | --- | --- |
| `@deepseek-ai/dsh-tool-bash` | `bash`, `bash_kill`, `bash_output` | `ctx.tools`, `ctx.bash` | `tool/call`, `tool/result`, `context/message via agent.inject() for background completion notices` | - | The bash/bash_output/bash_kill tools are model-facing consumers of the bash executor seam. |
| `@deepseek-ai/dsh-tool-fs` | `edit`, `read`, `write` | `ctx.tools`, `ctx.fs`, `ctx.systemPrompt` | `tool/call`, `fs/write-intent or fs/edit-intent for mutations`, `fs/observed after successful file operations`, `tool/result` | - | read/write/edit are the model-facing filesystem tools; read windowing lives here, while read-before-edit policy is supplied by fs-policy through fs/* events. |
| `@deepseek-ai/dsh-tool-subagent` | `subagent` | `ctx.tools`, `ctx.subagents` | `tool/call`, `tool/result`, `child session events through the chosen provider` | `subagent`, `subagent_fork` | The default package schema registers subagent; shipped coding/acp configs load it twice to expose spawn and fork backends. |
| `@deepseek-ai/dsh-tool-todo` | `todo_write` | `ctx.tools`, `owning Agent session` | `tool/call`, `todo/write`, `tool/result` | - | todo_write is session-owned state; UIs render the latest todo/write event as a checklist or ACP plan. |
| `@deepseek-ai/dsh-tool-web` | `web_fetch`, `web_search` | `ctx.tools`, `ctx.web`, `ctx.systemPrompt` | `tool/call`, `tool/result` | - | web_search and web_fetch keep provider selection behind ctx.web so model-visible schemas stay stable across backend swaps. |

View File

@@ -5,26 +5,35 @@
Maintenance mode: curated Mermaid flow; exact tool schemas and event signatures live in generated catalogs.
This graph shows where policy, hooks, sandboxing, and future filesystem guards fit without changing the loop. The key extension point is the `tools/execute` waterfall.
This graph shows where policy, hooks, sandboxing, filesystem guards, result rewriting, and UI rendering fit without changing the loop. The key extension points are the `tools/pre-execute` and `tools/post-execute` waterfalls.
```mermaid
flowchart TD
model["Assistant message contains tool-call block"]
toolCall["Session event: tool/call"]
waterfall["ctx.tools.execute()<br/>tools/execute waterfall"]
policy["Policy / permission / hooks listener"]
toolCall["Session event: tool/call<br/>logged before execution"]
presentCall["UI pending card<br/>presentCall(args)"]
pre["tools/pre-execute waterfall<br/>hooks, permission, sandbox"]
denied["deny or ask<br/>tool body skipped"]
toolBody["Registered tool execute() body"]
owned["Tool-owned session events<br/>todo/write, future fs policy facts"]
toolResult["Session event: tool/result"]
ui["UI presentation<br/>presentCall / presentResult"]
model --> toolCall --> waterfall
waterfall --> policy
policy -->|next| toolBody
policy -->|veto / throw| toolResult
fsGate["fs/write-intent or fs/edit-intent<br/>tool-fs mutations only"]
owned["Tool-owned session events<br/>todo/write, fs/observed, hook/invoked, hook/result"]
post["tools/post-execute waterfall<br/>accept, block, replace, add context"]
context["Buffered additionalContext<br/>context/message after all tool results"]
toolResult["Session event: tool/result<br/>single model-facing outcome"]
presentResult["UI completed card<br/>presentResult(args, result)"]
model --> toolCall
toolCall --> presentCall
toolCall --> pre
pre -->|allow| toolBody
pre -->|deny or ask| denied
denied --> post
toolBody --> fsGate
fsGate --> toolBody
toolBody --> owned
toolBody --> toolResult
toolCall --> ui
toolResult --> ui
toolBody --> post
post --> context
post --> toolResult
toolResult --> presentResult
```
Future pressure from the fs stack: PR #128 snapshots a policy rejection card. The graph keeps the veto path explicit because filesystem read-before-edit checks, permission prompts, and hook bridges all belong on this path.
Filesystem read-before-edit checks live below `tool-fs` on the `fs/*` event gate, while hook bridges and future permission prompts live on the generic tool waterfalls. That split lets the same hooks observe bash, fs, web, todo, and subagent calls without coupling those tools to one policy service.