Browse Source

merge: bring master's rc.5 release and cordis tool renames into feat/pwsh-persistent-pty

Huanqi Cao 2 months ago
parent
commit
f5c0d7e522
100 changed files with 3348 additions and 723 deletions
  1. 2 2
      .agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.i18n.yaml
  2. 2 2
      .agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md
  3. 2 2
      .agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.zh.md
  4. 2 2
      .agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml
  5. 2 0
      .agents/notes/implemented/feature/2026-06-15-code-mode.md
  6. 2 0
      .agents/notes/implemented/feature/2026-06-15-code-mode.zh.md
  7. 2 2
      .agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.i18n.yaml
  8. 1 1
      .agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.md
  9. 1 1
      .agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.zh.md
  10. 2 2
      .agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.i18n.yaml
  11. 4 4
      .agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md
  12. 4 4
      .agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.zh.md
  13. 2 2
      .agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.i18n.yaml
  14. 1 1
      .agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.md
  15. 1 1
      .agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.zh.md
  16. 6 0
      .agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.i18n.yaml
  17. 270 0
      .agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.md
  18. 270 0
      .agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.zh.md
  19. 2 2
      .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml
  20. 1 1
      .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md
  21. 1 1
      .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md
  22. 420 0
      apps/cli/config/agent-presets/cordis/skills/cordis-plugin-development/SKILL.md
  23. 5 3
      apps/cli/config/agent-presets/minimal/agent.cordis.yml
  24. 4 1
      apps/cli/package.json
  25. 5 2
      apps/cli/tests/web-agent-presets.e2e.ts
  26. 1 1
      apps/web/package.json
  27. 1 1
      apps/web/tests/assembled-boot.ts
  28. 70 25
      apps/web/tests/cordis-tool-round.e2e.ts
  29. 3 0
      apps/web/tests/minimal-preset.snapshot.ts
  30. 6 6
      apps/web/tests/scaffold.ts
  31. 1 1
      apps/web/tests/smoke-real.e2e.ts
  32. 18 17
      apps/web/tests/snapshots/cordis-tool-round/session.jsonl
  33. 51 22
      apps/web/tests/snapshots/cordis-tool-round/ui.expected.md
  34. 1 1
      apps/web/tests/workspace-management.e2e.ts
  35. 2 2
      docs/capability-seams.i18n.yaml
  36. 21 0
      docs/capability-seams.md
  37. 21 0
      docs/capability-seams.zh.md
  38. 2 2
      docs/config-catalog.i18n.yaml
  39. 29 23
      docs/config-catalog.md
  40. 29 22
      docs/config-catalog.zh.md
  41. 1 1
      docs/cordis-api/inherited.md
  42. 2 2
      docs/event-producer-consumer.i18n.yaml
  43. 7 1
      docs/event-producer-consumer.md
  44. 7 1
      docs/event-producer-consumer.zh.md
  45. 2 2
      docs/module-graph.i18n.yaml
  46. 118 79
      docs/module-graph.md
  47. 118 79
      docs/module-graph.zh.md
  48. 2 2
      docs/subsystems/README.i18n.yaml
  49. 1 0
      docs/subsystems/README.md
  50. 1 0
      docs/subsystems/README.zh.md
  51. 6 0
      docs/subsystems/extensions.i18n.yaml
  52. 364 0
      docs/subsystems/extensions.md
  53. 364 0
      docs/subsystems/extensions.zh.md
  54. 2 2
      docs/subsystems/lsp.i18n.yaml
  55. 37 0
      docs/subsystems/lsp.md
  56. 37 0
      docs/subsystems/lsp.zh.md
  57. 2 2
      docs/subsystems/system-prompt.i18n.yaml
  58. 9 1
      docs/subsystems/system-prompt.md
  59. 9 1
      docs/subsystems/system-prompt.zh.md
  60. 2 2
      docs/subsystems/typert.i18n.yaml
  61. 17 0
      docs/subsystems/typert.md
  62. 17 0
      docs/subsystems/typert.zh.md
  63. 2 2
      docs/tool-catalog.i18n.yaml
  64. 140 15
      docs/tool-catalog.md
  65. 140 15
      docs/tool-catalog.zh.md
  66. 2 0
      examples/acp-agent/advanced.cordis.snapshot.yml
  67. 2 0
      examples/acp-agent/advanced.cordis.yml
  68. 2 0
      examples/acp-agent/cordis-tools.cordis.yml
  69. 3 2
      examples/acp-agent/tests/acp.snapshot.ts
  70. 10 3
      examples/acp-agent/tests/snapshots/advanced-toolchain/input.json
  71. 1 1
      examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
  72. 1 1
      examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
  73. 60 58
      examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl
  74. 128 7
      examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md
  75. 122 13
      examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json
  76. 1 1
      examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md
  77. 1 1
      examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json
  78. 1 1
      examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md
  79. 1 1
      examples/acp-agent/tests/snapshots/code-mode-turn/tool-schemas.expected.json
  80. 1 1
      examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/input.json
  81. 4 6
      examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
  82. 2 0
      examples/headless-agent/advanced.cordis.snapshot.yml
  83. 2 0
      examples/headless-agent/advanced.cordis.yml
  84. 64 26
      examples/headless-agent/tests/code-mode.e2e.ts
  85. 10 3
      examples/headless-agent/tests/snapshots/advanced-toolchain/input.json
  86. 3 3
      examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl
  87. 3 3
      examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl
  88. 2 2
      examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl
  89. 60 58
      examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl
  90. 2 2
      examples/jsonrpc-agent/README.i18n.yaml
  91. 1 1
      examples/jsonrpc-agent/README.md
  92. 1 1
      examples/jsonrpc-agent/README.zh.md
  93. 3 1
      examples/jsonrpc-agent/minimal.cordis.yml
  94. 17 16
      examples/jsonrpc-agent/tests/sdk.snapshot.ts
  95. 71 72
      examples/jsonrpc-agent/tests/snapshots/persistent-tools/notifications.expected.jsonl
  96. 71 72
      examples/jsonrpc-agent/tests/snapshots/persistent-tools/session.jsonl
  97. 1 0
      examples/package.json
  98. 2 0
      examples/web-cordis/cordis.yml
  99. 12 0
      knip.json
  100. 4 1
      package.json

+ 2 - 2
.agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md
-2026-08-10-minimal-preset-owns-rl-composition.md: d83083de74f1d3203822d82e4e04560819412b48
-2026-08-10-minimal-preset-owns-rl-composition.zh.md: 36aeea0d8af6e371eddd6f09e36bb48a0348959e
+2026-08-10-minimal-preset-owns-rl-composition.md: 65d24f9a03eedffac34f0c0141a8e2f643a48b7b
+2026-08-10-minimal-preset-owns-rl-composition.zh.md: 72eaa0e5bba46743abd336e64316c886fa58631a

+ 2 - 2
.agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md

@@ -14,13 +14,13 @@ The split also hid other drift. The preset mounted one-shot Bash rather than the
 
 The shipped Web `minimal` preset is the sole Web owner of the RL agent composition. It declares an entry-local PTY registry and local backend, persistent `bash` with the RL environment description and 300-second timeout, and `str_replace_editor`. Tool presentation remains a deployment choice. The later [bare two-tool runtime decision](../feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md) supersedes this note's original compaction and filesystem-provider choices: the current preset mounts an entry-local `fs-local` provider and no compaction backend. The editor accepts no `requireAbsolutePath` setting because absolute paths are its unconditional contract.
 
-The preset persona is exactly `You are a helpful software engineer assistant.` and sets `complete: true`. A complete `PromptSection` participates in ordinary assembly so tools, contexts, variables, and cooperative listeners still resolve; after the `system-prompt/assemble` waterfall, the prompt registry restores a detached copy of that section as the sole system-prompt section. Multiple effective complete sections reject assembly. This final registry constraint prevents harness identity, Web orientation, tool guidance, or an assembly listener from appending prompt text.
+The preset persona is exactly `You are a helpful software engineer assistant.`, sets `complete: true`, and suppresses runtime context for its agent scope. A complete `PromptSection` participates in ordinary assembly so tools, variables, and cooperative listeners still resolve; after the `system-prompt/assemble` waterfall, the prompt registry restores a detached copy of that section as the sole system-prompt section and discards every dynamic context contribution. Multiple effective complete sections reject assembly. These final registry constraints prevent harness identity, Web orientation, tool guidance, an assembly listener, sandbox policy, approval policy, delegation, or another dynamic context provider from adding model input.
 
 The process-wide `core-web.cordis.yml` patch is absent. Browser UI, workspace attachment, persistence, subprocess, sandbox, permission, model routing, and other cross-session services remain host-owned. Selecting `minimal` changes one agent's model-facing composition and shadows the host filesystem provider only for that agent, without changing other sessions in the Web process.
 
 ## Verification
 
-System-prompt and persona package tests prove final complete-section enforcement, including waterfall mutation and duplicate rejection. The shipped-preset composition test asserts the exact prompt, Bash description, absolute editor schema, and two-tool catalog under the default native presentation. The keyless Web replay sends a real request through a `minimal` agent while global identity, Web-orientation text, and a test section are registered, asserts the entry-local filesystem is bare and compaction is absent, then executes two persistent Bash calls to prove environment and cwd state survive and executes the editor through an absolute path.
+System-prompt and persona package tests prove final complete-section and runtime-context suppression, including waterfall mutation and duplicate rejection. The shipped-preset composition test asserts the exact prompt, Bash description, absolute editor schema, and two-tool catalog under the default native presentation. The keyless Web replay sends a real request through a `minimal` agent while global identity, Web-orientation text, dynamic policy contexts, and a test section are registered, asserts that no runtime-context snapshot exists, the entry-local filesystem is bare, and compaction is absent, then executes two persistent Bash calls to prove environment and cwd state survive and executes the editor through an absolute path.
 
 The standalone [`minimal.cordis.yml`](../../../../examples/jsonrpc-agent/minimal.cordis.yml) is the complete two-tool composition for the bundled JSON-RPC runtime. The [bare two-tool runtime decision](../feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md) owns its launch-specific environment configuration, bare filesystem, and absence of compaction. Its keyless SDK replay asserts the assembled system prompt and two-tool catalog, executes persistent Bash across calls, and exercises the editor; the Python SDK tutorial provides the runnable entry point.
 

+ 2 - 2
.agents/notes/implemented/bug-fix/2026-08-10-minimal-preset-owns-rl-composition.zh.md

@@ -14,13 +14,13 @@ Status: implemented
 
 随附的 Web `minimal` preset 是 RL agent 组合在 Web 中的唯一所有者。它声明 entry 本地的 PTY 注册表与本地后端、带 RL 环境描述且超时为 300 秒的持久 `bash`,以及 `str_replace_editor`。工具呈现仍由部署选择。后续的[裸双工具运行时决策](../feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md)取代了本记录最初的压缩与文件系统提供方选择:当前 preset 挂载 entry 本地的 `fs-local` 提供方,不挂载压缩后端。编辑器不接受 `requireAbsolutePath` 设置,因为要求绝对路径是它的无条件约定。
 
-preset persona 恰好是 `You are a helpful software engineer assistant.`,并设置 `complete: true`。complete `PromptSection` 参与常规组装,因此工具、上下文、变量和协作式监听器仍会解析;`system-prompt/assemble` waterfall(瀑布式事件)结束后,提示词注册表会将该段落的独立副本恢复为唯一的系统提示词段落。存在多个有效 complete 段时,组装会被拒绝。这项最终注册表约束可防止 harness 身份、Web 定位、工具引导或组装监听器追加提示词文本。
+preset persona 恰好是 `You are a helpful software engineer assistant.`,它设置 `complete: true`,并为其 agent 作用域抑制 runtime context。complete `PromptSection` 参与常规组装,因此工具、变量和协作式监听器仍会解析;`system-prompt/assemble` waterfall(瀑布式事件)结束后,提示词注册表会将该段落的独立副本恢复为唯一的系统提示词段落,并丢弃每个动态上下文贡献。存在多个有效 complete 段时,组装会被拒绝。这些最终注册表约束可防止 harness 身份、Web 定位、工具引导、组装监听器、沙箱策略、批准策略、委派或其他动态上下文提供方添加模型输入。
 
 进程级 `core-web.cordis.yml` patch 不再存在。浏览器 UI、workspace 附加、持久化、子进程、沙箱、权限、模型路由及其他跨会话服务仍由宿主持有。选择 `minimal` 会改变一个 agent 面向模型的组合,并且仅为该 agent 遮蔽宿主文件系统提供方,不会改变 Web 进程中的其他会话。
 
 ## 验证
 
-系统提示词与 persona 包测试证明了 complete 段的最终约束,包括 waterfall 修改与重复项拒绝。交付 preset 组合测试在默认原生呈现下断言精确的提示词、Bash 描述、要求绝对路径的编辑器 schema 和双工具目录。无密钥 Web 回放通过 `minimal` agent 发送一个真实请求,同时注册全局身份、Web 定位文本和一个测试段落;它断言 entry 本地文件系统是裸后端且压缩不存在,随后执行两次持久 Bash 调用,证明环境与 cwd 状态能够保留,并通过绝对路径执行编辑器。
+系统提示词与 persona 包测试证明了 complete 段最终约束与 runtime-context 抑制,包括 waterfall 修改与重复项拒绝。交付 preset 组合测试在默认原生呈现下断言精确的提示词、Bash 描述、要求绝对路径的编辑器 schema 和双工具目录。无密钥 Web 回放通过 `minimal` agent 发送一个真实请求,同时注册全局身份、Web 定位文本、动态策略上下文和一个测试段落;它断言不存在 runtime-context 快照、entry 本地文件系统是裸后端且压缩不存在,随后执行两次持久 Bash 调用,证明环境与 cwd 状态能够保留,并通过绝对路径执行编辑器。
 
 独立的 [`minimal.cordis.yml`](../../../../examples/jsonrpc-agent/minimal.cordis.yml) 是内置 JSON-RPC 运行时的完整双工具组合。[裸双工具运行时决策](../feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md)说明其启动方式专属的环境配置、裸文件系统和无压缩选择。其无密钥 SDK 回放会断言组装后的系统提示词与双工具目录,跨调用执行持久 Bash,并使用编辑器;Python SDK 教程提供可运行的入口。
 

+ 2 - 2
.agents/notes/implemented/feature/2026-06-15-code-mode.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-06-15-code-mode.md
-2026-06-15-code-mode.md: bc019c0b9acc6d834da41ceff2b1d1930fb34027
-2026-06-15-code-mode.zh.md: c19562b828089b6deeb048d30a08ce8681f150da
+2026-06-15-code-mode.md: adabf80ab03bdae57bba84957cdacf648c16c2f6
+2026-06-15-code-mode.zh.md: 24d83b9f896a73b449852d28c3e0a376fb6ace5a

+ 2 - 0
.agents/notes/implemented/feature/2026-06-15-code-mode.md

@@ -87,6 +87,8 @@ The worker runtime provides containment, not a security boundary: model code can
 
 The SDK instructs the model to write an async body in the loaded runtime's language (an erasable-TypeScript body by default; a Python `async` body under a Python runtime — see the [language-dispatch note](2026-07-31-code-mode-language-dispatch.md)), call tools through `await tools.name(args)`, catch rejected tool calls when needed, and return or log only the output that should re-enter context. Both flavors state the same contract in their own primitive: independent read-only calls MAY overlap under `Promise.all` (TypeScript) or `asyncio.gather` (Python), mutating calls run alone in submission order, and dependent work sequences with `await`. The declaration prefix can be as large as native schemas, especially in `'both'`, but remains stable for provider caching.
 
+The transport's own `description` and both SDK instruction flavors open by naming `code` and `description` as the call's two required arguments. Prose that describes the call as passing a program leaves the second argument discoverable only through the parameter schema, and a model that emits `{code}` alone loses the whole written program to an `INVALID_ARGS` rejection.
+
 ## Consequences
 
 Deployments switching to `'code'` must update any native-only `toolOrder`. Assembly listeners own the integrity of any rewritten protocol messages. Sub-dispatch starts in submission order under a bounded overlap pool, while per-call contexts retain their source, envelope, and metadata through the outer result.

+ 2 - 0
.agents/notes/implemented/feature/2026-06-15-code-mode.zh.md

@@ -87,6 +87,8 @@ worker 运行时只能约束程序的运行,而不构成安全边界:模型
 
 SDK 指示模型编写一个所加载运行时语言的异步函数体(默认可擦除 TypeScript;Python 运行时下为 Python `async` 函数体——见[语言分发 note](2026-07-31-code-mode-language-dispatch.md)),通过 `await tools.name(args)` 调用工具,在需要时捕获被拒绝的工具调用,并仅 return 或 log 应重新进入上下文的输出。两种 flavor 用各自的原语陈述同一约定:相互独立的只读调用可以(MAY)在 `Promise.all`(TypeScript)或 `asyncio.gather`(Python)下重叠,有副作用的调用按提交顺序单独运行,有依赖的工作用 `await` 排序。声明前缀可能与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。
 
+传输自身的 `description` 与两种 flavor 的 SDK 说明都以点名 `code` 和 `description` 这两个必填参数开头。把该调用描述成「传入一个程序」的散文会让第二个参数只能从参数 schema 中发现,而只发出 `{code}` 的模型会因 `INVALID_ARGS` 被拒,连同已写好的整个程序一起丢失。
+
 ## 后果
 
 切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议消息的完整性。子分发在有界的重叠池下按提交顺序启动,而每次调用的上下文会通过外层结果保留其 source、信封与元数据。

+ 2 - 2
.agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.md
-2026-07-30-current-sandbox-policy-context.md: ab231d19aec4852369c0f1a13fc50c69ab8128f1
-2026-07-30-current-sandbox-policy-context.zh.md: 4ac493dcfff5c286d569a46c34686dc4b8746618
+2026-07-30-current-sandbox-policy-context.md: b4c657ba52ff26e2e295e3635201424a155738d0
+2026-07-30-current-sandbox-policy-context.zh.md: bd32b021ef8622dc6843a163b21714a263bc8bed

+ 1 - 1
.agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.md

@@ -12,7 +12,7 @@ The sandbox policy already enforced and logged each session's file-effect mode,
 
 `dsh-sandbox-policy`, the owner of mode and workspace-root resolution, registers one `sandbox:policy` cache-safe context contribution. Every agent request resolves the active session directly through `ctx.sandboxPolicy.resolve({ session })`; there is no denial-history scan or process-local “last told” state.
 
-The policy contribution is capability-neutral and present for every agent session. It does not maintain a second inventory of mounted backends or tools; model-visible schemas remain the authority for available operations, while the context conditions its claims on any available operation that the DSH file sandbox enforces. The [capability-neutral policy context decision](../simplification/2026-07-31-capability-neutral-sandbox-policy-context.md) supersedes the earlier family-registration mechanism while retaining this note's cache-safe delivery and durable snapshot design.
+The policy contribution is capability-neutral and available to every agent session by default. A composition may suppress the complete runtime-context channel when its model interface intentionally excludes dynamic context; this does not disable policy enforcement. The contribution does not maintain a second inventory of mounted backends or tools; model-visible schemas remain the authority for available operations, while the context conditions its claims on any available operation that the DSH file sandbox enforces. The [capability-neutral policy context decision](../simplification/2026-07-31-capability-neutral-sandbox-policy-context.md) supersedes the earlier family-registration mechanism while retaining this note's cache-safe delivery and durable snapshot design.
 
 The contribution states only facts shared by every enforcement dialect. `read-only` says an available sandbox-enforced operation cannot modify files in the standing mode and directs the model to try an available tool normally, then follow any denial and escalation guidance that tool returns. `workspace-write` states the canonical session workspace with non-exclusive wording and summarizes, without enumerating, that some platform temporary areas may also be writable. `danger-full-access` says the DSH file sandbox does not restrict file modifications by available operations. Backend-selected temporary paths, `/dev/null`, runner readiness, exact tool availability, and other policy domains are absent because `resolve()` cannot establish them at request assembly.
 

+ 1 - 1
.agents/notes/implemented/feature/2026-07-30-current-sandbox-policy-context.zh.md

@@ -12,7 +12,7 @@ Status: implemented
 
 `dsh-sandbox-policy` 负责解析模式与工作区根目录,并注册一项缓存安全的 `sandbox:policy` 上下文贡献。每次 agent(智能体)请求都通过 `ctx.sandboxPolicy.resolve({ session })` 直接解析当前会话;不存在拒绝历史扫描或进程本地的「上次告知」状态。
 
-该策略贡献不依赖具体能力,并存在于每个 agent 会话中。它不会另行维护一份已挂载后端或工具清单;模型可见的 schema 仍是可用操作的权威来源,而上下文会将其声明限定在 DSH 文件沙箱所强制执行的任何可用操作上。[不依赖具体能力的策略上下文决策](../simplification/2026-07-31-capability-neutral-sandbox-policy-context.md)取代了较早的家族注册机制,同时保留本 Agent Note 的缓存安全交付与持久快照设计。
+该策略贡献不依赖具体能力,并默认可用于每个 agent 会话。当模型接口有意排除动态上下文时,组合可以抑制完整的 runtime-context 通道;这不会禁用策略强制机制。该贡献不会另行维护一份已挂载后端或工具清单;模型可见的 schema 仍是可用操作的权威来源,而上下文会将其声明限定在 DSH 文件沙箱所强制执行的任何可用操作上。[不依赖具体能力的策略上下文决策](../simplification/2026-07-31-capability-neutral-sandbox-policy-context.md)取代了较早的家族注册机制,同时保留本 Agent Note 的缓存安全交付与持久快照设计。
 
 该贡献只说明所有强制执行方言所共有的事实。`read-only` 表明受沙箱强制执行的可用操作在常驻模式下无法修改文件,并指示模型正常尝试可用工具,随后遵循该工具返回的任何拒绝与升权引导。`workspace-write` 用非排他措辞说明规范化的会话工作区,并概述某些平台临时区域可能也可写,而不逐一列举。`danger-full-access` 表明 DSH 文件沙箱不会限制可用操作修改文件。后端选择的临时路径、`/dev/null`、runner 就绪状态、确切的工具可用情况和其他策略领域都不会出现,因为 `resolve()` 无法在请求组装时确定它们。
 

+ 2 - 2
.agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md
-2026-08-11-minimal-profiles-bare-two-tool-runtime.md: 92d00a77de3e378abccc2ea67ba38a0cc76e0eca
-2026-08-11-minimal-profiles-bare-two-tool-runtime.zh.md: 1528b241436171145839240c7415ef18acab337f
+2026-08-11-minimal-profiles-bare-two-tool-runtime.md: 2f26dda5ddc905076dbc2f6c681f462973bde793
+2026-08-11-minimal-profiles-bare-two-tool-runtime.zh.md: ffdd8f0ddb86535468dbcb4384a6ba18c97b7124

+ 4 - 4
.agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.md

@@ -12,7 +12,7 @@ The two launch paths also have different configuration owners. Web mounts a per-
 
 ## Decision
 
-Both shipped minimal profiles expose exactly persistent `bash` and `str_replace_editor`, mount no context-compaction provider, and run the editor against `@deepseek-ai/dsh-fs-local`. The Web preset isolates `ctx.fs` inside the agent entry and mounts `fs-local` beside the editor, so other Web agents retain the host filesystem provider. Its persona remains the fixed complete prompt owned by the earlier [minimal-preset composition decision](../bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md).
+Both shipped minimal profiles expose exactly persistent `bash` and `str_replace_editor`, mount no context-compaction provider, suppress every `dsh-system-prompt` runtime-context contribution for fresh sessions, and run the editor against `@deepseek-ai/dsh-fs-local`. The Web preset isolates `ctx.fs` inside the agent entry and mounts `fs-local` beside the editor, so other Web agents retain the host filesystem provider. Its persona remains the fixed complete prompt owned by the earlier [minimal-preset composition decision](../bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md) and applies runtime-context suppression only to that agent scope. The standalone spine forwards the same setting to its process-owned system-prompt service. Sandbox and approval services remain mounted and enforce their policies; only their model-facing dynamic context is absent.
 
 The standalone [`minimal.cordis.yml`](../../../../examples/jsonrpc-agent/minimal.cordis.yml) remains a complete JSON-RPC process composition. It mounts `dsh-sdk-jsonrpc-server`, the local PTY and subprocess services required by persistent Bash, `fs-local`, the two tool consumers, and uncompressed JSONL persistence. It does not mount `token-meter`, `compaction-basic`, `fs-sandbox`, or `fs-observation-policy`. Persistent Bash still consumes the deployment's danger-full-access sandbox policy; the editor is not confined by that policy.
 
@@ -20,9 +20,9 @@ The standalone [`minimal.cordis.yml`](../../../../examples/jsonrpc-agent/minimal
 
 ## Verification
 
-The Web replay boots the complete Web host, creates the agent through the preset service, and asserts that the scoped filesystem is bare, no scoped compaction service exists, and the assembled request contains exactly the fixed prompt and two tools. It then executes persistent Bash and the editor against the real scoped services.
+The Web replay boots the complete Web host, creates the agent through the preset service, and asserts that the scoped filesystem is bare, no scoped compaction service exists, no system-prompt-owned runtime-context message was appended, and the assembled request contains exactly the fixed prompt and two tools. It then executes persistent Bash and the editor against the real scoped services.
 
-The SDK replay boots the real JSON-RPC agent process through the SDK client, injects an environment-selected prompt, asserts the assembled prompt and exact two-tool catalog, and executes both tools. Python SDK bundled-runtime coverage initializes the standalone configuration through each available packaged carrier with environment-selected model, model capacity, and prompt values. Cordis validation checks that both configurations resolve their declared plugins and configuration fields.
+The SDK replay boots the real JSON-RPC agent process through the SDK client, injects an environment-selected prompt, asserts the assembled prompt, exact two-tool catalog, and absence of every system-prompt-owned runtime-context message, and executes both tools. Python SDK bundled-runtime coverage initializes the standalone configuration through each available packaged carrier with environment-selected model, model capacity, and prompt values. Cordis validation checks that both configurations resolve their declared plugins and configuration fields.
 
 ## Alternatives considered
 
@@ -36,4 +36,4 @@ The SDK replay boots the real JSON-RPC agent process through the SDK client, inj
 
 ## Consequences
 
-Minimal sessions never summarize or replace earlier history; callers must keep turns within the selected model's context capacity. The editor can address any absolute path visible to the runtime process, independently of the persistent shell's sandbox policy. The two launch paths share their model-facing tool and no-compaction guarantees while retaining different prompt and model configuration appropriate to their owners. The Python SDK path continues to communicate only through the bundled stdio JSON-RPC runtime.
+Minimal sessions never summarize or replace earlier history and never add a runtime-context snapshot; callers must keep turns within the selected model's context capacity and must not rely on model-visible narration of standing sandbox or approval policy. The editor can address any absolute path visible to the runtime process, independently of the persistent shell's sandbox policy. The two launch paths share their model-facing tool, no-context, and no-compaction guarantees while retaining different prompt and model configuration appropriate to their owners. The Python SDK path continues to communicate only through the bundled stdio JSON-RPC runtime.

+ 4 - 4
.agents/notes/implemented/feature/2026-08-11-minimal-profiles-bare-two-tool-runtime.zh.md

@@ -12,7 +12,7 @@ Web `minimal` preset 与独立 JSON-RPC minimal 组合对外提供持久 `bash`
 
 ## 决策
 
-两种随附 minimal profile 都只对外提供持久 `bash` 与 `str_replace_editor`,不挂载上下文压缩提供方,并让编辑器使用 `@deepseek-ai/dsh-fs-local`。Web preset 在 agent entry 内隔离 `ctx.fs`,将 `fs-local` 与编辑器一起挂载,因此其他 Web agent 仍使用宿主文件系统提供方。其 persona 继续采用较早的 [minimal preset 组合决策](../bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md)所拥有的固定 complete 提示词。
+两种随附 minimal profile 都只对外提供持久 `bash` 与 `str_replace_editor`,不挂载上下文压缩提供方,为新建会话抑制每个 `dsh-system-prompt` runtime-context 贡献,并让编辑器使用 `@deepseek-ai/dsh-fs-local`。Web preset 在 agent entry 内隔离 `ctx.fs`,将 `fs-local` 与编辑器一起挂载,因此其他 Web agent 仍使用宿主文件系统提供方。其 persona 继续采用较早的 [minimal preset 组合决策](../bug-fix/2026-08-10-minimal-preset-owns-rl-composition.md)所拥有的固定 complete 提示词,并仅为该 agent 作用域实施 runtime-context 抑制。独立 spine 将同一设置转发给其进程拥有的 system-prompt 服务。沙箱与批准服务仍保持挂载并强制其策略;只有它们面向模型的动态上下文缺席。
 
 独立的 [`minimal.cordis.yml`](../../../../examples/jsonrpc-agent/minimal.cordis.yml) 仍是完整的 JSON-RPC 进程组合。它挂载 `dsh-sdk-jsonrpc-server`、持久 Bash 所需的本地 PTY 和子进程服务、`fs-local`、两个工具消费方,以及未压缩的 JSONL 持久化。它不挂载 `token-meter`、`compaction-basic`、`fs-sandbox` 或 `fs-observation-policy`。持久 Bash 仍消费部署的 danger-full-access 沙箱策略;编辑器不受该策略限制。
 
@@ -20,9 +20,9 @@ Web `minimal` preset 与独立 JSON-RPC minimal 组合对外提供持久 `bash`
 
 ## 验证
 
-Web 回放会启动完整 Web 宿主,通过 preset 服务创建 agent,并断言作用域文件系统为裸后端、不存在作用域压缩服务,而且组装请求只包含固定提示词与两个工具。随后,它通过真实作用域服务执行持久 Bash 和编辑器。
+Web 回放会启动完整 Web 宿主,通过 preset 服务创建 agent,并断言作用域文件系统为裸后端、不存在作用域压缩服务、没有追加 system-prompt 拥有的 runtime-context 消息,而且组装请求只包含固定提示词与两个工具。随后,它通过真实作用域服务执行持久 Bash 和编辑器。
 
-SDK 回放通过 SDK 客户端启动真实 JSON-RPC agent 进程,注入由环境选择的提示词,断言组装提示词与精确双工具目录,并执行两个工具。Python SDK 内置运行时覆盖会通过每种可用的打包载体,使用环境选择的模型、模型容量和提示词值初始化独立配置。Cordis 校验会检查两份配置能否解析声明的插件和配置字段。
+SDK 回放通过 SDK 客户端启动真实 JSON-RPC agent 进程,注入由环境选择的提示词,断言组装提示词与精确双工具目录,另外断言不存在任何 system-prompt 拥有的 runtime-context 消息,并执行两个工具。Python SDK 内置运行时覆盖会通过每种可用的打包载体,使用环境选择的模型、模型容量和提示词值初始化独立配置。Cordis 校验会检查两份配置能否解析声明的插件和配置字段。
 
 ## 考虑过的替代方案
 
@@ -36,4 +36,4 @@ SDK 回放通过 SDK 客户端启动真实 JSON-RPC agent 进程,注入由环
 
 ## 后果
 
-Minimal 会话不会摘要或替换较早历史;调用方必须让会话轮次保持在所选模型的上下文容量内。编辑器可以访问运行时进程可见的任何绝对路径,且不受持久 shell 沙箱策略影响。两条启动路径共享面向模型的工具与无压缩保证,同时保留适合各自所有者的不同提示词和模型配置。Python SDK 路径继续仅通过内置 stdio JSON-RPC 运行时通信。
+Minimal 会话不会摘要或替换较早历史,也不会添加 runtime-context 快照;调用方必须让会话轮次保持在所选模型的上下文容量内,且不得依赖模型可见的常驻沙箱或批准策略说明。编辑器可以访问运行时进程可见的任何绝对路径,且不受持久 shell 沙箱策略影响。两条启动路径共享面向模型的工具、无上下文与无压缩保证,同时保留适合各自所有者的不同提示词和模型配置。Python SDK 路径继续仅通过内置 stdio JSON-RPC 运行时通信。

+ 2 - 2
.agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.md
-2026-08-11-web-export-command-and-dialog.md: db4d63331282fbe06e87b282f9056187f2cd3e5e
-2026-08-11-web-export-command-and-dialog.zh.md: 971749963d309008a3b7727b7b485d1094ea7911
+2026-08-11-web-export-command-and-dialog.md: d28925500a45111d348b6151df9d4c62cc6de54b
+2026-08-11-web-export-command-and-dialog.zh.md: a9a9c4a5cc019a3242561e0cc5f8445625c7cb86

+ 1 - 1
.agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.md

@@ -10,7 +10,7 @@ Session export needs a stable Session-level visible action and an equivalent sla
 
 ## Decision
 
-`@deepseek-ai/dsh-session-log-download` registers a Web-only `/export` human command and provides the browser `ctx.sessionLogDownload` controller. The command records an ordinary `command/run` and `command/done`; after `command.execute` returns a successful result, `dsh-client-ui-commands` emits a local acknowledgment that asks this browser's controller to download ApiProxy's existing `GET /api/session.export` ZIP. Other clients render the broadcast command nodes without repeating the browser side effect. The 111×32 `Session log` capsule in the Session Header calls that controller directly. Both paths use a `HEAD` preflight for preparation errors, then hand the GET URL to the browser download manager so JavaScript never buffers the ZIP; they share the same in-flight state and Modal.
+`@deepseek-ai/dsh-session-log-export` registers a Web-only `/export` human command and provides the browser `ctx.sessionLogDownload` controller. The command records an ordinary `command/run` and `command/done`; after `command.execute` returns a successful result, `dsh-client-ui-commands` emits a local acknowledgment that asks this browser's controller to download ApiProxy's existing `GET /api/session.export` ZIP. Other clients render the broadcast command nodes without repeating the browser side effect. The 111×32 `Session log` capsule in the Session Header calls that controller directly. Both paths use a `HEAD` preflight for preparation errors, then hand the GET URL to the browser download manager so JavaScript never buffers the ZIP; they share the same in-flight state and Modal.
 
 The Header contribution occupies the right-aligned `conversation.session.header.utilities` list and renders the `Session log` text capsule with its trailing download icon plus the shared Modal. The title-adjacent `conversation.session.header.actions` list continues to own mode, Subagent, and Task entries, so mounting Session export does not reorder or move them. The export contribution does not observe Session history. A per-Session controller collapses concurrent gestures, aborts active preflights when its plugin disposes, ignores late requests after disposal, and preserves a user's closed state when the request later completes.
 

+ 1 - 1
.agents/notes/implemented/feature/2026-08-11-web-export-command-and-dialog.zh.md

@@ -10,7 +10,7 @@ Session 导出需要一个稳定的 Session 级外显入口,以及语义等价
 
 ## Decision
 
-`@deepseek-ai/dsh-session-log-download` 注册 Web 专用的 `/export` 用户命令,并提供浏览器 `ctx.sessionLogDownload` 控制器。该命令记录普通的 `command/run` 和 `command/done`;`command.execute` 返回成功结果后,`dsh-client-ui-commands` 会发布本地确认,请求当前浏览器的控制器下载 ApiProxy 现有的 `GET /api/session.export` ZIP。其他客户端会渲染广播的命令节点,但不会重复执行浏览器副作用。Session Header 中 111×32 的 `Session log` 胶囊按钮会直接调用该控制器。两种入口通过 `HEAD` 预检获得准备阶段错误,再把 GET URL 交给浏览器下载管理器,因此 JavaScript 不会缓冲 ZIP;两种入口共用进行中状态和 Modal。
+`@deepseek-ai/dsh-session-log-export` 注册 Web 专用的 `/export` 用户命令,并提供浏览器 `ctx.sessionLogDownload` 控制器。该命令记录普通的 `command/run` 和 `command/done`;`command.execute` 返回成功结果后,`dsh-client-ui-commands` 会发布本地确认,请求当前浏览器的控制器下载 ApiProxy 现有的 `GET /api/session.export` ZIP。其他客户端会渲染广播的命令节点,但不会重复执行浏览器副作用。Session Header 中 111×32 的 `Session log` 胶囊按钮会直接调用该控制器。两种入口通过 `HEAD` 预检获得准备阶段错误,再把 GET URL 交给浏览器下载管理器,因此 JavaScript 不会缓冲 ZIP;两种入口共用进行中状态和 Modal。
 
 Header 贡献占用最右侧的 `conversation.session.header.utilities` 列表,渲染带尾部下载图标的 `Session log` 文字 capsule 和共享 Modal。标题旁的 `conversation.session.header.actions` 列表继续承载模式、Subagent 和 Task 配置项,挂载 Session export 不会改变它们的顺序或位置。导出贡献不观察 Session 历史。逐 Session 控制器会折叠并发操作,在插件释放时取消活动预检,忽略释放后的迟到请求,并在请求后来完成时保留用户已经关闭弹窗的状态。
 

+ 6 - 0
.agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write .agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.md
+2026-08-08-cordis-web-dynamic-packages.md: c8ba3940bbcf7eeaa7b5a882f91ca8165bdd8cbf
+2026-08-08-cordis-web-dynamic-packages.zh.md: a6d961aef69e8820023ce3d749f0affd83a871c6

+ 270 - 0
.agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.md

@@ -0,0 +1,270 @@
+# Agent Note: Cordis Host/Client Dynamic Plugin Runtime
+
+Status: proposed
+
+English | [中文](2026-08-08-cordis-web-dynamic-packages.zh.md)
+
+## Problem
+
+The model needs to extend the current DSH process temporarily without modifying repository source, rebuilding the application, or refreshing the browser. An extension may run in the Host Node.js process, in a Client browser page, or as one plugin whose Host half retrieves data and whose Client half presents it.
+
+This capability cannot be limited to “execute some code.” Before writing code, the model needs to discover the Services, Events, Builtins, Slots, and theme tokens available on both platforms. The user needs to preview the code before deciding whether Client code may enter the page. A single plugin needs immutable versions, retries after failure, and rollback. Asynchronous runtime errors need to return to the model instead of remaining only in server logs or the browser console.
+
+Combining definition, approval, execution, version switching, capability discovery, and UI state into one action creates states that cannot be explained consistently: whether a successful definition also means a successful run; which version remains successful after a failed update; how long a Tool should wait when no page responds; which historical card owns the business UI after the same Package runs multiple times; and whether page-local Client load state can represent process-wide Host state.
+
+## Proposal
+
+### Core principles
+
+- The Host is the sole process-wide authority for Plugins, Packages, Runs, approvals, and version pointers.
+- The Client stores only the current page's approval interaction, load results, Slot contributions, business views, and page-local errors.
+- Define creates only immutable code versions; Run activates only a defined version.
+- A version switch commits `currentPackageId` only after the target Package completes its required Host/Client activation.
+- Before writing code, the model queries capabilities through Inspect Providers. Inspect results assist coding and are not plugin runtime business data.
+- Dynamic Host and Client code both use restricted plain JavaScript contexts and attach reversible side effects to the Cordis lifecycle.
+- Client code requires user authorization before entering a page. Authorization may cover one Package or future versions of the same Plugin.
+- Tool calls do not wait for approval or browser operations that may occur only after the current turn ends. State stores and model steering report asynchronous outcomes.
+
+### Package responsibilities and dependency direction
+
+Four packages under `packages/self-modification/` implement the dynamic runtime:
+
+| Package | npm package | Responsibility |
+| --- | --- | --- |
+| `tool-cordis` | `@deepseek-ai/dsh-tool-cordis` | Registers the System Prompt, seven model-facing Tools, Host Inspect Providers, `@pluginId` context injection, and Tool presentation metadata |
+| `cordis-host-runner` | `@deepseek-ai/dsh-cordis-host-runner` | Stores the authoritative Registry, allocates IDs, executes Host code, and manages versions, approvals, Runs, private handlers, Inspect routing, and model feedback |
+| `cordis-client-runner` | `@deepseek-ai/dsh-cordis-client-runner` | Synchronizes Inspect manifests in the browser, orchestrates approved Host→Client activation, evaluates Client code, and manages the Guard, Loader/Fiber, timer, styles, and teardown |
+| `ui-cordis` | `@deepseek-ai/dsh-client-ui-cordis` | Renders Define/Run Tool cards, the global Cordis panel, approval controls, version selection, runtime status, and Package-specific business views |
+
+`tool-cordis` depends only on the Host Runner's in-process service and does not import the Client implementation. `ui-cordis` consumes only the Client Runner face and Client-safe wire types and does not import the Host implementation. Existing generated Remote APIs and forwarded events connect Host and Client runtime control; the gateway owns no dynamic Plugin domain logic.
+
+### Domain objects
+
+#### Plugin
+
+A Plugin is a dynamic plugin instance that can be modified over time. It is identified by the branded type `CordisDynamicPluginId`, for example `clock-1`. When creating a Plugin, the model submits only a semantic prefix of 3 to 6 lowercase English letters; the Host appends a process-unique numeric suffix. The model cannot specify the complete `pluginId`.
+
+A Plugin belongs to the Session that defined it. Model-facing Tools can read and operate only Plugins from the current Session. The global Client panel can list Plugins from all Sessions, but each action still executes under the owner Session carried by that row.
+
+#### Package
+
+A Package is an immutable code version under a Plugin. It is identified by `CordisDynamicPackageId`, for example `pkg-2`. It contains a name, a purpose, optional Host code, and optional Client code, with at least one code half present. Every `cordis_define` creates a new Package; an existing Package cannot be modified in place.
+
+One Plugin may own multiple Packages, but at most one physical Run may exist at a time. Whether a Package contains a Host or Client half affects only its activation steps, not its version identity.
+
+#### Plugin Run
+
+A Plugin Run is one concrete activation attempt. It is identified by `CordisDynamicPluginRunId`, for example `run-3`. Every new activation attempt receives a new ID, including an attempt that fails after approval, a retry of the same Package, and a version update. `pluginRunId` associates approval, Host activation, Client loading, private RPC, Tool cards, and errors with the same attempt.
+
+The Host stores the current physical Run separately from `latestRun`. The physical Run is the activation that can currently receive calls and be torn down. `latestRun` records the approval, phase, status of both halves, and diagnostics for the most recent attempt. A failed attempt may leave no live physical Run while remaining available for inspection.
+
+#### Version pointers
+
+- `currentPackageId` is the most recent Package to complete its required activation flow. Stopping the plugin, beginning an update, or failing an update does not clear it.
+- `nextPackageId` is the target Package that is awaiting approval, activating, awaiting a Client, or most recently failed. It is cleared after the target succeeds and is committed as current.
+
+A Host-only Package commits current after the Host successfully establishes its Fiber. A Client-bearing Package commits current after Host activation succeeds and at least one Client successfully establishes the corresponding load. A Fiber that Cordis parks as waiting because a hard dependency is absent is still a successfully established lifecycle object; it is not equivalent to a parse or `apply` failure.
+
+If an update target fails, the old physical Run is not restarted automatically. The previous `currentPackageId` continues to identify the last successful version, and the failed target remains `nextPackageId`. The user or model can retry next, or reactivate current with `mode: "run"` to roll back.
+
+### Host authority and persistence
+
+`DynamicCordisRunnerService` and its internal Registry are the sole authority in the current DSH process. They store:
+
+- each Plugin's Session ownership and immutable Package set;
+- `currentPackageId`, `nextPackageId`, the physical Run, and `latestRun`;
+- per-Package authorization and cross-version Plugin authorization;
+- pending Client activation requests;
+- Host Fibers, Package-private handlers, waiting Services, and recent diagnostics;
+- Host and Client Inspect Registry directories and query routing.
+
+These objects are not written to configuration or disk and are not restored after process restart. The Session Log may retain Tool calls, results, and metadata needed by cards, but it does not replay dynamic code to restore the Registry. Historical cards remain in the conversation after a restart, but their original `pluginId` and `packageId` are no longer runnable.
+
+Runtime state is not written to Session projection as recoverable state. Refreshing a page or opening a new page does not automatically restore Client halves; automatic restoration would reintroduce connection identity, startup baselines, and cross-page consistency protocols, which are outside this design.
+
+### Define, Run, and version switching
+
+`cordis_define` has two modes: creating a Plugin submits `idPrefix`, while modifying an existing Plugin submits its exact `pluginId`. Code always uses `code: { host?, client? }`. Define validates arguments and plain JavaScript syntax, records immutable source, and returns the final IDs. It does not execute `apply`, create approval, change version pointers, or run implicitly.
+
+There is no separate `cordis_update`. `cordis_run` expresses activation intent through `mode`:
+
+| Version relationship | `mode` |
+| --- | --- |
+| No `currentPackageId` exists | `run` |
+| Target equals current, including restart, retry, or rollback | `run` |
+| Target differs from an existing current | `update` |
+| Retry `nextPackageId` after a failed update | `update` |
+
+Run first validates Plugin/Package ownership, the version relationship, and whether another transition is in progress. It then creates `pluginRunId` and writes `latestRun` and `nextPackageId`.
+
+A Host-only Package completes Host activation within the Tool call and returns `running` or a failure synchronously. A Client-bearing Package does not wait for a browser outcome within the Tool call: without authorization it registers approval and returns `awaiting-approval`; with authorization it registers automatic Client activation and returns `starting`. Both results mean that the request exists, not that full activation succeeded.
+
+When target activation actually starts, the Host stops the old physical Run before executing the target Host half. Only after Host success may the Client fetch and load source for the exact `pluginRunId`. Client success commits the version pointers. Any failure is recorded against that attempt, without restarting the old version and presenting it as target success.
+
+`cordis_stop` tears down the current Host/Client Run and pending approval request while retaining the Plugin, Packages, authorization, and version pointers. `cordis_undefine` stops first and then deletes the Plugin, Packages, authorization, and version pointers; historical cards then show only that the Plugin was removed.
+
+### Client approval and authorization
+
+A Package containing Client code requires user authorization before its first activation because model-generated code will run in the user's page. The approval panel offers three actions:
+
+- A single check authorizes the current Package. Later runs of the same Package do not need approval, but a new Package does.
+- A double check authorizes future versions of the current Plugin. New Packages, updates, retries, and rollbacks no longer require per-version approval.
+- Reject ends the current request without executing Host or Client code. The model must not immediately request approval again unless the user asks for it.
+
+Authorization is written to the Host Registry when the user allows it and remains even if a later technical step fails. When the panel runs a Package directly, the user's click itself authorizes that Package.
+
+A row awaiting approval shows only per-Package allow, cross-version allow, and reject; it does not simultaneously offer run, stop, or delete. The panel expands automatically when new approval appears. If auto-expansion fails or the panel is collapsed, the fixed entry and row status still show the pending approval count and state.
+
+### Client activation orchestration
+
+The Host sends Client activation requests through `cordis/request-run`. A request includes only request identity, Session, Plugin, Package, mode, name, purpose, and whether approval is required; it does not broadcast source code.
+
+An authorized page executes the following fixed sequence:
+
+1. Call `runHostHalf` to start the target Host half or bind to the same attempt's already-started Host Run.
+2. After Host success, call `getClientCode` with `pluginId + pluginRunId` to retrieve only the exact current Run's Client source.
+3. The Client Runner evaluates the plugin in the page, establishes its Loader entry/Fiber, and installs its Guard, styles, Slots, and page-local state.
+4. The page reports success, waiting, or failure through `resolveRequestRun` or `settleUserRun`.
+5. The Host accepts the report only for the still-current exact Run, commits current or saves diagnostics, and broadcasts request completion so other pages clear their activities.
+
+Host activation precedes Client activation so that the Client does not start before required Host handlers exist. A page may tear down the Host Run after Client failure only when that request created the Host Run; a page that merely bound to an existing Run does not own it.
+
+The Client Orchestrator stores pending approvals and active orchestration by `pluginId`, so one Plugin cannot run two page activations concurrently. Host inventory can reconstruct omitted pending-approval items and approval-free automatic activation requests.
+
+Client load state is a page-local fact. An active Host does not mean that the current page loaded the Client half. The UI has three primary states: gray “Ready” when no physical Run exists, yellow “Client ready to activate” when the Host runs but the current page has not successfully loaded the Client, and green “Running” when both halves are available in the current page. Approval and failure appear as additional states.
+
+This version does not establish per-connection identity or multi-page quorum. The first still-valid Client success may commit process-wide current; each page's store independently records whether that page loaded the Client.
+
+### Package-private Client-to-Host communication
+
+A dynamic Package uses a private JSON channel for Client-to-Host calls: the Host registers methods for the current Run with `harness.handle(method, handler)`, and the Client calls them with `host.call(method, args)`. Every call is associated with `pluginId + pluginRunId`, and the Host rejects stopped or stale Runs. Arguments and return values must be lossless JSON; functions, React elements, Contexts, Service instances, and class objects are forbidden.
+
+This channel serves only Client-to-Host calls within the same Package. It does not use public Remote Services or `ctx.remote` in dynamic code. The public Remote interface carries only the Runner's own control protocol and does not expose dynamic Packages.
+
+### Dynamic code, Guard, and lifecycle
+
+Host and Client both execute only plain JavaScript function bodies, without TypeScript, JSX, or bundler transformation. The Host executes in `node:vm`; the Client evaluates in a restricted closure. These contexts reduce misuse and provide instructional errors, but they are not security boundaries against malicious code.
+
+By default, the model reads an optional Service through `ctx.get('serviceName')` and checks for `undefined`. A plugin object declares `inject` only when the Service is a hard dependency whose absence must park the Package and whose later arrival must reactivate it. Direct `ctx.serviceName` access is allowed only when the same plugin declares the corresponding inject.
+
+Host and Client `timer` are same-named Cordis Services with the same interface, not global Builtins. A plugin that needs timers must declare `inject: ['timer']`; a timer created inside a React effect returns its disposer as cleanup.
+
+The current Fiber owns every registration and reversible side effect. Event listeners, Services, Tools, handlers, timers, Slots, styles, and theme overrides register through `ctx.effect()`, `ctx.on()`, or official APIs that return disposers. Stopping, updating, failure rollback, or undefining tears down both halves' contributions. Theme overrides are layered by source and return a disposer so unloading restores the previous theme values.
+
+Host, DSH, Cordis, and their Service instances, Event payloads, Slot props, Session/Conversation Snapshots, Tool state, and other runtime objects are internal live data. Dynamic code must not run `JSON.stringify`, `structuredClone`, recursive enumeration, full copying, or whole-object display on these objects or their descendants. It reads only leaf fields needed by the current task and constructs minimal owned data without Host references.
+
+### Inspect Providers and Catalogs
+
+Capability discovery uses three Tools: `cordis_inspect_list` lists Host/Client Provider manifests; `cordis_inspect_query` executes an explicit read-only query on the selected platform; and `cordis_inspect_self` queries the current Session's Plugins, Packages, source, version pointers, and runtime diagnostics.
+
+Host and Client each own a `CordisInspectRegistry`. A Provider registers a platform-unique ID, description, methods, input schemas, and output schemas. Provider methods are explicitly allowlisted queries, not arbitrary Service-method forwarding; the Registry has no layered target and does not automatically turn business Service methods into executable Inspect methods.
+
+The initial Providers are:
+
+| Platform | Provider.method | Data source |
+| --- | --- | --- |
+| Host / Client | `Service.listService` | Static Service Catalog for each platform |
+| Host / Client | `Event.listEvents` | Static Event Catalog for each platform |
+| Host / Client | `Builtin.listBuiltins` | Hand-maintained definitions beside the evaluator/Guard |
+| Host | `Tool.listTools` | Tool Registry actually visible to the current Agent |
+| Client | `Slots.listSubTree` | Static Slot Catalog plus the page's live subtree/occupants |
+| Client | `Theme.listTokens` | Read-only inspect export from ThemeService |
+
+When the Client Registry changes, it synchronizes the complete manifest to the Host without storing duplicate directories per Session. Host queries execute locally. For a Client query, the Host broadcasts a request ID and a page executes the local Provider and responds. The Host accepts only the first successful result that passes output-schema validation; a failed page does not settle the request. If no page succeeds, the Tool remains pending until a later success or Tool-call cancellation.
+
+Inspect data is used only before code is written to confirm capabilities, signatures, types, and mounting protocols. A plugin that needs runtime business data calls the actual Service or listens to the actual Event; it must not cache, display, or depend on Inspect/Catalog results.
+
+`CordisCatalogProjector` generates Host and Client Service and Event Catalogs separately through TypeRT. The Slot AST generator scans `SlotMap`, registration options, standard props, owner props, and referenced types; the Slots Provider merges the static Catalog with the live tree at query time. ThemeService exports theme tokens, Builtins are maintained manually beside the evaluator/Guard, and Tool schemas come from the Registry.
+
+Catalog generation scans real source signatures and then applies a model-visible allowlist. The allowlist may hide Services, members, `@deprecated` APIs, Runner-owned Services, and `cordis/*` control Events, but it must not rewrite method names, parameters, or return types for the remaining APIs. Guard may reject arguments, fix sources, or hide members, but it must respect source signatures.
+
+Model-visible owner JSDoc requires only a complete description, `@param` for every parameter, `@returns` for every non-void return, `@mode` for Events, and descriptions for Slot/props fields. Usage recommendations, counterexamples, and cross-capability choices belong in the Skill rather than duplicated Catalog example fields.
+
+### Model guidance layers
+
+Model guidance has four layers:
+
+- The System Prompt carries the stable runtime model, restrictions of both platforms, lifecycle, approval, version pointers, minimum code rules, and a usage map for the seven Tools. It still supports a minimally correct implementation when the Skill is unavailable.
+- The `cordis-plugin-development` Skill carries requirement navigation, capability composition, recommendations, and counterexamples without copying complete schemas.
+- Each Tool description states only that action's prerequisites, parameter semantics, synchronous or asynchronous result, and next step.
+- Provider/Catalog results supply current exact names, signatures, parameters, Slot props, tokens, and runtime query results.
+
+The System Prompt requires loading the Skill first, then listing/querying capabilities, and only then defining/running code. React examples in the Skill register into a Slot instead of returning a React Element directly from `apply()`. Examples use `React.createElement`, correct `ctx.get()`/`inject`, reversible effects, and minimal JSON RPC.
+
+### `@pluginId` and Tool UI
+
+The input system registers an `@pluginId` mention for the current Session. Selecting it injects only Plugin identity, the default baseline Package, version pointers, the active Run, and the latest status, not source code. The default baseline is selected in order from next, current, and the most recently defined Package. The model must read source through `cordis_inspect_self` before appending a Package in existing mode; an invalid mention must not silently create a replacement Plugin.
+
+The `cordis_define` card presents Host and Client code in two tabs. A `cordis_run` card associates with one exact attempt through `pluginRunId` and reads the Client store to show pending approval, Client ready to activate, running, failed, replaced by a later Run, or Plugin removed.
+
+A Package may register `key: "self"` into `tool.view.cordis`. At runtime, self binds to `pluginId + packageId`; the business Slot key omits `pluginRunId`, while owner props still provide the exact Run identity. The newest Run card for a Package owns the business UI, and earlier cards show that a newer Run exists. Cards react to store changes rather than scanning later Session Log entries or notifying one another.
+
+The global Cordis panel has one fixed entry and groups rows by current and other Sessions. Its title and collapse action remain fixed while only the list scrolls. A normal row can select a Package and run, stop, or delete it. A failed update can retry next or select current to roll back. A pending-approval row exposes only the two allow actions and reject.
+
+### Errors and model feedback
+
+Technical errors crossing Host and Client preserve the original `message` and preserve `stack` when the error object provides it. Structured diagnostics include `pluginId`, `packageId`, `pluginRunId`, and one phase: approval, host-load, host-apply, client-load, client-apply, or client-render.
+
+Host and Client Guards, Host evaluation and handlers, Client evaluation and apply, Slot `onEntryError`, and React ErrorBoundary all return errors to the owning Agent. The Client console also prints the original error object through `console.error`. A rendering error belongs to the exact Run and does not contaminate the immutable Package.
+
+After a model-initiated asynchronous Run succeeds, is rejected, or fails technically, `agent.steer` wakes the owning Agent. A technical failure requires the model to read diagnostics, correct the same Plugin, and retry autonomously. A user rejection forbids an automatic repeat request. A user's manual run, stop, or removal in the panel is supplied through context injection to the next step without waking the model proactively.
+
+## Alternatives considered
+
+**Combine Define and Run.** This removes the previewable “defined but not running” state and mixes syntax errors, approval, runtime errors, and retries into one action. The design therefore uses immutable Define and independent Run actions.
+
+**Use Package ID as Plugin ID.** A single-level ID cannot append immutable versions beneath a stable instance; updates would require stop, undefine, and a new define, while historical cards and `@` references could not retain object identity. The design therefore uses separate Plugin, Package, and Run identities.
+
+**Provide a separate `cordis_update`.** Update has the same loading, approval, UI, diagnostics, and execution semantics as Run, so a separate Tool would duplicate the protocol. It is represented by `cordis_run mode:"update"`.
+
+**Automatically restore the old physical Run after an update failure.** Automatic restoration combines “target failed” and “old version succeeded again” into one result. The design retains the old current pointer without restarting it, so the user explicitly chooses to retry next or run current.
+
+**Block `cordis_run` until user approval and the final Client outcome.** Approval or page interaction may only occur after the current model turn ends. Blocking would deadlock and occupy the Tool indefinitely when no page exists. The Tool returns immediately, while stores, Inspect, and steering report the final outcome.
+
+**Broadcast source from the Host and wait for Client acknowledgements with a timeout.** Broadcasting sends source to every page before authorization. A timeout cannot distinguish no page, a slow page, and no user action, and the Host would need compensating rollback. The protocol broadcasts only metadata, and an authorized page fetches source for the exact Run.
+
+**Automatically restore every Host-active Package when a page starts.** This requires connection identity, a startup baseline, and cross-page consistency. The design accepts page-local Client state and lets the user load again from the panel.
+
+**Connect Package halves through public Remote Services or `ctx.remote`.** This exposes dynamic Packages through the product RPC interface. Package-private `harness.handle`/`host.call` is sufficient for Client-to-Host JSON calls and rejects stale requests by `pluginRunId`.
+
+**Expose every Service method automatically as an Inspect query.** This turns capability discovery into a business-call proxy that bypasses plugin approval and lifecycle. Providers expose only curated read-only queries; the Service Catalog only describes business method signatures.
+
+**Put the complete API in the System Prompt or Skill.** Static text drifts and consumes context. The System Prompt retains stable rules, the Skill provides requirement navigation, and Provider/Catalog results return exact signatures and runtime directories.
+
+**Require Slot owners to register props schemas at runtime.** Slot props already exist in TypeScript types and JSDoc, so duplicate registration creates a second authority. The Slot AST Catalog extracts the static protocol and only merges the live tree at query time.
+
+**Write runtime state to the Session Log and restore it during replay.** Dynamic code and Fibers are process-local objects. Restoration would require re-executing historical code and reinterpreting approval. The Session retains only model-visible records; the Registry and page Runs are not restored.
+
+**Make historical Run cards scan later Session Log entries.** This couples Tool views to the complete log order and later message structure. The page card index/store already tells cards by Package when a later Run replaces them or their Plugin is deleted.
+
+## Acceptance criteria
+
+- A new Plugin can be created only from a 3-to-6-character lowercase English prefix; final Plugin, Package, and Run IDs are allocated by the Host and use branded types.
+- `cordis_define` validates only parameters and plain JavaScript syntax and returns an immutable Package; one Plugin can append versions while old source remains inspectable.
+- `cordis_run` strictly validates run/update; Host-only activation completes synchronously, while a Client-bearing activation returns `awaiting-approval` or `starting` without waiting for the final browser outcome.
+- A single check authorizes only the current Package, and a double check authorizes future versions of the same Plugin. Authorization survives technical failure, while rejection executes neither half.
+- The Host activates first and the Client then fetches source for the exact Run. A Client-bearing Package does not commit current before Client success, and current/next permit retry and rollback after failure.
+- One Plugin has at most one physical Run at a time. Stop tears down both halves while retaining definitions and pointers; undefine deletes every Package, authorization, and state.
+- The current page distinguishes “Ready,” “Client ready to activate,” and “Running,” and a pending-approval row shows only approval actions.
+- `tool.view.cordis` self binds Plugin + Package. The newest Run card for a Package exclusively owns its business UI, while old cards and deleted Plugins have explicit fallback states.
+- Host and Client Guards reject imports, JSX, undeclared Services, and unavailable globals. Services, timers, Slots, styles, Tools, handlers, and theme overrides are torn down with the Run.
+- Package-private RPC permits only lossless JSON from Client to Host and rejects a stale `pluginRunId`.
+- Inspect list returns Host and Client manifests together. Query calls only explicit read-only methods, and a Client query waits for the first schema-valid successful result or cancellation.
+- Service/Event Catalogs are generated per Host/Client and apply allowlists. `@deprecated` APIs, Runner-owned Services, and `cordis/*` control Events are hidden from the model; Slot query merges static props with the live subtree.
+- `cordis_inspect_self` returns layered Plugin lists, Package summaries, and exact source/diagnostics. `@pluginId` does not inject source and keeps updates in the same Plugin.
+- Asynchronous technical failures, Host handlers, Client Guards, and React rendering errors preserve message/stack and steer the owning Agent; user panel actions only inject context into the next step.
+- The System Prompt, Skill, Tool descriptions, and Provider/Catalog layers follow this Note. The Prompt remains sufficient to generate a minimally correct plugin if the Skill is unavailable.
+- Relevant workspaces pass `pnpm run build`; implementation adds Host/Client lifecycle, versioning, approval, Inspect, Guard, Tool-card, and real-application snapshot coverage.
+
+## Risks
+
+- **A process restart loses all dynamic objects.** Historical Tool cards remain, but the Registry is not restored; the user must define again.
+- **Multi-page state is not strongly consistent.** The first valid Client success may commit current while Client loading and rendering state still differs across pages. This version does not introduce connection identity, quorum, or page aggregation.
+- **Client Inspect may remain pending indefinitely.** The Host stores the latest manifest, but without a page successfully executing the Provider it cannot present stale data as a live result. If every page fails, the request waits until cancellation.
+- **Cross-version authorization expands trust.** A double check permits future Packages of the same Plugin without further approval. The UI must clearly distinguish per-Package and cross-version authorization.
+- **A failed update can leave current pointing to an old version that is not running.** Current identifies the last successful version, not the physical Run. UI, Inspect, and prompts must show active, current, and next together.
+- **Restricted contexts are not security sandboxes.** Host Services, files, commands, network access, and Client UI are real capabilities. Allowlists and approval reduce misuse but do not isolate malicious code.
+- **Catalogs, Guards, and source can drift.** Generators, allowlists, and owner JSDoc must be maintained together. Guard hiding rules must not create a second signature.
+- **Builtins require manual declarations.** React, harness, host, styles, and Context methods have no unified scannable source, so injection implementations and Provider definitions must share one maintenance location.
+- **Provider output schemas currently permit broad JSON.** The first version prioritizes Provider ownership, input validation, and Host/Client routing; output schemas can become narrower later.
+- **Host and Client Guards are parallel implementations.** Their available environments and Cordis type interfaces differ, so they remain separate. A shared specification should be extracted only if it removes code without obscuring security policy.

+ 270 - 0
.agents/notes/proposed/architecture/2026-08-08-cordis-web-dynamic-packages.zh.md

@@ -0,0 +1,270 @@
+# Agent Note: Cordis Host/Client 动态插件运行体系
+
+Status: proposed
+
+[English](2026-08-08-cordis-web-dynamic-packages.md) | 中文
+
+## Problem
+
+模型需要在不修改仓库源码、不重新构建应用、不刷新浏览器的前提下,临时扩展当前 DSH 进程。扩展既可能运行在 Host 的 Node.js 进程,也可能运行在 Client 浏览器页面,还可能由 Host 取数、Client 展示,共同组成一个插件。
+
+这项能力不能只是“执行一段代码”。模型需要在写代码前发现两端允许使用的 Service、Event、Builtin、Slot 和主题 token;用户需要先预览代码,再决定是否允许 Client 代码进入页面;同一个插件需要追加不可变版本、失败后重试或回退;运行后的异步错误需要回到模型,而不是只留在服务端日志或浏览器控制台。
+
+如果把定义、审批、运行、版本切换、能力发现和 UI 状态塞进一个动作,会产生无法稳定解释的状态:定义成功是否等于运行成功,升级失败后哪个版本仍是成功版本,页面没有响应时 Tool 应等待多久,同一个 Package 多次运行时哪张历史卡片承载业务 UI,以及 Client 页面局部装载状态是否能代表 Host 的进程级状态。
+
+## Proposal
+
+### 核心原则
+
+- Host 保存 Plugin、Package、Run、审批和版本指针的唯一进程级权威状态。
+- Client 只保存当前页面的审批交互、装载结果、Slot 贡献、业务视图和页面局部错误。
+- Define 只创建不可变代码版本;Run 只激活一个已定义版本。
+- 版本切换只有在目标 Package 完成要求的 Host/Client 激活后才提交 `currentPackageId`。
+- 模型写代码前通过 Inspect Provider 查询能力;Inspect 结果只辅助编码,不作为插件运行时业务数据。
+- Host 与 Client 动态代码都使用受限的 plain JavaScript 上下文,并把可撤销副作用挂到 Cordis 生命周期。
+- Client 代码进入页面前需要用户授权;授权范围可以是单个 Package,也可以是同一 Plugin 的后续版本。
+- Tool 调用不等待当前轮结束后才可能发生的审批或浏览器操作;异步结局通过状态存储和模型 steering 反馈。
+
+### 包职责与依赖方向
+
+动态运行体系由 `packages/self-modification/` 下四个包组成:
+
+| 包 | npm 包名 | 职责 |
+| --- | --- | --- |
+| `tool-cordis` | `@deepseek-ai/dsh-tool-cordis` | 注册 System Prompt、七个模型 Tool、Host Inspect Provider、`@pluginId` 上下文注入和 Tool 展示元数据 |
+| `cordis-host-runner` | `@deepseek-ai/dsh-cordis-host-runner` | 保存权威 Registry,分配 ID,执行 Host 代码,管理版本、审批、Run、私有 handler、Inspect 路由和模型反馈 |
+| `cordis-client-runner` | `@deepseek-ai/dsh-cordis-client-runner` | 在浏览器同步 Inspect manifest,编排审批后的 Host→Client 激活,求值 Client 代码,管理 Guard、Loader/Fiber、timer、样式和 teardown |
+| `ui-cordis` | `@deepseek-ai/dsh-client-ui-cordis` | 展示 Define/Run Tool 卡片、全局 Cordis 面板、审批控件、版本选择、运行状态和 Package 自定义业务视图 |
+
+`tool-cordis` 只依赖 Host Runner 的进程内服务,不导入 Client 实现。`ui-cordis` 只消费 Client Runner face 和 Client-safe wire 类型,不导入 Host 实现。Host 与 Client 的运行控制通过已有生成 Remote 面和转发事件连接,网关不拥有动态 Plugin 的领域逻辑。
+
+### 领域对象
+
+#### Plugin
+
+Plugin 是可持续修改的动态插件实例,由品牌类型 `CordisDynamicPluginId` 标识,例如 `clock-1`。新建 Plugin 时,模型只提交 3 至 6 位小写英文语义前缀;Host 添加进程内唯一数字后缀。完整 `pluginId` 不能由模型指定。
+
+Plugin 属于定义它的 Session。模型 Tool 只能读取和操作当前 Session 的 Plugin;全局 Client 面板可以列出所有 Session 的 Plugin,但每个动作仍使用该行携带的 owner Session 执行。
+
+#### Package
+
+Package 是 Plugin 下的不可变代码版本,由 `CordisDynamicPackageId` 标识,例如 `pkg-2`。它包含名称、用途、可选 Host 代码和可选 Client 代码,且至少包含一侧。每次 `cordis_define` 都创建新 Package;已有 Package 不允许原地修改。
+
+同一个 Plugin 可以拥有多个 Package,但同一时刻最多只有一个物理 Run。Package 是否含 Host 或 Client 半只决定激活步骤,不改变版本身份。
+
+#### Plugin Run
+
+Plugin Run 是一次具体激活尝试,由 `CordisDynamicPluginRunId` 标识,例如 `run-3`。每次新的激活尝试都会分配新 ID,包括审批后失败、重试同一 Package 和版本更新。`pluginRunId` 把审批、Host 激活、Client 装载、私有 RPC、Tool 卡片和错误关联到同一次尝试。
+
+Host 分开保存当前物理 Run 与 `latestRun`。物理 Run 表示此刻仍可调用和撤销的激活;`latestRun` 表示最近一次尝试的审批、阶段、两侧状态和诊断。一次失败可以没有存活的物理 Run,但仍留下可查询的 attempt。
+
+#### 版本指针
+
+- `currentPackageId` 是最近一次完成要求的激活流程的 Package。停止插件、开始更新或更新失败都不清除它。
+- `nextPackageId` 是正在等待审批、正在激活、等待 Client、或最近失败的目标 Package。目标成功提交为 current 后清除。
+
+Host-only Package 在 Host 成功建立 Fiber 后提交 current。包含 Client 的 Package 在 Host 激活成功且至少一个 Client 成功建立对应装载后提交 current。因硬依赖缺失而被 Cordis park 为 waiting 的 Fiber仍是成功建立的生命周期对象,不等同于解析或 `apply` 失败。
+
+更新目标失败时不自动重启旧物理 Run。旧 `currentPackageId` 继续表示最后成功版本,失败目标保留为 `nextPackageId`。用户或模型可以重试 next,也可以以 `mode: "run"` 重新激活 current 完成回退。
+
+### Host 权威状态与持久性
+
+`DynamicCordisRunnerService` 及其内部 Registry 是当前 DSH 进程内的唯一权威,保存:
+
+- Plugin 的 Session 归属和不可变 Package 集合;
+- `currentPackageId`、`nextPackageId`、物理 Run 和 `latestRun`;
+- 单 Package 授权与 Plugin 跨版本授权;
+- 待处理的 Client 激活请求;
+- Host Fiber、Package 私有 handler、等待中的 Service 和最近诊断;
+- Host 与 Client Inspect Registry 的目录和查询路由。
+
+这些对象不写入配置或磁盘,也不在进程重启后恢复。Session Log 可以保留 Tool 调用、结果和卡片所需元数据,但不会重放动态代码来恢复 Registry。进程重启后历史卡片仍可作为对话记录存在,原 `pluginId` 和 `packageId` 不再可运行。
+
+运行态不作为可恢复状态写入 Session projection。页面刷新或新页面打开不会自动恢复 Client 半;自动恢复会重新引入连接身份、启动期 baseline 和跨页面一致性协议,不属于当前设计。
+
+### Define、Run 与版本切换
+
+`cordis_define` 有两种模式:新建 Plugin 时提交 `idPrefix`;修改现有 Plugin 时提交精确 `pluginId`。代码统一为 `code: { host?, client? }`。Define 只校验参数和 plain JavaScript 语法,记录不可变源码并返回最终 ID。它不执行 `apply`、不产生审批、不改变版本指针,也不隐式运行。
+
+不提供独立 `cordis_update`。`cordis_run` 通过 `mode` 表达激活意图:
+
+| 版本关系 | `mode` |
+| --- | --- |
+| 尚无 `currentPackageId` | `run` |
+| 目标等于 current,包括重启、重试或回退 | `run` |
+| 目标与已有 current 不同 | `update` |
+| 更新失败后重试 `nextPackageId` | `update` |
+
+Run 先验证 Plugin/Package 归属、版本关系和是否已有转换在进行,再创建 `pluginRunId`、写入 `latestRun` 和 `nextPackageId`。
+
+Host-only Package 在 Tool 调用内完成 Host 激活,并同步返回 `running` 或失败。包含 Client 的 Package不在 Tool 调用内等待浏览器终局:未授权时登记审批并返回 `awaiting-approval`;已授权时登记自动 Client 激活并返回 `starting`。这两种返回都表示请求已建立,不表示完整激活成功。
+
+目标真正开始激活时,Host 先停止旧物理 Run,再执行目标 Host 半。Host 成功后才允许 Client 获取精确 `pluginRunId` 对应的源码并装载。Client 成功后 Host 提交版本指针;任何阶段失败都记录到该 attempt,不把旧版本重新启动伪装成目标成功。
+
+`cordis_stop` 撤销当前 Host/Client Run 及待审批请求,但保留 Plugin、Package、授权和版本指针。`cordis_undefine` 先停止,再删除 Plugin、Package、授权和版本指针;删除后历史卡片只显示“插件已移除”。
+
+### Client 审批与授权
+
+包含 Client 代码的 Package 在第一次激活前需要用户授权,因为它将在用户页面中运行模型生成的代码。审批面板提供三个动作:
+
+- 单勾允许当前 Package;同一 Package 后续重跑不再审批,新 Package 仍需审批。
+- 双勾允许当前 Plugin 的后续版本;新 Package、更新、重试和回退不再逐版本审批。
+- 拒绝结束当前请求,不执行 Host 或 Client 代码;模型不得在用户没有新要求时立即重复申请。
+
+授权在用户允许时写入 Host Registry,即使随后发生技术失败也保留。面板直接运行 Package 时,用户点击本身授权该 Package。
+
+待审批行只显示单次允许、跨版本允许和拒绝,不同时提供运行、停止或删除。发现新审批时面板自动展开;自动展开失败或被收起时,固定入口和行状态仍显示待审批数量与状态。
+
+### Client 激活编排
+
+Host 通过 `cordis/request-run` 发送 Client 激活请求。请求只包含请求身份、Session、Plugin、Package、mode、名称、用途和是否需要审批,不广播源码。
+
+获得授权的页面按固定顺序执行:
+
+1. 调用 `runHostHalf`,启动目标 Host 半或绑定同一次 attempt 已启动的 Host Run。
+2. Host 成功后,以 `pluginId + pluginRunId` 调用 `getClientCode`,只取得当前精确 Run 的 Client 源码。
+3. Client Runner 在页面求值插件,建立 Loader entry/Fiber,安装 Guard、样式、Slot 和页面局部状态。
+4. 页面调用 `resolveRequestRun` 或 `settleUserRun` 回报成功、waiting 或失败。
+5. Host 接受仍有效的精确 Run 回报,提交 current 或保存诊断,并广播请求结束,其他页面清理活动。
+
+Host 激活先于 Client,避免 Client 在所需 Host handler 尚未存在时启动。只有本次请求实际创建的 Host Run 才能因本页 Client 失败而撤销;只是绑定既有 Run 的页面没有其所有权。
+
+Client Orchestrator 按 `pluginId` 保存待审批和正在编排的活动,同一个 Plugin 不并发执行两次页面激活。Host inventory 可重建遗漏的待审批项和无需审批的自动激活请求。
+
+Client 装载状态是页面局部事实。Host active 不代表当前页面已装载 Client 半。UI 使用三种主要状态:无物理 Run为灰色“待激活”,Host 已运行但当前页面 Client 未成功装载为黄色“Client 待激活”,当前页面两侧可用为绿色“运行中”。审批中和失败作为额外状态显示。
+
+当前版本不建立 per-connection 身份或多页面法定人数。第一个仍有效的 Client 成功回报可以提交进程级 current;其他页面是否装载由各自页面 store 表示。
+
+### Package 私有 Client→Host 通信
+
+动态 Package 通过私有 JSON 通道从 Client 调用 Host:Host 使用 `harness.handle(method, handler)` 注册当前 Run 的方法,Client 使用 `host.call(method, args)` 调用。每次调用关联 `pluginId + pluginRunId`,Host 拒绝已停止或过期 Run。参数和返回值必须是无损 JSON,不允许函数、React 元素、Context、Service 实例或类对象。
+
+该通道只服务同一 Package 的 Client→Host 调用,不使用公开 Remote Service 或动态代码中的 `ctx.remote`。公开 Remote 面只承载 Runner 自己的控制协议,不向动态 Package 暴露。
+
+### 动态代码、Guard 与生命周期
+
+Host 和 Client 都只执行 plain JavaScript 函数体,不经过 TypeScript、JSX 或 bundler 转译。Host 运行在 `node:vm`,Client 在受限闭包中求值。两端上下文用于减少误用并提供教学错误,不是恶意代码安全边界。
+
+模型默认通过 `ctx.get('serviceName')` 读取可选 Service 并判断 `undefined`。只有 Service 是硬依赖、缺失时 Package 必须 waiting 并在 Service 出现后重新激活时,才在插件对象声明 `inject`。直接访问 `ctx.serviceName` 只在同一插件声明对应 inject 时允许。
+
+Host 与 Client 的 `timer` 都是同名 Cordis Service,使用一致接口,不是全局 Builtin。需要 timer 的插件必须声明 `inject: ['timer']`;React effect 中创建的 timer 把 disposer 作为 cleanup 返回。
+
+所有注册和可撤销副作用由当前 Fiber 拥有。Event listener、Service、Tool、handler、timer、Slot、样式和主题覆盖通过 `ctx.effect()`、`ctx.on()` 或返回 disposer 的官方 API 注册。停止、更新、失败回滚或 undefine 时撤销两端贡献。Theme override 必须按 source 分层并返回 disposer,使卸载后恢复此前主题值。
+
+宿主、DSH、Cordis 及其 Service、Event payload、Slot props、Session/Conversation Snapshot、Tool 状态和其他运行时对象是内部 live data。动态代码不得对这些对象或其子对象执行 `JSON.stringify`、`structuredClone`、递归枚举、全量复制或整体展示;只能读取当前任务所需叶子字段,构造不含宿主引用的最小自有数据。
+
+### Inspect Provider 与 Catalog
+
+能力发现分为三个 Tool:`cordis_inspect_list` 列 Host/Client Provider manifest;`cordis_inspect_query` 执行指定平台的显式只读查询;`cordis_inspect_self` 查询当前 Session 的 Plugin、Package、源码、版本指针和运行诊断。
+
+Host 和 Client 各自拥有 `CordisInspectRegistry`。Provider 注册平台内唯一 ID、说明、method、输入 schema 和输出 schema。Provider method 是显式白名单查询,不是任意 Service 方法透传;Registry 不维护分层 target,也不自动把业务 Service 方法变成可执行 Inspect method。
+
+首批 Provider 为:
+
+| Platform | Provider.method | 数据来源 |
+| --- | --- | --- |
+| Host / Client | `Service.listService` | 各平台 Service 静态 Catalog |
+| Host / Client | `Event.listEvents` | 各平台 Event 静态 Catalog |
+| Host / Client | `Builtin.listBuiltins` | evaluator/Guard 附近的手工定义 |
+| Host | `Tool.listTools` | 当前 Agent 真正可见的 Tool Registry |
+| Client | `Slots.listSubTree` | Slot 静态 Catalog与页面 live subtree/occupants |
+| Client | `Theme.listTokens` | ThemeService 的只读 inspect export |
+
+Client Registry 变化后向 Host 同步完整 manifest,不按 Session 保存重复目录。Host query 本地执行;Client query 由 Host 广播 request ID,页面调用本地 Provider 后回送。Host 只接受第一个通过输出 schema 校验的成功结果;失败页面不抢占请求。没有页面成功回答时 Tool 保持 pending,直到后续成功或 Tool call 取消。
+
+Inspect 数据只用于写代码前确认能力、签名、类型和挂载协议。插件运行时需要业务数据时必须调用实际 Service 或监听实际 Event,不能缓存、展示或依赖 Inspect/Catalog 返回值。
+
+`CordisCatalogProjector` 使用 TypeRT 分别生成 Host/Client Service 与 Event Catalog;Slot AST 生成器扫描 `SlotMap`、注册选项、standard props、owner props 和引用类型;Slots Provider 查询时合并静态 Catalog 与 live tree。Theme token 由 ThemeService 导出,Builtin 在 evaluator/Guard 附近手工维护,Tool schema 来自 Registry。
+
+Catalog 扫描真实源码签名,再应用 model-visible 白名单。白名单可以隐藏 Service、成员、`@deprecated` API、Runner 自身服务和 `cordis/*` 控制 Event,但不能改写剩余 API 的方法名、参数和返回类型。Guard 可以拒绝参数、固定来源或屏蔽成员,但必须尊重源码签名。
+
+模型可见 owner JSDoc 只要求完整 description、每个参数的 `@param`、非 void 返回的 `@returns`、Event 的 `@mode`,以及 Slot/props 字段说明。调用推荐、反例和跨能力选择放入 Skill,不在 Catalog 增加重复 example 字段。
+
+### 模型指导分层
+
+模型指导分为四层:
+
+- System Prompt 保存稳定运行模型、两端限制、生命周期、审批、版本指针、最低代码规范和七个 Tool 的使用地图。Skill 不可用时它仍须支持最低限度正确实现。
+- `cordis-plugin-development` Skill 保存需求导航、能力组合、推荐和反例,不复制完整 schema。
+- 每个 Tool description 只说明该动作的前置条件、参数语义、同步/异步结果和下一步。
+- Provider/Catalog 返回当前精确名称、签名、参数、Slot props、token 和运行时查询结果。
+
+System Prompt 要求先加载 Skill,再 list/query,之后 define/run。Skill 中 React 示例必须注册到 Slot,不能从 `apply()` 直接返回 React Element;示例使用 `React.createElement`、正确 `ctx.get()`/`inject`、可逆 effect 和最小 JSON RPC。
+
+### `@pluginId` 与 Tool UI
+
+输入系统为当前 Session 注册 `@pluginId` mention。选择后只注入 Plugin 身份、默认基准 Package、版本指针、活动 Run 和最近状态,不注入源码。默认基准依次选择 next、current、最近定义的 Package。模型必须先用 `cordis_inspect_self` 读取源码,再以 existing 模式追加 Package;引用失效时不能静默创建替代 Plugin。
+
+`cordis_define` 卡片以 Host/Client 两个子页签展示代码。`cordis_run` 卡片由 `pluginRunId` 关联精确 attempt,并读取 Client store 显示待审批、Client 待激活、运行中、失败、已被后续 Run 替代或 Plugin 已移除。
+
+Package 可以向 `tool.view.cordis` 注册 `key: "self"`。运行时把 self 绑定为 `pluginId + packageId`;业务 Slot key 不含 `pluginRunId`,但 owner props 仍提供精确 Run 身份。同一 Package 最新 Run 卡片承载业务 UI,更早卡片显示已有更新运行。卡片通过 store 响应变化,不扫描后续 Session Log,也不互相通知。
+
+全局 Cordis 面板使用一个固定入口,按当前会话和其他会话分组。面板标题和收起操作固定,只有列表滚动。普通行可选择 Package并运行、停止或删除;失败更新可重试 next 或选择 current 回退;待审批行只提供两个允许动作和拒绝。
+
+### 错误与模型反馈
+
+跨 Host/Client 的技术错误保留原始 `message`,并在错误对象提供时保留 `stack`。结构化诊断包含 `pluginId`、`packageId`、`pluginRunId` 和阶段:approval、host-load、host-apply、client-load、client-apply 或 client-render。
+
+Host/Client Guard、Host 求值与 handler、Client 求值与 apply、Slot `onEntryError` 和 React ErrorBoundary 都把错误回到 owning Agent。Client 控制台同时以 `console.error` 打印原始 error 对象。渲染错误属于精确 Run,不污染不可变 Package。
+
+模型发起的异步 Run 在成功、拒绝或技术失败后使用 `agent.steer` 唤醒 owning Agent。技术失败要求读取诊断、在同一 Plugin 修正并自主重试;用户拒绝则禁止自动重复申请。用户在面板手动运行、停止或移除通过 context injection 告知下一 step,但不主动唤醒模型。
+
+## Alternatives considered
+
+**Define 与 Run 合并。** 这会失去“已定义但未运行”的可预览状态,把语法错误、审批、运行错误和重试混成一个动作,因此拆为不可变 Define 和独立 Run。
+
+**Package ID 同时作为 Plugin ID。** 单层 ID 无法表达稳定实例下追加不可变版本,更新只能 stop、undefine、重新 define,历史卡片和 `@` 引用也无法保持同一对象,因此采用 Plugin、Package、Run 三层身份。
+
+**提供独立 `cordis_update`。** Update 的装载、审批、UI、诊断和 Run 相同,独立 Tool 只复制协议,因此合并到 `cordis_run mode:"update"`。
+
+**更新失败后自动恢复旧物理 Run。** 自动恢复会把“目标失败”和“旧版本重新成功”混成一个结果。当前设计保留旧 current 指针但不自动重启,让用户明确选择重试 next 或 run current。
+
+**让 `cordis_run` 阻塞到用户审批和 Client 终局。** 审批或页面操作可能只能在当前模型轮结束后发生,阻塞会形成死锁,并在无页面时无限占用 Tool。当前设计立即返回,通过 store、Inspect 和 steering 报告终局。
+
+**Host 广播源码并用超时等待 Client ack。** 广播会在授权前把代码发给所有页面;超时无法区分没有页面、页面慢和用户未操作;Host 还要维护补偿式回滚。当前协议只广播元数据,由获准页面按精确 Run 拉取源码。
+
+**页面启动时自动恢复所有 Host active Package。** 这要求连接身份、启动期 baseline 和跨页面一致性。当前设计接受页面局部 Client 状态,用户可在面板重新装载。
+
+**通过公开 Remote Service 或 `ctx.remote` 连接 Package 两半。** 这会把动态 Package 暴露到产品级 RPC 面。Package 私有 `harness.handle`/`host.call` 足以承载 Client→Host JSON 调用,并能按 `pluginRunId` 拒绝陈旧请求。
+
+**把所有 Service 方法自动暴露成 Inspect query。** 这会把能力发现变成业务调用代理,绕过插件审批和生命周期。Provider 只暴露策展的只读查询,Service Catalog 只描述业务方法签名。
+
+**把完整 API 写进 System Prompt 或 Skill。** 固化文本会漂移并占用上下文。System Prompt 保留稳定规则,Skill 负责需求导航,精确签名和运行时目录由 Provider/Catalog 返回。
+
+**要求 Slot owner 在运行时注册 props schema。** Slot props 已存在于 TypeScript 类型和 JSDoc 中,重复注册会制造第二份权威。当前设计用 Slot AST Catalog 提取静态协议,只在查询时合并 live tree。
+
+**把运行态写入 Session Log 并在 replay 恢复。** 动态代码和 Fiber 是进程局部对象,恢复要求重新执行历史代码并重新解释审批。Session 只保留模型可见记录,Registry 和页面 Run 不恢复。
+
+**让历史 Run 卡片扫描后续 Session Log。** 这会让 Tool view 依赖全量日志顺序和后续消息结构。页面 card index/store 已能按 Package 告知旧卡片被替代或 Plugin 被删除。
+
+## Acceptance criteria
+
+- 新 Plugin 只能由 3 至 6 位小写英文前缀创建,最终 Plugin、Package 和 Run ID 由 Host 分配并使用品牌类型。
+- `cordis_define` 只做参数和 plain JavaScript 语法检查,返回不可变 Package;同一 Plugin 可以追加版本,旧源码保持可 inspect。
+- `cordis_run` 严格校验 run/update;Host-only 同步完成,Client-bearing 返回 `awaiting-approval` 或 `starting`,不等待页面终局。
+- 单勾只授权当前 Package,双勾授权同一 Plugin 后续版本;授权在技术失败后仍保留,拒绝不执行两侧代码。
+- Host 先激活,Client 后取精确 Run 源码;Client 成功前不提交 Client-bearing Package 的 current,失败后 current/next 可用于重试和回退。
+- 一个 Plugin 同时最多一个物理 Run;stop 撤销两端贡献但保留定义和指针,undefine 删除全部 Package、授权和状态。
+- 当前页面能区分“待激活”“Client 待激活”和“运行中”,待审批时只显示审批动作。
+- `tool.view.cordis` 的 self 绑定 Plugin + Package;同 Package 最新 Run 卡片独占业务 UI,旧卡片和已删除 Plugin 有明确退化状态。
+- Host/Client Guard 拒绝 import、JSX、未声明 Service 和不可用全局;Service、timer、Slot、样式、Tool、handler 和主题覆盖随 Run teardown。
+- Package 私有 RPC 只允许 Client→Host 无损 JSON,并拒绝陈旧 `pluginRunId`。
+- Inspect list 一次返回 Host/Client manifest;query 只调用显式只读方法,Client 查询等待首个 schema-valid 成功结果或取消。
+- Service/Event Catalog 分 Host/Client 生成并应用白名单,`@deprecated` API、Runner 自身服务和 `cordis/*` 控制 Event 不向模型暴露;Slot query 合并静态 props 与 live subtree。
+- `cordis_inspect_self` 分层返回列表、Package 摘要和精确源码/诊断;`@pluginId` 不直接注入源码且更新留在同一 Plugin。
+- 异步技术失败、Host handler、Client Guard 和 React 渲染错误保留 message/stack 并 steering owning Agent;用户面板操作只注入下一 step context。
+- System Prompt、Skill、Tool description 和 Provider/Catalog 按本 Note 分层,Skill 不可用时 Prompt 仍足以生成最低限度正确的插件。
+- 相关工作区 `pnpm run build` 通过;实现阶段补齐 Host/Client lifecycle、版本、审批、Inspect、Guard、Tool 卡片与真实应用快照覆盖。
+
+## Risks
+
+- **进程重启丢失全部动态对象。** 历史 Tool 卡片仍在,但 Registry 不恢复;用户必须重新 define。
+- **多页面状态不是强一致系统。** 第一个有效 Client 成功结果可以提交 current,各页面的 Client 装载和渲染状态仍可能不同;当前不引入连接身份、法定人数或页面聚合。
+- **Client Inspect 可能长期 pending。** Host 保存最近 manifest,但没有页面成功执行 Provider 时不能用旧数据伪装 live 结果;多个页面都失败时请求等待到取消。
+- **跨版本授权扩大信任范围。** 双勾允许同一 Plugin 后续 Package 无需再次审批;UI 必须清楚区分单次和跨版本授权。
+- **失败更新可能留下 current 指向旧版本但旧版本未运行。** current 表示最后成功版本,不表示当前物理 Run;UI、Inspect 和提示必须同时展示 active、current 和 next。
+- **受限上下文不是安全沙箱。** Host Service、文件、命令、网络和 Client UI 都是真实能力;白名单与审批降低误用,不隔离恶意代码。
+- **Catalog、Guard 和源码可能漂移。** 生成器、白名单和 owner JSDoc 必须共同维护;Guard 的隐藏策略不能产生另一套签名。
+- **Builtin 依赖手工声明。** React、harness、host、styles 和 Context 方法没有统一可扫描入口,注入实现与 Provider 定义必须放在同一维护位置。
+- **Provider 输出 schema 当前允许较宽的 JSON。** 首版优先完成 Provider 所有权、输入校验和 Host/Client 路由;更窄的输出 schema 后续再收紧。
+- **Host 与 Client Guard 存在平行实现。** 两侧开放环境和 Cordis 类型面不同,当前保留各自实现;公共规格只有在能减少代码且不隐藏安全策略时再提取。

+ 2 - 2
.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write .agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md
-2026-08-11-repository-naming-contract-and-rename-ledger.md: 440ab360e0bd34071de244120aca75116a56ff30
-2026-08-11-repository-naming-contract-and-rename-ledger.zh.md: e5f8d37bdee790b374ecf18be41c04ad8588da46
+2026-08-11-repository-naming-contract-and-rename-ledger.md: ad5a2061c40011b3f8c32ecbb62a0b545f82f9f6
+2026-08-11-repository-naming-contract-and-rename-ledger.zh.md: 8f1b3505f0cc16a6e3e6429b5924cabda231f00f

+ 1 - 1
.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.md

@@ -208,7 +208,7 @@ Keep `/compact`, the command package, and the rejected decision to preserve sepa
 | `AgentDefaultModelService` | `AgentDefaultModelConfig` | The object stores one default model selection. It does not run a service or general registry. Keep its package, key, settings namespace, and type. |
 | `SessionReferenceService`, `ctx.sessionReferences` | `SessionReferenceResolver`, `ctx.sessionReferenceResolver` | It resolves one session reference from a URI or input. It does not own a reference collection. |
 | `SessionQueryService`, `SessionQuerySqlite` | `SessionQueryEngine`, `SqliteSessionQueryEngine` | The classes execute a query model and its SQLite implementation. Keep package names, key, and tool. |
-| `@deepseek-ai/dsh-session-export`, `session-export/`, Loader id `session-export`, `ctx.sessionExport` | `@deepseek-ai/dsh-session-log-download`, `session-log-download/`, Loader id `session-log-download`, `ctx.sessionLogDownload` | This package does not implement general Session export. It controls the Web download of one Host-streamed Session-log ZIP. The subject and browser side effect must be in its name. |
+| `@deepseek-ai/dsh-session-export`, `session-export/`, Loader id `session-export`, `ctx.sessionExport` | `@deepseek-ai/dsh-session-log-export`, `session-log-export/`, Loader id `session-log-download`, `ctx.sessionLogDownload` | The npm package names the Session-log export because npm rejects `download` in package names. The Loader id and browser API retain `download` because they describe the browser side effect. |
 | `SessionExportDownloadController`, other `SessionExport*` browser types, `useSessionExport`, `SessionExportHeader` | `SessionLogDownloadController`, corresponding `SessionLogDownload*` types, `useSessionLogDownload`, `SessionLogDownloadHeaderAction` | The controller owns preflight, duplicate-request collapse, modal state, and browser save. `ExportDownload` repeats the action, and the component contributes one Header action rather than the Header. |
 | `CommandService` in the host command package | `CommandRuntime` | The object registers and executes host commands across live calls. Keep its package, key, types, and events. |
 | `TokenMeterService` | `TokenMeter` | The object measures token use. `Service` adds no scope. |

+ 1 - 1
.agents/notes/proposed/architecture/2026-08-11-repository-naming-contract-and-rename-ledger.zh.md

@@ -208,7 +208,7 @@ PascalCase 标识符中的首字母缩略词使用首字母大写格式:`Ui`
 | `AgentDefaultModelService` | `AgentDefaultModelConfig` | 该对象存储一项默认模型选择。它不运行服务,也不是通用注册表。保留其包、键、设置命名空间和类型。 |
 | `SessionReferenceService`, `ctx.sessionReferences` | `SessionReferenceResolver`, `ctx.sessionReferenceResolver` | 它从 URI 或输入解析一个会话引用,并不拥有引用集合。 |
 | `SessionQueryService`, `SessionQuerySqlite` | `SessionQueryEngine`, `SqliteSessionQueryEngine` | 这些类执行查询模型及其 SQLite 实现。保留包名、键和工具。 |
-| `@deepseek-ai/dsh-session-export`, `session-export/`, Loader id `session-export`, `ctx.sessionExport` | `@deepseek-ai/dsh-session-log-download`, `session-log-download/`, Loader id `session-log-download`, `ctx.sessionLogDownload` | 该包不实现通用 Session 导出。它控制 Web 下载一个由 Host 流式输出的 Session 日志 ZIP。名称必须说明对象和浏览器副作用。 |
+| `@deepseek-ai/dsh-session-export`, `session-export/`, Loader id `session-export`, `ctx.sessionExport` | `@deepseek-ai/dsh-session-log-export`, `session-log-export/`, Loader id `session-log-download`, `ctx.sessionLogDownload` | npm 包名使用 Session 日志导出语义,因为 npm 禁止包名包含 `download`。Loader id 与浏览器 API 保留 `download`,因为它们描述浏览器副作用。 |
 | `SessionExportDownloadController`, 其他 `SessionExport*` 浏览器类型、`useSessionExport`、`SessionExportHeader` | `SessionLogDownloadController`, 对应的 `SessionLogDownload*` 类型、`useSessionLogDownload`、`SessionLogDownloadHeaderAction` | 该 controller 拥有预检、重复请求合并、弹窗状态和浏览器保存。`ExportDownload` 重复表达同一动作,该组件贡献的是一个 Header action,不是整个 Header。 |
 | 宿主命令包中的 `CommandService` | `CommandRuntime` | 该对象跨实时调用注册并执行宿主命令。保留其包、键、类型和事件。 |
 | `TokenMeterService` | `TokenMeter` | 该对象测量 token 用量。`Service` 没有补充作用域信息。 |

+ 420 - 0
apps/cli/config/agent-presets/cordis/skills/cordis-plugin-development/SKILL.md

@@ -0,0 +1,420 @@
+---
+name: cordis-plugin-development
+description: Create, modify, debug, or extend dynamic Cordis Plugins, including Host Services and Events, Client Slot and theme UI, Package-private Client-to-Host calls, dynamic Tools, version updates, approval failures, and runtime diagnostics. Use this Skill to route a user request to the correct platform and Inspect Provider, then define, run, repair, or roll back the Plugin.
+---
+
+# Develop Dynamic Cordis Plugins
+
+First determine whether a capability belongs on Host or Client, then query the real interface before writing code. Never infer a complete API from a Service name, Event payload, Slot props, theme token, or example.
+
+## Standard workflow
+
+1. Call `cordis_inspect_list` to obtain the Providers, methods, and schemas currently registered on Host and Client.
+2. Select the smallest set of `cordis_inspect_query` calls needed to read the exact Services, Events, Builtins, Slots, Theme tokens, or Tools that the implementation will use.
+3. For a new Plugin, design its first Package. To modify an existing Plugin, first use `cordis_inspect_self(pluginId, packageId)` to read the base source and diagnostics.
+4. Write plain JavaScript in `code.host`, `code.client`, or both, then call `cordis_define`.
+5. Call `cordis_run` with the final `pluginId` and `packageId` returned by define.
+6. Handle approval, waiting, Client loading, and render failures from the Run card, steering messages, or `cordis_inspect_self`.
+7. Use `cordis_stop` to disable the Plugin temporarily. Use `cordis_undefine` only when it is no longer needed.
+
+Do not wait in the same turn for user approval or asynchronous browser results. After `cordis_run` returns `awaiting-approval` or `starting`, end the current Tool flow and wait for the system to report the final outcome through state updates and steering.
+
+## Tool usage guidance
+
+| Tool | Use it when | Do not |
+| --- | --- | --- |
+| `cordis_inspect_list` | Discover current Host/Client Providers and method schemas in one call; refresh after the runtime capability directory changes | Hard-code Provider names and skip list; treat a manifest as business data |
+| `cordis_inspect_query` | Confirm exact Service methods, Event modes, Builtins, Slots, tokens, or Tool schemas before writing code | Use it instead of calling a real Service from the Plugin; assume a Client query will finish without a responding page |
+| `cordis_inspect_self` | List current Plugins, inspect version pointers, or read exact Package source and runtime diagnostics | Fetch all source just to build a list; use it to modify or start a Plugin |
+| `cordis_define` | Create a Plugin's first version or append an immutable Package to an existing Plugin; let the user preview the code first | Expect define to execute `apply`, request approval, or update current |
+| `cordis_run` | Activate an exact Package; use `run` for first activation, restart, or rollback, and `update` to switch versions | Use `run` to switch versions implicitly; treat pending or starting as success |
+| `cordis_stop` | Pause current effects while preserving Packages, grants, and version pointers for later use | Use stop to mean permanent deletion |
+| `cordis_undefine` | Permanently remove a Plugin and all of its Packages and clear historical business views | Call it while rollback, inspection, or restart is still needed |
+
+## Choose a platform
+
+| Requirement | Preferred platform | Inspect first |
+| --- | --- | --- |
+| Files, commands, processes, or networking | Host | `fs`, `bash`, `subprocess`, `pty`, and `web` in `Service.listService` |
+| Agents, durable Session data, or Host lifecycle | Host | The relevant Service and `Event.listEvents` |
+| Register a dynamic Tool callable in the next model step | Host | `harness` in `Builtin.listBuiltins`, plus `Tool.listTools` |
+| Page theme, layout, or current page state | Client | `Theme.listTokens` and Client `Service.listService` |
+| Conversation Snapshot or session/workspace lists | Client | The target Slot's standard props and owner props |
+| Settings pages, sidebars, input areas, overlays, or Tool cards | Client | `Slots.listSubTree` |
+| Fetch on Host and display on Client | Both | Host Service + `harness.handle`; Client Slot + `host.call` |
+
+Prefer the capability closest to the data owner. If Slot props already provide the Conversation Snapshot, do not fetch it again through Host. If only the Package's own styles need to change, do not override the global theme. If only a small entry point is needed, do not replace an entire product UI region.
+
+## Provider navigation
+
+Select methods from the actual `cordis_inspect_list` result. Common initial methods include:
+
+- `Service.listService`: without `service`, returns every callable Service with its purpose and exact method signatures. Query the selected `service` again for access rules, structured method descriptions/parameters/returns, and only its referenced types.
+- `Event.listEvents`: without `event`, returns every Event with its purpose, dispatch mode, and exact listener signature. Query the selected `event` again for its structured listener contract and only its referenced types; a Waterfall listener must call `next()`.
+- `Builtin.listBuiltins`: returns evaluator-provided symbols and signatures that cannot be obtained through `ctx.get()`.
+- `Slots.listSubTree`: without `root`, returns compact live trees with each Slot's purpose, kind, scope, registration keys, replacement risk, and children. With an exact `root`, it also returns that selected Slot's full contract, props, and current occupants while keeping descendants compact.
+- `Theme.listTokens`: returns theme tokens that may currently be queried and overridden; it does not modify the theme.
+- `Tool.listTools`: returns Tool schemas actually visible to the current Agent, including dynamically registered Tools.
+
+Provider names, methods, and inputs must come from the current list result. The Service/Event Catalog describes which interfaces this version permits; it does not guarantee that a Service is currently mounted. At runtime, use real Services and Events rather than caching or displaying Catalog query results.
+
+## Execution environment
+
+Both `code.host` and `code.client` are plain JavaScript function bodies that return a Cordis Plugin. They are not compiled by TypeScript, JSX, or a bundler.
+
+Do not use:
+
+- `import`, `require`, TypeScript types, `as`, decorators, or JSX;
+- globals not confirmed by `Builtin.listBuiltins`;
+- guessed access to `window`, `document`, `process`, `Buffer`, `fetch`, or native timers.
+
+Client React code must use `React.createElement(...)`.
+
+Correct:
+
+```js
+return {
+  apply(ctx) {
+    const slots = ctx.get('slots')
+    if (slots === undefined) return
+    slots.inject('tool.view.cordis', () => slots.register(
+      { name: 'tool.view.cordis', key: 'self' },
+      () => React.createElement('div', null, 'Hello'),
+    ))
+  },
+}
+```
+
+Incorrect:
+
+```jsx
+return {
+  apply(ctx) {
+    return <div>Hello</div>
+  },
+}
+```
+
+JSX is not the only problem in this example. `apply()` registers lifecycle contributions and cannot return a React Element as the Plugin result. UI must be registered in a queried Slot.
+
+## Access Services
+
+Read optional capabilities with `ctx.get(name)` by default and handle their absence:
+
+```js
+return {
+  apply(ctx) {
+    const service = ctx.get('serviceName')
+    if (service === undefined) return
+    service.someMethod()
+  },
+}
+```
+
+Declare `inject` only when a Service is a hard dependency and the Plugin must enter waiting until Cordis reactivates it after the Service appears:
+
+```js
+return {
+  inject: ['requiredService'],
+  apply(ctx) {
+    ctx.requiredService.someMethod()
+  },
+}
+```
+
+Do not overuse `inject` merely to avoid an `undefined` check. Do not access `ctx.requiredService` without declaring the injection; the Guard rejects undeclared dependencies.
+
+## Manage side effects
+
+Every contribution must be removed after the Plugin is stopped, updated, or removed. Prefer Cordis lifecycle APIs:
+
+- Use `ctx.on()` to register Event listeners.
+- Use `ctx.effect()` to own an external subscription that returns a disposer.
+- Retain disposers returned by Cordis Service, Tool, Slot, timer, and theme APIs.
+- Do not create process-wide or page-wide side effects at module scope or outside `apply()`.
+
+Recommended:
+
+```js
+return {
+  apply(ctx) {
+    const service = ctx.get('serviceName')
+    if (service === undefined) return
+    ctx.effect(() => service.subscribe((value) => {
+      console.log(value)
+    }))
+  },
+}
+```
+
+If `subscribe()` does not return a disposer, first query whether the Service provides a supported cleanup mechanism. Do not assume unload automatically removes arbitrary third-party callbacks.
+
+## Host and Client timers
+
+On both platforms, the timer is a Service named `timer` with the same interface; it is not a Builtin. Query `{ "service": "timer" }` through the corresponding platform's `Service.listService` before using it. Declare `inject: ['timer']` before using the timer mixin.
+
+One-shot delay:
+
+```js
+return {
+  inject: ['timer'],
+  apply(ctx) {
+    const onClick = () => {
+      ctx.timeout(() => console.log('done'), 300)
+    }
+    // Pass onClick to a queried Slot UI.
+  },
+}
+```
+
+Periodic work in a React component:
+
+```js
+return {
+  inject: ['timer'],
+  apply(ctx) {
+    function Clock() {
+      React.useEffect(() => ctx.interval(() => console.log('tick'), 1000), [])
+      return React.createElement('div', null, 'Running')
+    }
+    // Register Clock in a queried Slot.
+  },
+}
+```
+
+Incorrect:
+
+```js
+return {
+  apply(ctx) {
+    ctx.timeout(() => console.log('invalid'), 300)
+  },
+}
+```
+
+```js
+setTimeout(() => console.log('invalid'), 300)
+```
+
+The first example does not declare the timer hard dependency. The second uses a global timer that does not exist.
+
+## Listen to Events
+
+Query the Event Provider first to confirm the platform, parameter order, return value, and `mode`.
+
+Ordinary emit Event:
+
+```js
+return {
+  apply(ctx) {
+    ctx.on('some/event', (payload) => {
+      console.log(payload)
+    })
+  },
+}
+```
+
+The last parameter of a Waterfall Event is `next`. Unless the listener intentionally stops downstream processing, it must call and return it:
+
+```js
+return {
+  apply(ctx) {
+    ctx.on('some/waterfall', (payload, next) => {
+      console.log(payload)
+      return next()
+    })
+  },
+}
+```
+
+## Register Client UI
+
+Query `Slots.listSubTree` without `root` to choose a target from the compact purpose and topology tree, then query the exact Slot with `root` before writing its registration. The exact result determines:
+
+- the Slot's purpose in the layout;
+- whether its registration protocol is `single`, `list`, `keyed`, or `chain`;
+- registration options;
+- scope standard props and business owner props;
+- current occupants, replacement risks, and descendant Slots.
+
+Use `ctx.get('slots')` and handle its absence. Then use `slots.inject` to wait for the Slot declaration and call `slots.register` inside the callback:
+
+```js
+return {
+  apply(ctx) {
+    const slots = ctx.get('slots')
+    if (slots === undefined) return
+    slots.inject('target.slot', () => slots.register(
+      { name: 'target.slot', id: 'my-view' },
+      (props) => React.createElement('div', null, String(props.someValue)),
+    ))
+  },
+}
+```
+
+`ctx.get('slots')` does not require an injection. Do not rewrite it as `ctx.slots` unless `inject: ['slots']` is declared:
+
+```js
+return {
+  apply(ctx) {
+    ctx.slots.register({ name: 'target.slot' }, () => null)
+  },
+}
+```
+
+Do not guess an `id`, `key`, selector, or props before querying the Slot protocol. Do not default to root-level `root`, `sidebar`, `conversation`, or `details` Slots; replacing an entire occupant also removes the descendant Slots it declares.
+
+### Settings pages
+
+A full settings UI should usually register its own section through `settings.section` to obtain a complete content area. `settings.general.item` is only appropriate for one compact, general-purpose preference. Query the actual subtree, options, and props for both, then select the narrowest entry point that is still sufficient.
+
+Dynamic Plugins are temporary and process-local, so their settings UI does not need persistent storage. Do not add durable settings or another persistence mechanism for it. Register the UI in the appropriate settings Slot and keep any transient interaction state in memory for the lifetime of the Plugin.
+
+### Session and page data
+
+A session-scoped Slot may provide `useSession`, `useSessions`, `useWorkspaces`, `useProjection`, input state, or actions through standard props. Follow the query result and prefer owner or standard props directly; do not add a Host RPC for data already present there.
+
+Select only the fields that the UI actually needs. Do not copy or render an entire Conversation Snapshot, Session, Tool call, or Slot props object.
+
+### Cordis Run-specific panel
+
+To place interactive UI in the latest `cordis_run` card, register `tool.view.cordis` with `key: 'self'`:
+
+When the feature needs user interaction tied to this Package's result, this region is often a good fit because it keeps the controls in the conversation flow beside the Run card. It is not the default target for every Client UI: settings, sidebars, message actions, and overlays should use their own queried Slots when those locations better match the feature.
+
+```js
+return {
+  apply(ctx) {
+    const slots = ctx.get('slots')
+    if (slots === undefined) return
+    slots.inject('tool.view.cordis', () => slots.register(
+      { name: 'tool.view.cordis', key: 'self' },
+      (props) => React.createElement('div', null, `Package ${props.packageId}`),
+    ))
+  },
+}
+```
+
+At runtime, `self` binds to `pluginId + packageId`. Do not include `pluginRunId` in the key. When the same Package runs multiple times, the latest Run card hosts the UI and older cards automatically degrade.
+
+### Ordinary Tool cards
+
+To customize the call card for an ordinary model Tool, query `tool.call.toolview`. Its key is the Tool name; registering an existing key may replace the product's default card. When customizing only a newly added Tool, first verify its schema with `Tool.listTools`, then query the complete `ToolCallOwnerProps`.
+
+### Overlays and local entry points
+
+- For toasts, status notices, and frame-wide overlays, query `shell.overlay` first; observe its pointer-events and ordering rules.
+- When the selected target is a global overlay Slot, decide whether the UI should be draggable, how the user shows and hides it, and which existing layers it must cover or remain below.
+- For small sidebar actions, prefer additive inner Slots such as `sidebar.footer.action`; do not replace the entire sidebar.
+- For supplementary content after a conversation turn, query `conversation.chat.turnTail` and register according to its returned chain selector and fallback rules.
+
+## Themes and styles
+
+Determine the scope of the change first:
+
+1. Global theme: first query `Theme.listTokens`, then query `{ "service": "theme" }` through Client `Service.listService`. Supply light and dark values for each override as required by the query, and retain the returned disposer.
+2. The Package's own components: use `styles.insert(css)` and prefer theme CSS variables for colors.
+3. New visible content: choose a Slot first, then decide between local CSS and global tokens.
+
+Do not manipulate `document.body`, `window`, or hard-coded product DOM selectors. The theme Service changes tokens but does not create UI. Slots create UI but do not replace the theme system.
+
+## Call Host from Client
+
+Host registers a Package-private method with `harness.handle(method, handler)`, and Client invokes it with `host.call(method, args)`. This is Client→Host JSON RPC.
+
+Host:
+
+```js
+return {
+  apply(ctx) {
+    harness.handle('read-state', async (args) => {
+      return { value: args.key }
+    })
+  },
+}
+```
+
+Client:
+
+```js
+return {
+  async apply(ctx) {
+    const result = await host.call('read-state', { key: 'demo' })
+    console.log(result.value)
+  },
+}
+```
+
+Arguments and return values must be lossless JSON. Do not pass functions, React elements, class instances, Contexts, Services, or other runtime objects; return `null` when there is no response data. Do not register a public Remote Service or use `ctx.remote` for Package-private communication.
+
+## Register a dynamic model Tool
+
+Host can use `harness` to register a Tool callable in the next model step. First query the current `harness` signature with Host `Builtin.listBuiltins`, then inspect existing Tool names and schemas with `Tool.listTools` to avoid conflicts.
+
+Tool arguments and return values must be JSON-compatible. `execute` owns the business result; render and presentation own only what the model and native UI see. Tool registration must belong to the current Plugin Fiber so it is automatically removed after stop or update.
+
+## Handle internal live data
+
+Service instances, Event payloads, Slot props, Session and Conversation Snapshots, Tool state, and other DSH/Cordis objects are internal live data.
+
+Do not:
+
+- call `JSON.stringify` or `structuredClone` on these objects or their descendants;
+- recursively enumerate, fully copy, or display them as a whole;
+- place Host objects in the Package's long-lived state or RPC return values.
+
+Read only the leaf fields required by the current feature. Extract the minimum strings, numbers, booleans, and other scalar values before constructing owned JSON.
+
+## Versions, approval, and repair
+
+- A Plugin is the stable instance identified by `pluginId`.
+- A Package is an immutable code version identified by `packageId`.
+- Every activation attempt has its own `pluginRunId`.
+- `currentPackageId` is the latest successful version; it does not imply that the Plugin is currently running.
+- `nextPackageId` is the target awaiting approval, activating, awaiting Client activation, or most recently failed.
+
+Choose the `cordis_run` mode as follows:
+
+| Current state | Target | mode |
+| --- | --- | --- |
+| No current | Any Package under the Plugin | `run` |
+| Has current | The same Package | `run` |
+| Has current | A different Package | `update` |
+| Update failed | `nextPackageId` | `update` to retry |
+| Update failed | `currentPackageId` | `run` to roll back |
+
+An unauthorized Client Package returns `awaiting-approval`. A single check mark authorizes only the current Package; double check marks authorize future versions of the same Plugin. A grant remains after a technical runtime failure. An authorized Package returns `starting` and completes asynchronously in the browser.
+
+After a technical failure:
+
+1. Use `cordis_inspect_self(pluginId, packageId)` to read the failed version's source and exact diagnostics.
+2. If the error involves an unknown capability, list and query the corresponding Provider again.
+3. Define a new Package under the same Plugin; do not overwrite the failed Package.
+4. Run again with the new `packageId` and the correct mode.
+
+Do not retry automatically after the user rejects approval. A failed update does not automatically restore the old physical Run; explicitly run current when recovery is required.
+
+## Modify @pluginId
+
+When the user identifies a target with `@pluginId`, do not create another Plugin. The injected context contains only identity, version pointers, and the default base Package, not source code.
+
+Modify it as follows:
+
+1. Read the base Package with `cordis_inspect_self(pluginId, packageId)`.
+2. Preserve the Host or Client half that does not need to change and modify only the target code.
+3. Call `cordis_define` with `plugin.kind: 'existing'` and the original `pluginId`.
+4. Use the returned `packageId`; when current exists, activate the new version with `update` in the usual case.
+
+If the reference is unavailable, explain that the Plugin was removed, belongs to another Session, or was lost on process restart. Do not create a same-named replacement.
+
+## Common failure checks
+
+| Failure | Check first |
+| --- | --- |
+| `service "x" is not declared` | Whether code uses `ctx.x` without declaring `inject: ['x']` on the Plugin object; switch to `ctx.get('x')` with an absence check or declare a true hard dependency |
+| `cannot get property "timer" without inject` | Query the timer Service and declare `inject: ['timer']` |
+| Client parse failure | Whether the code uses JSX, TypeScript, import, or an unavailable global |
+| Slot registration failure | Whether the live subtree was queried, the Slot exists, and options, key, or selector satisfy the returned protocol |
+| UI loads but the page reports an error | Inspect the `client-render` diagnostic and stack; the error belongs to an exact Run, so define a new Package to repair it |
+| `host.call` failure | The Host handler name, current `pluginRunId`, JSON arguments, and real Service dependencies inside the handler |
+| Update failure | Preserve current/next semantics; repair next and update, or run current to roll back |

+ 5 - 3
apps/cli/config/agent-presets/minimal/agent.cordis.yml

@@ -1,15 +1,17 @@
 # The `minimal` agent preset: a fixed-prompt, two-tool coding-agent composition.
 #
 # The persona is the complete system prompt, so global identity, Web orientation,
-# tool guidance, and later assembly listeners cannot add prompt text. The model
-# composes only the persistent shell and `str_replace_editor` tools. Context
-# compaction is deliberately absent.
+# tool guidance, and later assembly listeners cannot add prompt text. Runtime
+# context snapshots are suppressed for this preset, and the model composes only
+# the persistent shell (`bash` on POSIX, `pwsh` on win32) and
+# `str_replace_editor`. Context compaction is absent.
 
 - id: persona
   name: '@deepseek-ai/dsh-persona'
   config:
     text: You are a helpful software engineer assistant.
     complete: true
+    includeRuntimeContext: false
 
 # The PTY registry is an agent-owned service, so it lives in an entry-local
 # realm. The backend still consumes the host sandbox policy and subprocess

+ 4 - 1
apps/cli/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@deepseek-ai/dsh",
   "description": "dsh CLI: profile boot, plugin management, and the browser UI alias",
-  "version": "0.0.1-rc.2",
+  "version": "0.0.1-rc.5",
   "publishConfig": {
     "access": "restricted"
   },
@@ -27,6 +27,9 @@
     "@deepseek-ai/dsh-agent-tool-presentation": "workspace:^",
     "@deepseek-ai/dsh-app-boot": "workspace:^",
     "@deepseek-ai/dsh-base": "workspace:^",
+    "@deepseek-ai/dsh-cordis-client-runner": "workspace:^",
+    "@deepseek-ai/dsh-client-ui-agent-preset": "workspace:^",
+    "@deepseek-ai/dsh-client-ui-cordis": "workspace:^",
     "@deepseek-ai/dsh-command-compact": "workspace:^",
     "@deepseek-ai/dsh-command-goal": "workspace:^",
     "@deepseek-ai/dsh-compaction-basic": "workspace:^",

+ 5 - 2
apps/cli/tests/web-agent-presets.e2e.ts

@@ -260,7 +260,10 @@ describe('the shipped Web composition', () => {
     try {
       const tools = toolNames(ctx, handle.agent)
       // The self-referential toolset is what distinguishes this preset.
-      expect(tools).toEqual(expect.arrayContaining(['cordis_inspect', 'cordis_mount', 'cordis_unmount']))
+      expect(tools).toEqual(expect.arrayContaining([
+        'cordis_inspect_list', 'cordis_inspect_query', 'cordis_inspect_self',
+        'cordis_define', 'cordis_run', 'cordis_stop', 'cordis_undefine',
+      ]))
       // And it keeps the standard agent's own tools rather than replacing them.
       expect(tools).toEqual(expect.arrayContaining(['bash', 'read', 'edit', 'skill']))
       expect(tools).not.toContain('str_replace_editor')
@@ -314,7 +317,7 @@ describe('the shipped Web composition', () => {
     })
     try {
       // Editing the live runtime is opt-in per session, not ambient.
-      expect(toolNames(ctx, handle.agent)).not.toContain('cordis_mount')
+      expect(toolNames(ctx, handle.agent)).not.toContain('cordis_define')
     } finally {
       await handle.dispose()
     }

+ 1 - 1
apps/web/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@deepseek-ai/dsh-web-frontend",
   "description": "Web application entry: vite build over the @deepseek-ai/dsh-client-web shell library; dist/ served by apps/cli's dsh web",
-  "version": "0.0.1-rc.2",
+  "version": "0.0.1-rc.5",
   "publishConfig": {
     "access": "restricted"
   },

+ 1 - 1
apps/web/tests/assembled-boot.ts

@@ -43,7 +43,7 @@ const PLUGINS: readonly (WebBootEntry & { bundlePath: string })[] = [
       '@deepseek-ai/dsh-client-ui-sidebar',
     ],
   },
-  { id: '@deepseek-ai/dsh-session-log-download', bundlePath: 'packages/session-query/session-log-download/lib/client.js', url: '/plugins/session-log-download.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-commands', '@deepseek-ai/dsh-client-ui-conversation'] },
+  { id: '@deepseek-ai/dsh-session-log-export', bundlePath: 'packages/session-query/session-log-export/lib/client.js', url: '/plugins/session-log-download.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-commands', '@deepseek-ai/dsh-client-ui-conversation'] },
   { id: '@deepseek-ai/dsh-client-ui-trajectory', bundlePath: 'packages/client/ui-trajectory/lib/client.js', url: '/plugins/ui-trajectory.js', rev: 'fx', inject: ['@deepseek-ai/dsh-client-ui-conversation'] },
 ]
 

+ 70 - 25
apps/web/tests/cordis-tool-round.e2e.ts

@@ -1,7 +1,13 @@
 // Web e2e scenario for the opt-in Cordis tools. Record mode drives a real
-// model through inspect, mount, and unmount; replay pins the same shipped Web
-// composition, durable calls, generic rows, highlighted Plugin source, and
-// conversation accessibility tree.
+// model through inspect, define, run, and stop; replay pins the same shipped Web
+// composition, durable calls, Cordis-owned rows, the define card's own source view,
+// and conversation accessibility tree.
+//
+// The approval is never in the fixture. The fixture pins what the MODEL said;
+// tools execute for real, and this test answers the approval before starting the
+// stop turn. The package therefore carries a browser half whose only
+// job is to be visible (`[data-snapshot-probe]`): its absence before the answer
+// and presence after it is the v3 user gate, proven rather than described.
 import { readFile } from 'node:fs/promises'
 import { fileURLToPath } from 'node:url'
 import type { Browser, Page } from 'playwright'
@@ -17,12 +23,24 @@ import { connectFreshWorkspace, newEnglishPage, saveFailureShot } from './suppor
 const FIXTURE = fileURLToPath(new URL('./snapshots/cordis-tool-round/session.jsonl', import.meta.url))
 const UI_EXPECTED = fileURLToPath(new URL('./snapshots/cordis-tool-round/ui.expected.md', import.meta.url))
 const MODE = webSnapshotMode()
-const CORDIS_TOOLS = ['cordis_inspect', 'cordis_mount', 'cordis_unmount'] as const
-const MOUNT_CODE = 'return { name: "snapshot-noop", apply(ctx) {} }'
-const PROMPT = 'Use only Cordis tools. First call cordis_inspect with what "temporary". '
-  + `Then call cordis_mount with this exact code: ${JSON.stringify(MOUNT_CODE)}. `
-  + 'Read its returned id and call cordis_unmount with that exact id. '
-  + 'After all three calls succeed, reply exactly CORDIS_UI_DONE and stop.'
+const CORDIS_TOOLS = ['cordis_inspect_self', 'cordis_define', 'cordis_run', 'cordis_stop'] as const
+const PACKAGE_CODE = 'return { name: "snapshot-noop", apply(ctx) {} }'
+// The browser half is the PROBE this scenario turns on: it renders a marker into
+// the frame-wide overlay, so "did the plugin actually run in this page" becomes a
+// DOM fact. A host-only package would sidestep the approval round trip entirely
+// (the host runs those immediately), which would drop the v3 user gate out of
+// coverage — the one thing this scenario exists to prove.
+const CLIENT_CODE = 'return { inject: ["slots"], apply(ctx) { ctx.slots.register('
+  + '{ name: "shell.overlay", id: "snapshot-probe" }, '
+  + '() => React.createElement("div", { "data-snapshot-probe": "loaded" })) } }'
+const PROMPT = 'Use only Cordis tools. First call cordis_inspect_self with no arguments. '
+  + 'Then call cordis_define with plugin kind "new", idPrefix "snap", name "snapshot noop", '
+  + 'purpose "does nothing, for the snapshot", '
+  + `code.host exactly ${JSON.stringify(PACKAGE_CODE)} and code.client exactly ${JSON.stringify(CLIENT_CODE)}. `
+  + 'Read its returned pluginId and packageId, then call cordis_run with those exact IDs and mode "run". '
+  + 'After the run request returns, reply exactly CORDIS_UI_READY and stop.'
+const STOP_PROMPT = 'Use only Cordis tools. Call cordis_stop with pluginId "snap-1". '
+  + 'After it succeeds, reply exactly CORDIS_UI_DONE and stop.'
 
 function assertCompleteCordisLifecycle(events: readonly SessionEvent[]): void {
   const turnEnd = events.findLast(
@@ -46,7 +64,7 @@ function assertCompleteCordisLifecycle(events: readonly SessionEvent[]): void {
   expect(results.every(event => !event.data.message.content[0].isError)).toBe(true)
 }
 
-describe('web e2e: Cordis tools use the generic row variants', () => {
+describe('web e2e: Cordis tools use their owned cards', () => {
   let scaffold: WebScaffold
   let browser: Browser
   let page: Page
@@ -75,14 +93,30 @@ describe('web e2e: Cordis tools use the generic row variants', () => {
   it('drives the recorded Cordis lifecycle to a settled turn (all modes)', async () => {
     onTestFailed(() => saveFailureShot(page, 'web-e2e-cordis-drive'))
     if (MODE !== 'record') {
-      expect(fixtureUserPrompts(await readFile(FIXTURE, 'utf8'))).toEqual([PROMPT])
+      expect(fixtureUserPrompts(await readFile(FIXTURE, 'utf8'))).toEqual([PROMPT, STOP_PROMPT])
     }
     const input = page.locator('textarea').first()
     await input.waitFor({ timeout: 10_000 })
-    const settled = scaffold.whenTurnSettled()
+    const runTurnSettled = scaffold.whenTurnSettled()
     await input.fill(PROMPT)
     await input.press('Enter')
-    const sessionId = await settled
+
+    // The approval is the TEST's action in every mode: the fixture pins what the
+    // model said, and the gate is a real round trip through the real panel.
+    const approve = page.locator('[data-cordis-approve]').first()
+    await approve.waitFor({ timeout: 90_000 })
+    // The one assertion this scenario cannot give up: the model asking to run is
+    // NOT the plugin running. Until a person answers, the browser half has not
+    // been fetched, evaluated, or mounted anywhere on this page.
+    expect(await page.locator('[data-snapshot-probe]').count()).toBe(0)
+    await approve.click()
+    await expect.poll(() => page.locator('[data-snapshot-probe]').count(), { timeout: 30_000 }).toBe(1)
+
+    const sessionId = await runTurnSettled
+    const stopTurnSettled = scaffold.whenTurnSettled()
+    await input.fill(STOP_PROMPT)
+    await input.press('Enter')
+    await stopTurnSettled
     if (MODE === 'record') {
       assertCompleteCordisLifecycle(sessionEvents)
       await expect.poll(() => page.getByText('CORDIS_UI_DONE', { exact: true }).count(), { timeout: 15_000 })
@@ -95,25 +129,36 @@ describe('web e2e: Cordis tools use the generic row variants', () => {
     assertCompleteCordisLifecycle(sessionEvents)
   })
 
-  it.skipIf(MODE === 'record')('renders Cordis lifecycle titles over the generic row mechanics', async () => {
+  it.skipIf(MODE === 'record')('renders localized Cordis lifecycle cards', async () => {
     onTestFailed(() => saveFailureShot(page, 'web-e2e-cordis-rows'))
     await expect.poll(() => page.getByText('CORDIS_UI_DONE', { exact: true }).count(), { timeout: 15_000 })
       .toBeGreaterThanOrEqual(1)
 
-    const inspectRow = page.locator('[data-tool="cordis_inspect"]').filter({ hasText: 'Inspect' }).first()
+    const inspectRow = page.locator('[data-tool="cordis_inspect_self"]').filter({ hasText: 'Inspect' }).first()
     await inspectRow.waitFor({ timeout: 10_000 })
 
-    const mountRow = page.locator('[data-tool="cordis_mount"]').filter({ hasText: 'Mount temporary Plugin' }).first()
-    await mountRow.waitFor({ timeout: 10_000 })
+    // cordis_define does NOT go through the generic row: ui-cordis registers a
+    // keyed toolview for it, and a keyed hit replaces the generic card. So the
+    // title here is the CARD's ("Cordis Plugin"), and the expanded body is the
+    // card's own two code sections rather than a generic args dump.
+    const defineRow = page.locator('[data-tool="cordis_define"]').filter({ hasText: 'Cordis Plugin' }).first()
+    await defineRow.waitFor({ timeout: 10_000 })
     // The whole summary row is the expand toggle (unified tool-row interaction).
-    await mountRow.locator('[aria-expanded]').first().click()
-    await expect.poll(() => mountRow.locator('pre.shiki').textContent(), { timeout: 10_000 })
-      .toContain(MOUNT_CODE)
-
-    const unmountRow = page.locator('[data-tool="cordis_unmount"]').filter({ hasText: 'Unmount temporary Plugin' }).first()
-    await unmountRow.waitFor({ timeout: 10_000 })
-    await expect.poll(() => unmountRow.textContent()).toContain('dyn-')
-    await expect(unmountRow.getAttribute('data-state')).resolves.toBe('ok')
+    await defineRow.locator('[aria-expanded]').first().click()
+    await expect.poll(() => defineRow.textContent(), { timeout: 10_000 }).toContain('data-snapshot-probe')
+    await defineRow.getByRole('tab', { name: 'Host' }).click()
+    await expect.poll(() => defineRow.textContent()).toContain(PACKAGE_CODE)
+
+    const runRow = page.locator('[data-tool="cordis_run"]').filter({ hasText: 'Run Cordis Plugin' }).first()
+    await runRow.waitFor({ timeout: 10_000 })
+    await expect.poll(() => runRow.textContent()).toContain('snap-')
+
+    const stopRow = page.locator('[data-tool="cordis_stop"]').filter({ hasText: 'Stop Cordis Plugin' }).first()
+    await stopRow.waitFor({ timeout: 10_000 })
+    await expect.poll(() => stopRow.textContent()).toContain('snap-')
+    await expect(stopRow.getAttribute('data-state')).resolves.toBe('ok')
+    // Stopping withdraws the browser half from every page, probe included.
+    await expect.poll(() => page.locator('[data-snapshot-probe]').count(), { timeout: 15_000 }).toBe(0)
   })
 
   it.skipIf(MODE === 'record')('matches the conversation aria golden', async () => {

+ 3 - 0
apps/web/tests/minimal-preset.snapshot.ts

@@ -55,6 +55,9 @@ describe('minimal agent preset', () => {
 
     const requestHeader = agentHandle.agent.session.requestHeader()
     if (requestHeader === undefined) throw new Error('the minimal agent issued no model request')
+    expect(agentHandle.agent.session.events.some(event => event.type === 'user/message'
+      && event.data.source.kind === 'plugin'
+      && event.data.source.plugin === '@deepseek-ai/dsh-system-prompt')).toBe(false)
     const presetFileSystem = scaffold.ctx.agentPresets.serviceFor(agentHandle.agent, 'fs')
     expect(presetFileSystem).toBeDefined()
     expect(presetFileSystem?.sandboxMode).toBeUndefined()

+ 6 - 6
apps/web/tests/scaffold.ts

@@ -70,7 +70,6 @@ import SessionStore, {
   type SessionHeader,
 } from '@deepseek-ai/dsh-session'
 import JsonlSessionPersistence from '@deepseek-ai/dsh-session-persistence-jsonl'
-import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
 // Empty type imports carry the webServer/agents/sessionPersistence Context merges.
 import type {} from '@deepseek-ai/dsh-host-webserver'
 import type {} from '@deepseek-ai/dsh-agent'
@@ -217,7 +216,7 @@ export interface LaunchOptions {
    */
   toolsMode?: 'native' | 'code' | 'both'
   /**
-   * Insert the opt-in self-referential Cordis tools into the shipped tree.
+   * Insert the opt-in model-facing Cordis tool provider into the shipped tree.
    * Record and replay use the same tool surface, so captured request headers
    * remain reconstructable without making the tools a product default.
    */
@@ -460,8 +459,12 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
       // be able to change a golden, whatever roots a scenario asks for.
       : [{ id: 'agent-presets', config: { ...options.agentPresets, includeUserRoot: false } }],
     ...options.toolsMode === undefined ? [] : [{ id: 'tools', config: { mode: options.toolsMode } }],
+    // The shipped Web bundle already owns both runners and the Cordis UI. This
+    // scenario adds only the model-facing tools that exercise those services.
     ...options.cordisTools === true
-      ? [{ insert: [{ id: 'tool-cordis', name: 'cordis:tool-cordis' }] }]
+      ? [{ insert: [
+        { id: 'tool-cordis', name: '@deepseek-ai/dsh-tool-cordis' },
+      ] }]
       : [],
     ...options.deepSeekSearch === undefined
       ? []
@@ -513,9 +516,6 @@ export async function launchWebScaffold(options: LaunchOptions = {}): Promise<We
     // and a preset resolving package names from its own directory cannot reach
     // `@deepseek-ai/cordis-plugin-group` by name.
     ctx.loader.builtins.group = Group
-    // The shipped CLI deliberately has no dependency on this opt-in package.
-    // Keep the Loader row real without broadening the product installation.
-    if (options.cordisTools === true) ctx.loader.builtins['tool-cordis'] = ToolCordis
     await ctx.loader.create({
       name: 'cordis:include',
       config: { path: pathToFileURL(rootConfig).href, patches },

+ 1 - 1
apps/web/tests/smoke-real.e2e.ts

@@ -144,7 +144,7 @@ async function detailsTrack(page: Page): Promise<number> {
 const UI_PLUGIN_DIRS = [
   'connection', 'runtime', 'ui-theme', 'locale', 'ui-layout', 'ui-sidebar',
   'ui-settings', 'ui-settings-general', 'ui-settings-models', 'ui-conversation',
-  'ui-model-selection', 'ui-user-questions', 'ui-trajectory', '../session-query/session-log-download',
+  'ui-model-selection', 'ui-user-questions', 'ui-trajectory', '../session-query/session-log-export',
 ]
 const ROUND_DONE_MARKER = 'WEB_ROUND_DONE'
 const notReady = UI_PLUGIN_DIRS.filter((dir) => {

+ 18 - 17
apps/web/tests/snapshots/cordis-tool-round/session.jsonl

@@ -1,15 +1,13 @@
 {"type":"session","version":0,"id":"{{sessionId}}","createdAt":1785157562825,"cwd":"{{cwd}}/workspace"}
 {"type":"turn/start","seq":0,"time":1785157562881,"data":{"turn":1,"trigger":{"kind":"message","source":{"kind":"user","rpcId":"{{rpcId}}"}}}}
-{"type":"user/message","seq":1,"time":1785157562882,"data":{"content":[{"type":"text","text":"Use only Cordis tools. First call cordis_inspect with what \"temporary\". Then call cordis_mount with this exact code: \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\". Read its returned id and call cordis_unmount with that exact id. After all three calls succeed, reply exactly CORDIS_UI_DONE and stop."}],"source":{"kind":"user","rpcId":"{{rpcId}}"}},"surfaceOp":"append"}
+{"type":"user/message","seq":1,"time":1785157562882,"data":{"content":[{"type":"text","text":"Use only Cordis tools. First call cordis_inspect_self with no arguments. Then call cordis_define with plugin kind \"new\", idPrefix \"snap\", name \"snapshot noop\", purpose \"does nothing, for the snapshot\", code.host exactly \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\" and code.client exactly \"return { inject: [\\\"slots\\\"], apply(ctx) { ctx.slots.register({ name: \\\"shell.overlay\\\", id: \\\"snapshot-probe\\\" }, () => React.createElement(\\\"div\\\", { \\\"data-snapshot-probe\\\": \\\"loaded\\\" })) } }\". Read its returned pluginId and packageId, then call cordis_run with those exact IDs and mode \"run\". After the run request returns, reply exactly CORDIS_UI_READY and stop."}],"source":{"kind":"user","rpcId":"{{rpcId}}"}},"surfaceOp":"append"}
 {"type":"session/title","seq":2,"time":1785157562883,"data":{"title":"Use only Cordis tools. First","messageSeqs":[1],"source":{"kind":"fallback"}}}
 {"type":"step/start","seq":3,"time":1785157562937,"data":{"turn":1,"step":1}}
 {"type":"request/header","seq":4,"time":1785157562938,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash","reasoningEffort":"high"},"system":"{{system}}","tools":"{{tools}}","messagePrefix":["{{messagePrefix}}"]},"reason":"initial"}}
 {"type":"assistant/chunk","seq":5,"time":1785157564667,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
-{"type":"reasoning-chunks","seq0":6,"time0":1785157564667,"data":{"turn":1,"step":1,"index":0,"dt":[115,31,3,0,1,0,1,21,1,0,0,0,1,23,0,1,0,0,0,24,2,1,0,0,0,28,2,0,0,0,1,23,2,22,2,1,25,2,0,0,25,27,1,1,0,0,28,2,0,0,0,0,32,1,31,1,0,0,0,9,29,3,0,0,0,1,23,1,0,0,0,27,4,0,0,0,23,2,0,0],"texts":["The"," user"," wants"," me"," to",":\n","1","."," Call"," `","cord","is","_in","spect","`"," with"," `","what",":"," \"","t","emporary","\"`\n","2","."," Call"," `","cord","is","_m","ount","`"," with"," the"," exact"," code"," provided","\n","3","."," Read"," the"," returned"," id"," and"," call"," `","cord","is","_un","mount","`"," with"," that"," exact"," id","\n","4","."," Reply"," exactly"," \"","C","ORD","IS","_","UI","_D","ONE","\""," and"," stop","\n\n","Let"," me"," start"," with"," step"," ","1","."]}}
 {"type":"assistant/chunk","seq":87,"time":1785157565360,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}}
-{"type":"tool-call-chunks","seq0":88,"time0":1785157565360,"data":{"turn":1,"step":1,"index":1,"dt":[15,2,0,0,25,2,0,0,27,1],"id":"call_00_KZk918WtlKan9pHMULIT8794","name":"cordis_inspect","args":["","{","\"","what","\"",": ","\"","t","emporary","\"","}"]}}
-{"type":"assistant/chunk","seq":99,"time":1785157565490,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The user wants me to:\n1. Call `cordis_inspect` with `what: \"temporary\"`\n2. Call `cordis_mount` with the exact code provided\n3. Read the returned id and call `cordis_unmount` with that exact id\n4. Reply exactly \"CORDIS_UI_DONE\" and stop\n\nLet me start with step 1."}}}}
-{"type":"assistant/chunk","seq":100,"time":1785157565491,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_KZk918WtlKan9pHMULIT8794","name":"cordis_inspect","arguments":"{\"what\": \"temporary\"}"}}}}
+{"type":"assistant/chunk","seq":99,"time":1785157565490,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"I will inspect the current Session's dynamic Cordis Plugins before defining the snapshot Package."}}}}
+{"type":"assistant/chunk","seq":100,"time":1785157565491,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"cordis-inspect-self","name":"cordis_inspect_self","arguments":"{}"}}}}
 {"type":"assistant/chunk","seq":101,"time":1785157565491,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":15137,"outputTokens":128,"cacheReadTokens":1280,"reasoningTokens":81}}}}
 {"type":"assistant/chunk","seq":102,"time":1785157565491,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
 {"type":"assistant/message","seq":103,"time":1785157565495,"data":{"turn":1,"step":1,"content":[{"type":"reasoning","text":"The user wants me to:\n1. Call `cordis_inspect` with `what: \"temporary\"`\n2. Call `cordis_mount` with the exact code provided\n3. Read the returned id and call `cordis_unmount` with that exact id\n4. Reply exactly \"CORDIS_UI_DONE\" and stop\n\nLet me start with step 1."},{"type":"tool-call","id":"call_00_KZk918WtlKan9pHMULIT8794","name":"cordis_inspect","arguments":"{\"what\": \"temporary\"}"}],"provenance":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"usage":{"inputTokens":15137,"outputTokens":128,"cacheReadTokens":1280,"reasoningTokens":81}},"sourceEventSeqs":[5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102],"surfaceOp":"append"}
@@ -18,11 +16,9 @@
 {"type":"step/end","seq":106,"time":1785157565503,"data":{"turn":1,"step":1}}
 {"type":"step/start","seq":107,"time":1785157565503,"data":{"turn":1,"step":2}}
 {"type":"assistant/chunk","seq":108,"time":1785157566524,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
-{"type":"reasoning-chunks","seq0":109,"time0":1785157566525,"data":{"turn":1,"step":2,"index":0,"dt":[105,30,2,0,0,24,2,0,0,27,2,1,0,25,0,0,0,1,0,39,1],"texts":["Good",","," no"," temporary"," plugins"," running","."," Now"," step"," ","2",":"," call"," cord","is","_m","ount"," with"," the"," exact"," code","."]}}
 {"type":"assistant/chunk","seq":131,"time":1785157566845,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}}
-{"type":"tool-call-chunks","seq0":132,"time0":1785157566845,"data":{"turn":1,"step":2,"index":1,"dt":[42,4,1,0,0,15,2,0,0,0,16,0,0,0,0,1,23,2,0,0,25,7,18],"id":"call_00_OyrlxqqpnvzTe11sN5Oy2361","name":"cordis_mount","args":["","{","\"","code","\"",": ","\"","return"," {"," name",":"," \\\"","sn","apshot","-no","op","\\\","," apply","(ctx",")"," {}"," }","\"","}"]}}
-{"type":"assistant/chunk","seq":156,"time":1785157567041,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"Good, no temporary plugins running. Now step 2: call cordis_mount with the exact code."}}}}
-{"type":"assistant/chunk","seq":157,"time":1785157567041,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_OyrlxqqpnvzTe11sN5Oy2361","name":"cordis_mount","arguments":"{\"code\": \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\"}"}}}}
+{"type":"assistant/chunk","seq":156,"time":1785157567041,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"No dynamic Plugins are present, so I will define the requested Host and Client Package."}}}}
+{"type":"assistant/chunk","seq":157,"time":1785157567041,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"cordis-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"snapshot noop\",\"purpose\":\"does nothing, for the snapshot\",\"code\":{\"host\":\"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\",\"client\":\"return { inject: [\\\"slots\\\"], apply(ctx) { ctx.slots.register({ name: \\\"shell.overlay\\\", id: \\\"snapshot-probe\\\" }, () => React.createElement(\\\"div\\\", { \\\"data-snapshot-probe\\\": \\\"loaded\\\" })) } }\"}}"}}}}
 {"type":"assistant/chunk","seq":158,"time":1785157567042,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":72,"outputTokens":82,"cacheReadTokens":16512,"reasoningTokens":22}}}}
 {"type":"assistant/chunk","seq":159,"time":1785157567042,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
 {"type":"assistant/message","seq":160,"time":1785157567043,"data":{"turn":1,"step":2,"content":[{"type":"reasoning","text":"Good, no temporary plugins running. Now step 2: call cordis_mount with the exact code."},{"type":"tool-call","id":"call_00_OyrlxqqpnvzTe11sN5Oy2361","name":"cordis_mount","arguments":"{\"code\": \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\"}"}],"provenance":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"usage":{"inputTokens":72,"outputTokens":82,"cacheReadTokens":16512,"reasoningTokens":22}},"sourceEventSeqs":[108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159],"surfaceOp":"append"}
@@ -31,11 +27,9 @@
 {"type":"step/end","seq":163,"time":1785157567050,"data":{"turn":1,"step":2}}
 {"type":"step/start","seq":164,"time":1785157567050,"data":{"turn":1,"step":3}}
 {"type":"assistant/chunk","seq":165,"time":1785157567835,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
-{"type":"reasoning-chunks","seq0":166,"time0":1785157567836,"data":{"turn":1,"step":3,"index":0,"dt":[83,25,2,0,0,26,1,1,0,0,0,41,2,0,0,0,0,8,2,0,0,0],"texts":["The"," id"," is"," \"","d","yn","-","1","\"."," Now"," step"," ","3",":"," call"," cord","is","_un","mount"," with"," that"," id","."]}}
 {"type":"assistant/chunk","seq":189,"time":1785157568117,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":1,"blockType":"tool-call"}}}
-{"type":"tool-call-chunks","seq0":190,"time0":1785157568118,"data":{"turn":1,"step":3,"index":1,"dt":[17,2,1,24,2,0,1,25,0,0,0,29],"id":"call_00_e38S6zeYdZGvbhecUCil6659","name":"cordis_unmount","args":["","{","\"","id","\"",": ","\"","d","yn","-","1","\"","}"]}}
-{"type":"assistant/chunk","seq":203,"time":1785157568278,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The id is \"dyn-1\". Now step 3: call cordis_unmount with that id."}}}}
-{"type":"assistant/chunk","seq":204,"time":1785157568279,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"call_00_e38S6zeYdZGvbhecUCil6659","name":"cordis_unmount","arguments":"{\"id\": \"dyn-1\"}"}}}}
+{"type":"assistant/chunk","seq":203,"time":1785157568278,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The Host returned snap-1/pkg-1, so I will request its first activation."}}}}
+{"type":"assistant/chunk","seq":204,"time":1785157568279,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":1,"block":{"type":"tool-call","id":"cordis-run","name":"cordis_run","arguments":"{\"pluginId\":\"snap-1\",\"packageId\":\"pkg-1\",\"mode\":\"run\"}"}}}}
 {"type":"assistant/chunk","seq":205,"time":1785157568279,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":63,"outputTokens":72,"cacheReadTokens":16640,"reasoningTokens":23}}}}
 {"type":"assistant/chunk","seq":206,"time":1785157568279,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
 {"type":"assistant/message","seq":207,"time":1785157568280,"data":{"turn":1,"step":3,"content":[{"type":"reasoning","text":"The id is \"dyn-1\". Now step 3: call cordis_unmount with that id."},{"type":"tool-call","id":"call_00_e38S6zeYdZGvbhecUCil6659","name":"cordis_unmount","arguments":"{\"id\": \"dyn-1\"}"}],"provenance":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"usage":{"inputTokens":63,"outputTokens":72,"cacheReadTokens":16640,"reasoningTokens":23}},"sourceEventSeqs":[165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206],"surfaceOp":"append"}
@@ -44,13 +38,20 @@
 {"type":"step/end","seq":210,"time":1785157568282,"data":{"turn":1,"step":3}}
 {"type":"step/start","seq":211,"time":1785157568282,"data":{"turn":1,"step":4}}
 {"type":"assistant/chunk","seq":212,"time":1785157569185,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"reasoning"}}}
-{"type":"reasoning-chunks","seq0":213,"time0":1785157569186,"data":{"turn":1,"step":4,"index":0,"dt":[165,26,26,1,0,27,9,17,2,1,0,0,0,44,1,0,0,1,0,6,3],"texts":["All"," three"," calls"," succeeded","."," I"," should"," now"," reply"," exactly"," \"","C","ORD","IS","_","UI","_D","ONE","\""," and"," stop","."]}}
 {"type":"assistant/chunk","seq":235,"time":1785157569515,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":1,"blockType":"text"}}}
-{"type":"text-chunks","seq0":236,"time0":1785157569515,"data":{"turn":1,"step":4,"index":1,"dt":[0,0,35,1,0,0],"texts":["C","ORD","IS","_","UI","_D","ONE"]}}
-{"type":"assistant/chunk","seq":243,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"All three calls succeeded. I should now reply exactly \"CORDIS_UI_DONE\" and stop."}}}}
-{"type":"assistant/chunk","seq":244,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CORDIS_UI_DONE"}}}}
+{"type":"assistant/chunk","seq":243,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"reasoning","text":"The activation request has been submitted, so I will return the requested readiness marker."}}}}
+{"type":"assistant/chunk","seq":244,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":1,"block":{"type":"text","text":"CORDIS_UI_READY"}}}}
 {"type":"assistant/chunk","seq":245,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":29,"outputTokens":30,"cacheReadTokens":16768,"reasoningTokens":22}}}}
 {"type":"assistant/chunk","seq":246,"time":1785157569551,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
 {"type":"assistant/message","seq":247,"time":1785157569553,"data":{"turn":1,"step":4,"content":[{"type":"reasoning","text":"All three calls succeeded. I should now reply exactly \"CORDIS_UI_DONE\" and stop."},{"type":"text","text":"CORDIS_UI_DONE"}],"provenance":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"usage":{"inputTokens":29,"outputTokens":30,"cacheReadTokens":16768,"reasoningTokens":22}},"sourceEventSeqs":[212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246],"surfaceOp":"append"}
 {"type":"step/end","seq":248,"time":1785157569554,"data":{"turn":1,"step":4}}
 {"type":"turn/end","seq":249,"time":1785157569554,"data":{"turn":1,"reason":{"kind":"completed"}}}
+{"type":"user/message","seq":250,"time":1785157569555,"data":{"content":[{"type":"text","text":"Use only Cordis tools. Call cordis_stop with pluginId \"snap-1\". After it succeeds, reply exactly CORDIS_UI_DONE and stop."}],"source":{"kind":"user","rpcId":"{{rpcId}}"}},"surfaceOp":"append"}
+{"type":"assistant/chunk","seq":251,"time":1785157569556,"data":{"turn":2,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":252,"time":1785157569557,"data":{"turn":2,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"cordis-stop","name":"cordis_stop","arguments":"{\"pluginId\":\"snap-1\"}"}}}}
+{"type":"assistant/chunk","seq":253,"time":1785157569558,"data":{"turn":2,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":254,"time":1785157569559,"data":{"turn":2,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/chunk","seq":255,"time":1785157569560,"data":{"turn":2,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
+{"type":"assistant/chunk","seq":256,"time":1785157569561,"data":{"turn":2,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"CORDIS_UI_DONE"}}}}
+{"type":"assistant/chunk","seq":257,"time":1785157569562,"data":{"turn":2,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":258,"time":1785157569563,"data":{"turn":2,"step":2,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}

+ 51 - 22
apps/web/tests/snapshots/cordis-tool-round/ui.expected.md

@@ -9,45 +9,67 @@
   - tablist:
     - tab "Chat" [selected]
     - tab "Trajectory"
-- text: "Use only Cordis tools. First call cordis_inspect with what \"temporary\". Then call cordis_mount with this exact code: \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\". Read its returned id and call cordis_unmount with that exact id. After all three calls succeed, reply exactly CORDIS_UI_DONE and stop. {{clock}}"
+- text: "Use only Cordis tools. First call cordis_inspect_self with no arguments. Then call cordis_define with plugin kind \"new\", idPrefix \"snap\", name \"snapshot noop\", purpose \"does nothing, for the snapshot\", code.host exactly \"return { name: \\\"snapshot-noop\\\", apply(ctx) {} }\" and code.client exactly \"return { inject: [\\\"slots\\\"], apply(ctx) { ctx.slots.register({ name: \\\"shell.overlay\\\", id: \\\"snapshot-probe\\\" }, () => React.createElement(\\\"div\\\", { \\\"data-snapshot-probe\\\": \\\"loaded\\\" })) } }\". Read its returned pluginId and packageId, then call cordis_run with those exact IDs and mode \"run\". After the run request returns, reply exactly CORDIS_UI_READY and stop. {{clock}}"
 - button "Copy":
   - img
 - button "Context injection @deepseek-ai/dsh-system-prompt":
   - img
   - img
   - text: Context injection @deepseek-ai/dsh-system-prompt
-- button "Think The user wants me to:":
+- button "Think I will inspect the current Session's dynamic Cordis Plugins before defining the snapshot Package.":
   - img
   - img
-  - text: "Think The user wants me to:"
-- button "Inspect temporary":
+  - text: Think I will inspect the current Session's dynamic Cordis Plugins before defining the snapshot Package.
+- 'button "Tool call cordis_inspect_self · {}"':
   - img
   - img
-  - text: Inspect temporary
-- 'button "Think Good, no temporary plugins running. Now step 2: call cordis_mount with the exact code."':
+  - text: "Tool call cordis_inspect_self · {}"
+- button "Think No dynamic Plugins are present, so I will define the requested Host and Client Package.":
   - img
   - img
-  - text: "Think Good, no temporary plugins running. Now step 2: call cordis_mount with the exact code."
-- 'button "Mount temporary Plugin return { name: \"snapshot-noop\", apply(ctx) {} }" [expanded]':
+  - text: Think No dynamic Plugins are present, so I will define the requested Host and Client Package.
+- button "Register Cordis Plugin snapshot noop does nothing, for the snapshot Ready" [expanded]:
   - img
-  - text: "Mount temporary Plugin return { name: \"snapshot-noop\", apply(ctx) {} }"
-- text: typescript
-- button "Copy"
-- code: "return { name: \"snapshot-noop\", apply(ctx) {} }"
-- text: OUT Temporary Plugin dyn-1 is running (plugin "snapshot-noop"; available until unmounted or DSH restarts).
+  - text: Register Cordis Plugin snapshot noop does nothing, for the snapshot Ready
+- tablist "Plugin source":
+  - tab "Client"
+  - tab "Host" [selected]
+- tabpanel "Host":
+  - text: javascript
+  - button "Copy"
+  - code: "return { name: \"snapshot-noop\", apply(ctx) {} }"
+- text: Result Defined snap-1/pkg-1 (snapshot noop); it is not running yet. Use cordis_run to activate this Package. Run controls live in the Cordis panel above Settings
 - button "Inspect"
-- 'button "Think The id is \"dyn-1\". Now step 3: call cordis_unmount with that id."':
+- button "Think The Host returned snap-1/pkg-1, so I will request its first activation.":
   - img
   - img
-  - text: "Think The id is \"dyn-1\". Now step 3: call cordis_unmount with that id."
-- button "Unmount temporary Plugin dyn-1":
+  - text: Think The Host returned snap-1/pkg-1, so I will request its first activation.
+- img
+- text: Run Cordis Plugin snap-1 · pkg-1 Ready
+- button "Inspect"
+- text: snap-1/pkg-1 is awaiting user approval (run-1).
+- button "Think The activation request has been submitted, so I will return the requested readiness marker.":
+  - img
   - img
+  - text: Think The activation request has been submitted, so I will return the requested readiness marker.
+- paragraph: CORDIS_UI_READY
+- button "Copy":
   - img
-  - text: Unmount temporary Plugin dyn-1
-- button "Think All three calls succeeded. I should now reply exactly \"CORDIS_UI_DONE\" and stop.":
+- button "Good response":
   - img
+- button "Bad response":
+  - img
+- button "Branch into a new conversation":
   - img
-  - text: Think All three calls succeeded. I should now reply exactly "CORDIS_UI_DONE" and stop.
+- text: {{clock}} Ran for {{duration}}
+- button "Context injection cordis-host-runner":
+  - img
+  - img
+  - text: Context injection cordis-host-runner
+- img
+- text: Stop Cordis Plugin snap-1
+- button "Inspect"
+- text: Dynamic Plugin snap-1 is stopped; its definition and versions remain.
 - paragraph: CORDIS_UI_DONE
 - button "Copy":
   - img
@@ -57,7 +79,14 @@
   - img
 - button "Branch into a new conversation":
   - img
-- text: {{clock}} Ran for {{duration}} TTFT {{duration}} {{throughput}} tok/s
+- text: {{clock}} Ran for {{duration}} Use only Cordis tools. Call cordis_stop with pluginId "snap-1". After it succeeds, reply exactly CORDIS_UI_DONE and stop. {{clock}}
+- button "Copy":
+  - img
+- status:
+  - text: "This turn failedllm-replay: script exhausted — session requested model call #7 but its script has only 6; re-record the scenario"
+  - code: UNKNOWN
+- button "Back to bottom":
+  - img
 - textbox "Message the agent"
 - button "Commands":
   - img
@@ -65,6 +94,6 @@
 - button "Select model, current DeepSeek-V4-Flash":
   - text: DeepSeek-V4-Flash
   - img
-- button "13% of context used"
+- button "0% of context used"
 - button "Send message" [disabled]
-- text: 1 turns · 4 steps LLM {{duration}} · Tool call {{duration}} TTFT avg {{duration}} · {{throughput}} tok/s Cache hit 77% Input 66.5K tok · Output 312 tok
+- text: 3 turns · 7 steps LLM {{duration}} · Tool call {{duration}} Cache hit 77% Input 66.5K tok · Output 318 tok

+ 1 - 1
apps/web/tests/workspace-management.e2e.ts

@@ -380,7 +380,7 @@ describe('web e2e: workspace management (create / rename / flat view / hover aff
     await expect.poll(() => page.getByText('Sessions', { exact: true }).count(), { timeout: 10_000 }).toBeGreaterThanOrEqual(1)
     await expect.poll(() => page.getByText('Ungrouped', { exact: true }).count(), { timeout: 5_000 }).toBe(0)
     await expect.poll(() => page.locator('[role="treeitem"]').count(), { timeout: 10_000 }).toBeGreaterThanOrEqual(1)
-    expect(await page.evaluate(() => localStorage.getItem('dsh.workspace.view.v4'))).toContain('flat')
+    expect(await page.evaluate(() => localStorage.getItem('dsh.workspace.view.v5'))).toContain('flat')
     // Persisted across reload; then restore grouped for inter-spec hygiene.
     const warningStart = tripwire.warnings.length
     await page.reload({ waitUntil: 'load' })

+ 2 - 2
docs/capability-seams.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/capability-seams.md
-capability-seams.md: 5302b42525b0394993b06f474b5f6b1237795372
-capability-seams.zh.md: 0271bdb9b4020e4cc1b6c1ef3bb8e73850085740
+capability-seams.md: a990a9dd4d92d10e37b82e6a63caa4a5a469c441
+capability-seams.zh.md: 441d9222835e67c4a9f657d2335860005934094b

+ 21 - 0
docs/capability-seams.md

@@ -185,12 +185,21 @@ flowchart LR
   svc_workflowEngine["ctx.workflowEngine<br/>Workflow script engine"]
   pkg_workflow_worker_thread["workflow-worker-thread"]
   pkg_tool_workflow["tool-workflow"]
+  pkg_lsp["lsp"]
+  svc_lsp["ctx.lsp<br/>Language-server navigation seam"]
+  pkg_lsp_local["lsp-local"]
+  pkg_tool_lsp["tool-lsp"]
+  svc_apiProxy["ctx.apiProxy<br/>Host API dispatch"]
+  pkg_cordis_host_runner["cordis-host-runner"]
+  svc_dynamicCordisRunner["ctx.dynamicCordisRunner<br/>Dynamic Cordis package host runner"]
+  svc_cordisInspect["ctx.cordisInspect<br/>Dynamic Cordis inspect registry"]
   pkg_acp --> svc_approval
   pkg_agent --> svc_agents
   pkg_agent_default_model --> svc_agentDefaultModel
   pkg_agent_loop --> svc_agentLoop
   pkg_agent_presets --> svc_agentPresets
   pkg_api_gateway --> svc_typertGateway
+  pkg_apiproxy --> svc_apiProxy
   pkg_approval --> svc_approval
   pkg_attachment --> svc_attachments
   pkg_attachment_local --> svc_attachments
@@ -202,6 +211,8 @@ flowchart LR
   pkg_compaction --> svc_compaction
   pkg_compaction_basic --> svc_compaction
   pkg_compaction_tool_result_pruner --> svc_toolResultPruner
+  pkg_cordis_host_runner --> svc_cordisInspect
+  pkg_cordis_host_runner --> svc_dynamicCordisRunner
   pkg_credentials --> svc_credentials
   pkg_credentials_local --> svc_credentials
   pkg_directory_picker --> svc_directoryPicker
@@ -220,6 +231,8 @@ flowchart LR
   pkg_llm_deepseek --> svc_llm
   pkg_llm_pi_ai --> svc_llm
   pkg_llm_replay --> svc_llm
+  pkg_lsp --> svc_lsp
+  pkg_lsp_local --> svc_lsp
   pkg_message_feedback --> svc_messageFeedback
   pkg_modules --> svc_clientModules
   pkg_permission_presets --> svc_permissionPresets
@@ -287,6 +300,7 @@ flowchart LR
   svc_agents --> pkg_acp
   svc_agents --> pkg_agent_loop
   svc_agents --> pkg_subagent_inprocess
+  svc_apiProxy --> pkg_connection
   svc_approval --> pkg_tool_bash
   svc_approval --> pkg_tools
   svc_attachments --> pkg_host_runtime
@@ -294,10 +308,12 @@ flowchart LR
   svc_clientModules --> pkg_hmr
   svc_codeRuntime --> pkg_tools
   svc_compaction --> pkg_compaction_basic
+  svc_cordisInspect --> pkg_tool_cordis
   svc_credentials --> pkg_apiproxy
   svc_credentials --> pkg_llm_deepseek
   svc_credentials --> pkg_llm_pi_ai
   svc_directoryPicker --> pkg_apiproxy
+  svc_dynamicCordisRunner --> pkg_tool_cordis
   svc_e2b --> pkg_fs_e2b
   svc_e2b --> pkg_subprocess_e2b
   svc_fs --> pkg_tool_fs
@@ -311,6 +327,7 @@ flowchart LR
   svc_jobs --> pkg_tool_terminal
   svc_llm --> pkg_agent_loop
   svc_llm --> pkg_compaction_basic
+  svc_lsp --> pkg_tool_lsp
   svc_sandbox --> pkg_bash_sandbox
   svc_sandbox --> pkg_terminal_bash
   svc_sandboxPolicy --> pkg_bash_sandbox
@@ -446,5 +463,9 @@ flowchart LR
 | `ctx.webServer` | `core` | `webserver` | - | `connection`, `modules`, `hmr` | - | Plain node:http carrier: named-route registry, index transform taps, and the static dist fallback; web-transport plugins register their own routes. |
 | `ctx.clientModules` | `core` | `modules` | - | `hmr` | - | Composes the __DSH_BOOT__ entry graph from an incremental dsh.client scan, serves plugin bundles, and notifies rebuilt/graph-changed subscribers. |
 | `ctx.workflowEngine` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | [`tool-workflow`](../packages/workflow/tool-workflow), [`tool-ralph`](../packages/workflow/tool-ralph) | - | One engine per context, as in bash, with no named-provider registry; the general workflow and fixed Ralph consumers start runs whose agent() calls fan out through ctx.subagents. |
+| `ctx.lsp` | `seam` | [`lsp`](../packages/lsp/lsp) | `lsp-local` | [`tool-lsp`](../packages/lsp/tool-lsp) | - | Provider registration and selection plus normalized query execution over exactly four operations; the seam offers no protocol escape hatch, so a backend translates into the normalized request and result. |
+| `ctx.apiProxy` | `core` | `apiproxy` | - | `connection` | - | The transport-agnostic host gateway face: it dispatches browser API calls, and each open host stream subscribes to the events it forwards rather than being pushed to through a broadcast verb. |
+| `ctx.dynamicCordisRunner` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | Owns the in-memory definition registry, the vm sandbox for host halves, and the request-run round trip; browser pages reach the same service over the wire through its remote namespace. |
+| `ctx.cordisInspect` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | Registers host inspect providers, mirrors the client provider manifest, and routes client queries through the dynamic Cordis transport. |
 
 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.

+ 21 - 0
docs/capability-seams.zh.md

@@ -187,12 +187,21 @@ flowchart LR
   svc_workflowEngine["ctx.workflowEngine<br/>Workflow script engine"]
   pkg_workflow_worker_thread["workflow-worker-thread"]
   pkg_tool_workflow["tool-workflow"]
+  pkg_lsp["lsp"]
+  svc_lsp["ctx.lsp<br/>Language-server navigation seam"]
+  pkg_lsp_local["lsp-local"]
+  pkg_tool_lsp["tool-lsp"]
+  svc_apiProxy["ctx.apiProxy<br/>Host API dispatch"]
+  pkg_cordis_host_runner["cordis-host-runner"]
+  svc_dynamicCordisRunner["ctx.dynamicCordisRunner<br/>Dynamic Cordis package host runner"]
+  svc_cordisInspect["ctx.cordisInspect<br/>Dynamic Cordis inspect registry"]
   pkg_acp --> svc_approval
   pkg_agent --> svc_agents
   pkg_agent_default_model --> svc_agentDefaultModel
   pkg_agent_loop --> svc_agentLoop
   pkg_agent_presets --> svc_agentPresets
   pkg_api_gateway --> svc_typertGateway
+  pkg_apiproxy --> svc_apiProxy
   pkg_approval --> svc_approval
   pkg_attachment --> svc_attachments
   pkg_attachment_local --> svc_attachments
@@ -204,6 +213,8 @@ flowchart LR
   pkg_compaction --> svc_compaction
   pkg_compaction_basic --> svc_compaction
   pkg_compaction_tool_result_pruner --> svc_toolResultPruner
+  pkg_cordis_host_runner --> svc_cordisInspect
+  pkg_cordis_host_runner --> svc_dynamicCordisRunner
   pkg_credentials --> svc_credentials
   pkg_credentials_local --> svc_credentials
   pkg_directory_picker --> svc_directoryPicker
@@ -222,6 +233,8 @@ flowchart LR
   pkg_llm_deepseek --> svc_llm
   pkg_llm_pi_ai --> svc_llm
   pkg_llm_replay --> svc_llm
+  pkg_lsp --> svc_lsp
+  pkg_lsp_local --> svc_lsp
   pkg_message_feedback --> svc_messageFeedback
   pkg_modules --> svc_clientModules
   pkg_permission_presets --> svc_permissionPresets
@@ -289,6 +302,7 @@ flowchart LR
   svc_agents --> pkg_acp
   svc_agents --> pkg_agent_loop
   svc_agents --> pkg_subagent_inprocess
+  svc_apiProxy --> pkg_connection
   svc_approval --> pkg_tool_bash
   svc_approval --> pkg_tools
   svc_attachments --> pkg_host_runtime
@@ -296,10 +310,12 @@ flowchart LR
   svc_clientModules --> pkg_hmr
   svc_codeRuntime --> pkg_tools
   svc_compaction --> pkg_compaction_basic
+  svc_cordisInspect --> pkg_tool_cordis
   svc_credentials --> pkg_apiproxy
   svc_credentials --> pkg_llm_deepseek
   svc_credentials --> pkg_llm_pi_ai
   svc_directoryPicker --> pkg_apiproxy
+  svc_dynamicCordisRunner --> pkg_tool_cordis
   svc_e2b --> pkg_fs_e2b
   svc_e2b --> pkg_subprocess_e2b
   svc_fs --> pkg_tool_fs
@@ -313,6 +329,7 @@ flowchart LR
   svc_jobs --> pkg_tool_terminal
   svc_llm --> pkg_agent_loop
   svc_llm --> pkg_compaction_basic
+  svc_lsp --> pkg_tool_lsp
   svc_sandbox --> pkg_bash_sandbox
   svc_sandbox --> pkg_terminal_bash
   svc_sandboxPolicy --> pkg_bash_sandbox
@@ -448,5 +465,9 @@ flowchart LR
 | `ctx.webServer` | `core` | `webserver` | - | `connection`, `modules`, `hmr` | - | 普通的 node:http 载体:具名路由注册表、索引转换 tap,以及静态 dist 回退;Web 传输插件注册自己的路由。 |
 | `ctx.clientModules` | `core` | `modules` | - | `hmr` | - | 通过增量 `dsh.client` 扫描组合 __DSH_BOOT__ 入口图,提供插件组合包,并通知重建/图变更订阅方。 |
 | `ctx.workflowEngine` | `seam` | [`workflow`](../packages/workflow/workflow) | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | [`tool-workflow`](../packages/workflow/tool-workflow), [`tool-ralph`](../packages/workflow/tool-ralph) | - | 每个上下文使用一个引擎,与 bash 相同,且没有具名提供方注册表;通用工作流与固定 Ralph 消费方启动运行,其中的 agent() 调用通过 ctx.subagents 扇出。 |
+| `ctx.lsp` | `seam` | [`lsp`](../packages/lsp/lsp) | `lsp-local` | [`tool-lsp`](../packages/lsp/tool-lsp) | - | 提供方注册与选择,加上恰好四种操作的标准化查询执行;该 seam 不提供协议逃生口,后端必须转换为标准化请求和结果。 |
+| `ctx.apiProxy` | `core` | `apiproxy` | - | `connection` | - | 与传输无关的 Host 网关接口:它分派浏览器 API 调用,每条打开的 Host 流自行订阅转发事件,而不是由广播方法向其推送。 |
+| `ctx.dynamicCordisRunner` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | 拥有内存定义注册表、Host 半的 vm 沙箱和 request-run 往返流程;浏览器页面通过其 Remote 命名空间在线访问同一服务。 |
+| `ctx.cordisInspect` | `core` | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | - | [`tool-cordis`](../packages/extensions/tool-cordis) | - | 注册 Host inspect 提供方、镜像 Client 提供方 manifest,并通过动态 Cordis 传输路由 Client 查询。 |
 
 维护模式:混合模式。服务从 Cordis 声明中发现;接口、实现和消费方角色在 `scripts/gen-doc-graphs.ts` 中分类,并设有完整性守卫。

+ 2 - 2
docs/config-catalog.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/config-catalog.md
-config-catalog.md: 09106e25600851705d102d2265354404f2369a8d
-config-catalog.zh.md: 12d7487719a553e5152ca529b30540aa7c8eaafd
+config-catalog.md: 91b8798d0235a28b2ae464ff53e6afd2c3e35d2e
+config-catalog.zh.md: 49a6a21aa337b265f990d1da409e0f05731bc34c

+ 29 - 23
docs/config-catalog.md

@@ -196,9 +196,10 @@ Source: [`packages/preset/agent-presets/src/preset.ts:52`](../packages/preset/ag
 /**
  * Bundle config: each field forwarded verbatim to the child that owns it —
  * `agents` to the agent loop (an app that pre-creates no agents, like the ACP
- * bridge, simply omits it), `includeHarnessIdentity`, `persona`, and `toolOrder`
- * to the system-prompt plugin (the fixed opener, deployment persona, and explicit
- * model-facing tool order), the `tools` object to the tool registry (its presentation `mode`),
+ * bridge, simply omits it), `includeHarnessIdentity`, `includeRuntimeContext`,
+ * `persona`, and `toolOrder` to the system-prompt plugin (the fixed opener,
+ * dynamic-context policy, deployment persona, and explicit model-facing tool
+ * order), the `tools` object to the tool registry (its presentation `mode`),
  * `dshHome` to bash environment and local skill discovery, `sessionTitle` to
  * the fallback title service, `skills` to the
  * skill registry/local provider/tool consumer, `workspaceContext` to the
@@ -222,6 +223,8 @@ export interface Config {
   maxParallelToolCalls?: AgentLoopConfig['maxParallelToolCalls']
   /** Whether the system prompt includes the fixed Harness identity (default true). */
   includeHarnessIdentity?: SystemPromptConfig['includeHarnessIdentity']
+  /** Whether model history includes dynamic runtime-context snapshots (default true). */
+  includeRuntimeContext?: SystemPromptConfig['includeRuntimeContext']
   /** The deployment persona (see dsh-system-prompt's `Config`). */
   persona?: SystemPromptConfig['persona']
   /** The explicit model-facing tool order (see dsh-system-prompt's `Config`). */
@@ -275,7 +278,7 @@ export interface GoalConfig {
 
 Depends on: [`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`GoalDomainConfig`](#deepseek-aidsh-goal) · [`InvariantConfig`](#deepseek-aidsh-invariants) · [`JobsConfig`](#deepseek-aidsh-jobs-local) · [`SessionTitleConfig`](#deepseek-aidsh-session-title) · [`SkillFileSystem`](../packages/skill/skill-filesystem/src/index.ts) · [`SkillRegistryConfig`](#deepseek-aidsh-skill) · [`SystemPromptConfig`](#deepseek-aidsh-system-prompt) · [`toolBash`](../packages/shell/tool-bash/src/index.ts) · [`toolGoal`](../packages/goal/tool-goal/src/index.ts) · [`toolJobs`](../packages/jobs/tool-jobs/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools) · [`toolSkill`](../packages/skill/tool-skill/src/index.ts) · [`workspaceContext`](../packages/context/agent-instructions/src/index.ts)
 
-Source: [`packages/examples/agent-spine-demo/src/index.ts:91`](../packages/examples/agent-spine-demo/src/index.ts)
+Source: [`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts)
 
 ## `@deepseek-ai/dsh-agent-tool-presentation`
 
@@ -496,6 +499,20 @@ export interface ToolResultPruneConfig {
 
 Source: [`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts)
 
+## `@deepseek-ai/dsh-cordis-host-runner`
+
+Requires: `tools`
+
+```ts config-catalog
+/** Runner configuration. */
+export interface Config {
+  /** Maximum synchronous VM evaluation time in milliseconds. */
+  vmTimeoutMs?: number
+}
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts)
+
 ## `@deepseek-ai/dsh-credentials-local`
 
 ```ts config-catalog
@@ -1246,6 +1263,8 @@ export interface Config {
   text: string
   /** Make this persona the complete system prompt, suppressing every other section. */
   complete?: boolean
+  /** Suppress dynamic runtime-context snapshots for this persona's agent scope. */
+  includeRuntimeContext?: boolean
 }
 ```
 
@@ -2049,6 +2068,8 @@ Source: [`packages/e2b/subprocess-e2b/src/index.ts:25`](../packages/e2b/subproce
 export interface Config {
   /** Include the fixed DeepSeek Harness identity before the deployment persona (default true). */
   includeHarnessIdentity?: boolean
+  /** Include dynamic runtime-context snapshots in model history (default true). */
+  includeRuntimeContext?: boolean
   /**
    * Deployment-wide order-0 persona template. A scoped section named
    * `deployment:persona` shadows it; `{{variable}}` references are strict.
@@ -2186,24 +2207,6 @@ export interface Config {
 
 Source: [`packages/shell/tool-bash-persistent/src/index.ts:437`](../packages/shell/tool-bash-persistent/src/index.ts)
 
-## `@deepseek-ai/dsh-tool-cordis`
-
-Requires: `tools`
-
-```ts config-catalog
-/** Config for the tool-cordis plugin: the sandbox evaluation bound. */
-export interface Config {
-  /**
-   * Milliseconds the SYNCHRONOUS portion of mount code may run in the vm
-   * before evaluation is aborted (default 5000). An async body escapes this
-   * bound — see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md for the trust stance.
-   */
-  vmTimeoutMs?: number
-}
-```
-
-Source: [`packages/extensions/tool-cordis/src/index.ts:25`](../packages/extensions/tool-cordis/src/index.ts)
-
 ## `@deepseek-ai/dsh-tool-fs`
 
 Requires: `tools` · `fs` · `systemPrompt`
@@ -2834,6 +2837,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
 - `@deepseek-ai/dsh-client-ui-agent-preset` ([`packages/client/ui-agent-preset/src/index.ts`](../packages/client/ui-agent-preset/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-commands` ([`packages/client/ui-commands/src/index.ts`](../packages/client/ui-commands/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-conversation` ([`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts))
+- `@deepseek-ai/dsh-client-ui-cordis` ([`packages/extensions/ui-cordis/src/index.ts`](../packages/extensions/ui-cordis/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-deliverables` — requires `systemPrompt` ([`packages/client/ui-deliverables/src/index.ts`](../packages/client/ui-deliverables/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-directory-picker-browse` ([`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-directory-picker-native` ([`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts))
@@ -2863,6 +2867,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
 - `@deepseek-ai/dsh-command-feedback` — requires `commands` ([`packages/feedback/command-feedback/src/index.ts`](../packages/feedback/command-feedback/src/index.ts))
 - `@deepseek-ai/dsh-command-goal` — requires `commands` · `goals` ([`packages/goal/command-goal/src/index.ts`](../packages/goal/command-goal/src/index.ts))
 - `@deepseek-ai/dsh-commands` ([`packages/interaction/commands/src/index.ts`](../packages/interaction/commands/src/index.ts))
+- `@deepseek-ai/dsh-cordis-client-runner` ([`packages/extensions/cordis-client-runner/src/index.ts`](../packages/extensions/cordis-client-runner/src/index.ts))
 - `@deepseek-ai/dsh-fs-e2b` — requires `e2b` ([`packages/e2b/fs-e2b/src/index.ts`](../packages/e2b/fs-e2b/src/index.ts))
 - `@deepseek-ai/dsh-fs-observation-policy` ([`packages/fs/fs-observation-policy/src/index.ts`](../packages/fs/fs-observation-policy/src/index.ts))
 - `@deepseek-ai/dsh-goal-round-driver` — requires `agents` · `goals` · `sessions` ([`packages/goal/goal-round-driver/src/index.ts`](../packages/goal/goal-round-driver/src/index.ts))
@@ -2874,7 +2879,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
 - `@deepseek-ai/dsh-schedule` — requires `agents` · `sessions` · `tools` · `sessionPersistence` ([`packages/schedule/schedule/src/index.ts`](../packages/schedule/schedule/src/index.ts))
 - `@deepseek-ai/dsh-session` ([`packages/core/session/src/index.ts`](../packages/core/session/src/index.ts))
 - `@deepseek-ai/dsh-session-checkpoint-policy` — requires `llm` · `sessionPersistence` · `sessions` · `tools` ([`packages/session/session-checkpoint-policy/src/index.ts`](../packages/session/session-checkpoint-policy/src/index.ts))
-- `@deepseek-ai/dsh-session-log-download` — requires `commands` ([`packages/session-query/session-log-download/src/index.ts`](../packages/session-query/session-log-download/src/index.ts))
+- `@deepseek-ai/dsh-session-log-export` — requires `commands` ([`packages/session-query/session-log-export/src/index.ts`](../packages/session-query/session-log-export/src/index.ts))
 - `@deepseek-ai/dsh-session-projection` ([`packages/session/session-projection/src/index.ts`](../packages/session/session-projection/src/index.ts))
 - `@deepseek-ai/dsh-session-stats` — requires `sessionProjections` ([`packages/session/session-stats/src/index.ts`](../packages/session/session-stats/src/index.ts))
 - `@deepseek-ai/dsh-skill-badge` — requires `skills` ([`packages/skill/skill-badge/src/index.ts`](../packages/skill/skill-badge/src/index.ts))
@@ -2884,6 +2889,7 @@ These load from a `cordis.yml` entry with no `config:` block; they declare no co
 - `@deepseek-ai/dsh-terminal` ([`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts))
 - `@deepseek-ai/dsh-tool-ask-user` — requires `tools` · `userQuestions` ([`packages/interaction/tool-ask-user/src/index.ts`](../packages/interaction/tool-ask-user/src/index.ts))
 - `@deepseek-ai/dsh-tool-call-timeout-policy` — requires `tools` ([`packages/guard/timeout-policy/src/index.ts`](../packages/guard/timeout-policy/src/index.ts))
+- `@deepseek-ai/dsh-tool-cordis` — requires `tools` · `systemPrompt` · `dynamicCordisRunner` · `cordisInspect` ([`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/tool-cordis/src/index.ts))
 - `@deepseek-ai/dsh-tool-subagent-control` — requires `tools` · `subagents` ([`packages/subagent/tool-subagent-control/src/index.ts`](../packages/subagent/tool-subagent-control/src/index.ts))
 - `@deepseek-ai/dsh-user-questions` ([`packages/interaction/user-questions/src/index.ts`](../packages/interaction/user-questions/src/index.ts))
 - `@deepseek-ai/dsh-workspace` — requires `storageDomain` · `sessionPersistence` ([`packages/workspace/workspace/src/index.ts`](../packages/workspace/workspace/src/index.ts))

+ 29 - 22
docs/config-catalog.zh.md

@@ -198,9 +198,10 @@ export type PresetTrust = 'system' | 'user'
 /**
  * Bundle config: each field forwarded verbatim to the child that owns it —
  * `agents` to the agent loop (an app that pre-creates no agents, like the ACP
- * bridge, simply omits it), `includeHarnessIdentity`, `persona`, and `toolOrder`
- * to the system-prompt plugin (the fixed opener, deployment persona, and explicit
- * model-facing tool order), the `tools` object to the tool registry (its presentation `mode`),
+ * bridge, simply omits it), `includeHarnessIdentity`, `includeRuntimeContext`,
+ * `persona`, and `toolOrder` to the system-prompt plugin (the fixed opener,
+ * dynamic-context policy, deployment persona, and explicit model-facing tool
+ * order), the `tools` object to the tool registry (its presentation `mode`),
  * `dshHome` to bash environment and local skill discovery, `sessionTitle` to
  * the fallback title service, `skills` to the
  * skill registry/local provider/tool consumer, `workspaceContext` to the
@@ -224,6 +225,8 @@ export interface Config {
   maxParallelToolCalls?: AgentLoopConfig['maxParallelToolCalls']
   /** Whether the system prompt includes the fixed Harness identity (default true). */
   includeHarnessIdentity?: SystemPromptConfig['includeHarnessIdentity']
+  /** Whether model history includes dynamic runtime-context snapshots (default true). */
+  includeRuntimeContext?: SystemPromptConfig['includeRuntimeContext']
   /** The deployment persona (see dsh-system-prompt's `Config`). */
   persona?: SystemPromptConfig['persona']
   /** The explicit model-facing tool order (see dsh-system-prompt's `Config`). */
@@ -277,7 +280,7 @@ export interface GoalConfig {
 
 依赖:[`AgentLoopConfig`](#deepseek-aidsh-agent-loop) · [`GoalDomainConfig`](#deepseek-aidsh-goal) · [`InvariantConfig`](#deepseek-aidsh-invariants) · [`JobsConfig`](#deepseek-aidsh-jobs-local) · [`SessionTitleConfig`](#deepseek-aidsh-session-title) · [`SkillFileSystem`](../packages/skill/skill-filesystem/src/index.ts) · [`SkillRegistryConfig`](#deepseek-aidsh-skill) · [`SystemPromptConfig`](#deepseek-aidsh-system-prompt) · [`toolBash`](../packages/shell/tool-bash/src/index.ts) · [`toolGoal`](../packages/goal/tool-goal/src/index.ts) · [`toolJobs`](../packages/jobs/tool-jobs/src/index.ts) · [`ToolsConfig`](#deepseek-aidsh-tools) · [`toolSkill`](../packages/skill/tool-skill/src/index.ts) · [`workspaceContext`](../packages/context/agent-instructions/src/index.ts)
 
-来源:[`packages/examples/agent-spine-demo/src/index.ts:91`](../packages/examples/agent-spine-demo/src/index.ts)
+来源:[`packages/examples/agent-spine-demo/src/index.ts:92`](../packages/examples/agent-spine-demo/src/index.ts)
 
 ## `@deepseek-ai/dsh-agent-tool-presentation`
 
@@ -498,6 +501,20 @@ export interface ToolResultPruneConfig {
 
 来源:[`packages/compaction/compaction-tool-result-pruner/src/types.ts:4`](../packages/compaction/compaction-tool-result-pruner/src/types.ts)
 
+## `@deepseek-ai/dsh-cordis-host-runner`
+
+需要:`tools`
+
+```ts config-catalog
+/** Runner configuration. */
+export interface Config {
+  /** Maximum synchronous VM evaluation time in milliseconds. */
+  vmTimeoutMs?: number
+}
+```
+
+来源:[`packages/extensions/cordis-host-runner/src/index.ts:88`](../packages/extensions/cordis-host-runner/src/index.ts)
+
 ## `@deepseek-ai/dsh-credentials-local`
 
 ```ts config-catalog
@@ -1248,6 +1265,8 @@ export interface Config {
   text: string
   /** Make this persona the complete system prompt, suppressing every other section. */
   complete?: boolean
+  /** Suppress dynamic runtime-context snapshots for this persona's agent scope. */
+  includeRuntimeContext?: boolean
 }
 ```
 
@@ -2051,6 +2070,8 @@ export interface Config {
 export interface Config {
   /** Include the fixed DeepSeek Harness identity before the deployment persona (default true). */
   includeHarnessIdentity?: boolean
+  /** Include dynamic runtime-context snapshots in model history (default true). */
+  includeRuntimeContext?: boolean
   /**
    * Deployment-wide order-0 persona template. A scoped section named
    * `deployment:persona` shadows it; `{{variable}}` references are strict.
@@ -2188,23 +2209,6 @@ export interface Config {
 
 来源:[`packages/shell/tool-bash-persistent/src/index.ts:437`](../packages/shell/tool-bash-persistent/src/index.ts)
 
-## `@deepseek-ai/dsh-tool-cordis`
-
-需要:`tools`
-
-```ts config-catalog
-/** Config for the tool-cordis plugin: the sandbox evaluation bound. */
-export interface Config {
-  /**
-   * Milliseconds the SYNCHRONOUS portion of mount code may run in the vm
-   * before evaluation is aborted (default 5000). An async body escapes this
-   * bound — see .agents/notes/implemented/feature/2026-07-08-self-referential-cordis-toolset.md for the trust stance.
-   */
-  vmTimeoutMs?: number
-}
-```
-
-来源:[`packages/extensions/tool-cordis/src/index.ts:25`](../packages/extensions/tool-cordis/src/index.ts)
 ## `@deepseek-ai/dsh-tool-fs`
 
 需要:`tools` · `fs` · `systemPrompt`
@@ -2835,6 +2839,7 @@ export interface Config {
 - `@deepseek-ai/dsh-client-ui-agent-preset`([`packages/client/ui-agent-preset/src/index.ts`](../packages/client/ui-agent-preset/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-commands`([`packages/client/ui-commands/src/index.ts`](../packages/client/ui-commands/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-conversation`([`packages/client/ui-conversation/src/index.ts`](../packages/client/ui-conversation/src/index.ts))
+- `@deepseek-ai/dsh-client-ui-cordis`([`packages/extensions/ui-cordis/src/index.ts`](../packages/extensions/ui-cordis/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-deliverables` — 需要 `systemPrompt`([`packages/client/ui-deliverables/src/index.ts`](../packages/client/ui-deliverables/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-directory-picker-browse`([`packages/client/ui-directory-picker-browse/src/index.ts`](../packages/client/ui-directory-picker-browse/src/index.ts))
 - `@deepseek-ai/dsh-client-ui-directory-picker-native`([`packages/client/ui-directory-picker-native/src/index.ts`](../packages/client/ui-directory-picker-native/src/index.ts))
@@ -2864,6 +2869,7 @@ export interface Config {
 - `@deepseek-ai/dsh-command-feedback` — 需要 `commands`([`packages/feedback/command-feedback/src/index.ts`](../packages/feedback/command-feedback/src/index.ts))
 - `@deepseek-ai/dsh-command-goal` — 需要 `commands` · `goals`([`packages/goal/command-goal/src/index.ts`](../packages/goal/command-goal/src/index.ts))
 - `@deepseek-ai/dsh-commands`([`packages/interaction/commands/src/index.ts`](../packages/interaction/commands/src/index.ts))
+- `@deepseek-ai/dsh-cordis-client-runner`([`packages/extensions/cordis-client-runner/src/index.ts`](../packages/extensions/cordis-client-runner/src/index.ts))
 - `@deepseek-ai/dsh-fs-e2b` — 需要 `e2b`([`packages/e2b/fs-e2b/src/index.ts`](../packages/e2b/fs-e2b/src/index.ts))
 - `@deepseek-ai/dsh-fs-observation-policy`([`packages/fs/fs-observation-policy/src/index.ts`](../packages/fs/fs-observation-policy/src/index.ts))
 - `@deepseek-ai/dsh-goal-round-driver` — 需要 `agents` · `goals` · `sessions`([`packages/goal/goal-round-driver/src/index.ts`](../packages/goal/goal-round-driver/src/index.ts))
@@ -2875,7 +2881,7 @@ export interface Config {
 - `@deepseek-ai/dsh-schedule` — 需要 `agents` · `sessions` · `tools` · `sessionPersistence`([`packages/schedule/schedule/src/index.ts`](../packages/schedule/schedule/src/index.ts))
 - `@deepseek-ai/dsh-session`([`packages/core/session/src/index.ts`](../packages/core/session/src/index.ts))
 - `@deepseek-ai/dsh-session-checkpoint-policy` — 需要 `llm` · `sessionPersistence` · `sessions` · `tools`([`packages/session/session-checkpoint-policy/src/index.ts`](../packages/session/session-checkpoint-policy/src/index.ts))
-- `@deepseek-ai/dsh-session-log-download` — 需要 `commands`([`packages/session-query/session-log-download/src/index.ts`](../packages/session-query/session-log-download/src/index.ts))
+- `@deepseek-ai/dsh-session-log-export` — 需要 `commands`([`packages/session-query/session-log-export/src/index.ts`](../packages/session-query/session-log-export/src/index.ts))
 - `@deepseek-ai/dsh-session-projection`([`packages/session/session-projection/src/index.ts`](../packages/session/session-projection/src/index.ts))
 - `@deepseek-ai/dsh-session-stats` — 需要 `sessionProjections`([`packages/session/session-stats/src/index.ts`](../packages/session/session-stats/src/index.ts))
 - `@deepseek-ai/dsh-skill-badge` — 需要 `skills`([`packages/skill/skill-badge/src/index.ts`](../packages/skill/skill-badge/src/index.ts))
@@ -2885,6 +2891,7 @@ export interface Config {
 - `@deepseek-ai/dsh-terminal`([`packages/terminal/terminal/src/index.ts`](../packages/terminal/terminal/src/index.ts))
 - `@deepseek-ai/dsh-tool-ask-user` — 需要 `tools` · `userInteraction`([`packages/interaction/tool-ask-user/src/index.ts`](../packages/interaction/tool-ask-user/src/index.ts))
 - `@deepseek-ai/dsh-tool-call-timeout-policy` — 需要 `tools`([`packages/guard/timeout-policy/src/index.ts`](../packages/guard/timeout-policy/src/index.ts))
+- `@deepseek-ai/dsh-tool-cordis` — 需要 `tools` · `systemPrompt` · `dynamicCordisRunner` · `cordisInspect`([`packages/extensions/tool-cordis/src/index.ts`](../packages/extensions/tool-cordis/src/index.ts))
 - `@deepseek-ai/dsh-tool-subagent-control` — 需要 `tools` · `subagents`([`packages/subagent/tool-subagent-control/src/index.ts`](../packages/subagent/tool-subagent-control/src/index.ts))
 - `@deepseek-ai/dsh-user-questions`([`packages/interaction/user-questions/src/index.ts`](../packages/interaction/user-questions/src/index.ts))
 - `@deepseek-ai/dsh-workspace` — 需要 `storageDomain` · `sessionPersistence`([`packages/workspace/workspace/src/index.ts`](../packages/workspace/workspace/src/index.ts))

+ 1 - 1
docs/cordis-api/inherited.md

@@ -16,7 +16,7 @@ This file is GENERATED from source (`scripts/gen-cordis-catalog.ts`) and verifie
 - `ctx.get / ctx.set / ctx.provide / ctx.accessor / ctx.mixin` — Low-level service-store access and binding. ([`vendor/cordis/src/reflect.ts:7`](../../vendor/cordis/src/reflect.ts))
 - `ctx.extend / ctx.isolate / ctx.intercept` — Derive a child context (scoped services / isolation / interception). ([`vendor/cordis/src/context.ts:42`](../../vendor/cordis/src/context.ts))
 - `ctx.root / ctx.scope / ctx.fiber / ctx.registry / ctx.reflect / ctx.events / ctx.logger` — Ambient handles onto the running context graph. ([`vendor/cordis/src/context.ts:16`](../../vendor/cordis/src/context.ts))
-- `ctx.timer (+ interval / timeout / throttle / debounce / setTimeout / setInterval)` — Disposable timer helpers. The `timer` key is provided at runtime; the six helpers are mixed onto ctx directly (declared via Pick). ([`vendor/timer/src/index.ts:4`](../../vendor/timer/src/index.ts))
+- `ctx.timer (+ interval / timeout / throttle / debounce)` — Disposable timer helpers. The `timer` key is provided at runtime; the four supported helpers are mixed onto ctx directly (declared via Pick). ([`vendor/timer/src/index.ts:4`](../../vendor/timer/src/index.ts))
 - `ctx.loader` — The config Loader that booted the app (present under the loader). ([`vendor/loader/src/index.ts:30`](../../vendor/loader/src/index.ts))
 - `ctx.hmr` — The hot-module-reload watcher (present under the hmr plugin). ([`vendor/hmr/src/index.ts:15`](../../vendor/hmr/src/index.ts))
 

+ 2 - 2
docs/event-producer-consumer.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/event-producer-consumer.md
-event-producer-consumer.md: ad5366d41fa802f351b876c438cce5728a312f4c
-event-producer-consumer.zh.md: b25673cbe975525fed4112910fbc98425e346eb9
+event-producer-consumer.md: 6a79e6f7ce5addc64b10efa8da7a886dcfb36dc2
+event-producer-consumer.zh.md: f7576a8e28e4f1db2c65c324595c05c98b8fe488

+ 7 - 1
docs/event-producer-consumer.md

@@ -15,7 +15,7 @@ This matrix shows which packages dispatch each harness-owned event and which pac
 | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:197`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs) |
 | `agent/inbox/discarded` | `emit` | [`packages/core/agent/src/runtime-types.ts:205`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent) |
 | `agent/inbox/inserted` | `emit` | [`packages/core/agent/src/runtime-types.ts:186`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) |
-| `agent/pre-step` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:231`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent-instructions`](../packages/context/agent-instructions), [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-skill`](../packages/skill/tool-skill) |
+| `agent/pre-step` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:231`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent-instructions`](../packages/context/agent-instructions), [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-skill`](../packages/skill/tool-skill) |
 | `agent/request` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:244`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent`](../packages/core/agent) |
 | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:260`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`llm-retry`](../packages/llm/llm-retry) |
 | `agent/session-start` | `emit` | [`packages/core/agent/src/runtime-types.ts:217`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
@@ -23,6 +23,12 @@ This matrix shows which packages dispatch each harness-owned event and which pac
 | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:278`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
 | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/index.ts:30`](../packages/interaction/user-approval/src/index.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `apiproxy` |
 | `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:72`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `apiproxy` |
+| `cordis/dynamic-package` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:379`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/dynamic-retract` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:385`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/inspect-query` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:391`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/inspect-query-resolved` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:397`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/request-run` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:367`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/request-run-resolved` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:373`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
 | `credentials/updated` | `emit` | [`packages/credentials/credentials/src/types.ts:29`](../packages/credentials/credentials/src/types.ts) | [`credentials`](../packages/credentials/credentials) (`events.dispatch`) | `apiproxy`, [`credentials`](../packages/credentials/credentials) |
 | `domain/changed` | `emit` | [`packages/storage/storage-domain/src/events.ts:46`](../packages/storage/storage-domain/src/events.ts) | [`storage-domain`](../packages/storage/storage-domain) (`emit`) | `apiproxy`, [`storage-domain`](../packages/storage/storage-domain), [`workspace`](../packages/workspace/workspace) |
 | `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:66`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) |

+ 7 - 1
docs/event-producer-consumer.zh.md

@@ -17,7 +17,7 @@
 | `agent/inbox/claimed` | `emit` | [`packages/core/agent/src/runtime-types.ts:197`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`acp`](../packages/acp/acp), [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent), [`tool-jobs`](../packages/jobs/tool-jobs) |
 | `agent/inbox/discarded` | `emit` | [`packages/core/agent/src/runtime-types.ts:205`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver), [`subagent`](../packages/subagent/subagent) |
 | `agent/inbox/inserted` | `emit` | [`packages/core/agent/src/runtime-types.ts:186`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emit`) | [`goal-round-driver`](../packages/goal/goal-round-driver) |
-| `agent/pre-step` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:231`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent-instructions`](../packages/context/agent-instructions), [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-skill`](../packages/skill/tool-skill) |
+| `agent/pre-step` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:231`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent-instructions`](../packages/context/agent-instructions), [`compaction-basic`](../packages/compaction/compaction-basic), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex), [`plan-mode`](../packages/plan/plan-mode), [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver), [`time-context`](../packages/context/time-context), [`tmux-context`](../packages/context/tmux-context), [`tool-cordis`](../packages/extensions/tool-cordis), [`tool-skill`](../packages/skill/tool-skill) |
 | `agent/request` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:244`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`agent`](../packages/core/agent) |
 | `agent/request-error` | `waterfall` | [`packages/core/agent/src/runtime-types.ts:260`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`waterfall`) | [`compaction-basic`](../packages/compaction/compaction-basic), [`llm-retry`](../packages/llm/llm-retry) |
 | `agent/session-start` | `emit` | [`packages/core/agent/src/runtime-types.ts:217`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`emitAgentEvent`) | [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
@@ -25,6 +25,12 @@
 | `agent/turn-stopping` | `serial` | [`packages/core/agent/src/runtime-types.ts:278`](../packages/core/agent/src/runtime-types.ts) | [`agent-loop`](../packages/core/agent-loop) (`serial`) | [`hooks-claude-code`](../packages/hooks/hooks-claude-code), [`hooks-codex`](../packages/hooks/hooks-codex) |
 | `approval/request` | `waterfall` | [`packages/interaction/user-approval/src/index.ts:30`](../packages/interaction/user-approval/src/index.ts) | [`user-approval`](../packages/interaction/user-approval) (`waterfall`) | [`acp`](../packages/acp/acp), `apiproxy` |
 | `commands/change` | `emit` | [`packages/interaction/commands/src/types.ts:72`](../packages/interaction/commands/src/types.ts) | [`commands`](../packages/interaction/commands) (`events.dispatch`) | `apiproxy` |
+| `cordis/dynamic-package` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:379`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/dynamic-retract` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:385`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/inspect-query` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:391`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/inspect-query-resolved` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:397`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/request-run` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:367`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
+| `cordis/request-run-resolved` | `emit` | [`packages/extensions/cordis-host-runner/src/types.ts:373`](../packages/extensions/cordis-host-runner/src/types.ts) | [`cordis-host-runner`](../packages/extensions/cordis-host-runner) (`emit`) | `apiproxy` |
 | `credentials/updated` | `emit` | [`packages/credentials/credentials/src/types.ts:29`](../packages/credentials/credentials/src/types.ts) | [`credentials`](../packages/credentials/credentials) (`events.dispatch`) | `apiproxy`, [`credentials`](../packages/credentials/credentials) |
 | `domain/changed` | `emit` | [`packages/storage/storage-domain/src/events.ts:46`](../packages/storage/storage-domain/src/events.ts) | [`storage-domain`](../packages/storage/storage-domain) (`emit`) | `apiproxy`, [`storage-domain`](../packages/storage/storage-domain), [`workspace`](../packages/workspace/workspace) |
 | `fs/edit-intent` | `waterfall` | [`packages/fs/fs/src/index.ts:66`](../packages/fs/fs/src/index.ts) | [`tool-fs`](../packages/fs/tool-fs) (`waterfall`), [`tool-str-replace-editor`](../packages/fs/tool-str-replace-editor) (`waterfall`) | [`fs-observation-policy`](../packages/fs/fs-observation-policy) |

+ 2 - 2
docs/module-graph.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/module-graph.md
-module-graph.md: 3aa3efd323836e48e79b22018f8c85a1869a22f2
-module-graph.zh.md: 438ac5208e3471ac11286a30cd82966f481a8de9
+module-graph.md: b7f68c8204c19ab3ea6d169fb68c1ce651e57471
+module-graph.zh.md: 472dcc06425e1c514cf8e07cd6e55bccdabe976e

+ 118 - 79
docs/module-graph.md

@@ -92,7 +92,7 @@ flowchart TD
     pkg_hooks_codex["hooks-codex"]
   end
   subgraph group_session_query["packages/session-query"]
-    pkg_session_log_download["session-log-download"]
+    pkg_session_log_export["session-log-export"]
     pkg_session_query["session-query"]
     pkg_session_query_sqlite["session-query-sqlite"]
     pkg_tool_session_query["tool-session-query"]
@@ -189,6 +189,9 @@ flowchart TD
     pkg_sdk_jsonrpc_demo["sdk-jsonrpc-demo"]
   end
   subgraph group_extensions["packages/extensions"]
+    pkg_client_ui_cordis["client-ui-cordis"]
+    pkg_cordis_client_runner["cordis-client-runner"]
+    pkg_cordis_host_runner["cordis-host-runner"]
     pkg_tool_cordis["tool-cordis"]
   end
   subgraph group_feedback["packages/feedback"]
@@ -638,20 +641,6 @@ flowchart TD
   pkg_acp --> pkg_invariants
   pkg_acp --> pkg_session
   pkg_acp --> pkg_user_approval
-  pkg_api_remotes --> pkg_agent
-  pkg_api_remotes --> pkg_agent_presets
-  pkg_api_remotes --> pkg_api_gateway
-  pkg_api_remotes --> pkg_commands
-  pkg_api_remotes --> pkg_credentials
-  pkg_api_remotes --> pkg_goal
-  pkg_api_remotes --> pkg_host_plugin_inventory
-  pkg_api_remotes --> pkg_invariants
-  pkg_api_remotes --> pkg_llm
-  pkg_api_remotes --> pkg_message_feedback
-  pkg_api_remotes --> pkg_session
-  pkg_api_remotes --> pkg_session_persistence
-  pkg_api_remotes --> pkg_settings
-  pkg_api_remotes --> pkg_typert_registry
   pkg_headless --> pkg_agent
   pkg_headless --> pkg_agent_default_model
   pkg_headless --> pkg_invariants
@@ -674,8 +663,6 @@ flowchart TD
   pkg_command_feedback --> pkg_invariants
   pkg_command_feedback --> pkg_session
   pkg_command_feedback --> pkg_session_telemetry
-  pkg_host_apiproxy --> pkg_agent_presets
-  pkg_host_apiproxy --> pkg_invariants
   pkg_permission_presets --> pkg_commands
   pkg_permission_presets --> pkg_invariants
   pkg_permission_presets --> pkg_sandbox
@@ -834,10 +821,6 @@ flowchart TD
   pkg_tool_session_query --> pkg_system_prompt
   pkg_tool_session_query --> pkg_timeout
   pkg_tool_session_query --> pkg_tools
-  pkg_client_runtime --> pkg_api_remotes
-  pkg_client_runtime --> pkg_invariants
-  pkg_client_runtime --> pkg_typert_protocol
-  pkg_client_runtime --> pkg_typert_registry
   pkg_command_compact --> pkg_commands
   pkg_command_compact --> pkg_compaction
   pkg_command_compact --> pkg_invariants
@@ -855,9 +838,14 @@ flowchart TD
   pkg_session_reference --> pkg_output_retention
   pkg_session_reference --> pkg_session
   pkg_session_reference --> pkg_session_query
-  pkg_tool_cordis --> pkg_invariants
-  pkg_tool_cordis --> pkg_scope
-  pkg_tool_cordis --> pkg_tools
+  pkg_cordis_host_runner --> pkg_agent
+  pkg_cordis_host_runner --> pkg_brand
+  pkg_cordis_host_runner --> pkg_invariants
+  pkg_cordis_host_runner --> pkg_llm
+  pkg_cordis_host_runner --> pkg_scope
+  pkg_cordis_host_runner --> pkg_session
+  pkg_cordis_host_runner --> pkg_tools
+  pkg_cordis_host_runner --> pkg_typert_protocol
   pkg_repeat_tool_reminder --> pkg_agent
   pkg_repeat_tool_reminder --> pkg_invariants
   pkg_repeat_tool_reminder --> pkg_tools
@@ -1011,29 +999,40 @@ flowchart TD
   pkg_hooks_claude_code --> pkg_session_persistence
   pkg_hooks_claude_code --> pkg_subagent
   pkg_hooks_claude_code --> pkg_tools
+  pkg_api_remotes --> pkg_agent
+  pkg_api_remotes --> pkg_agent_presets
+  pkg_api_remotes --> pkg_api_gateway
+  pkg_api_remotes --> pkg_commands
+  pkg_api_remotes --> pkg_cordis_host_runner
+  pkg_api_remotes --> pkg_credentials
+  pkg_api_remotes --> pkg_goal
+  pkg_api_remotes --> pkg_host_plugin_inventory
+  pkg_api_remotes --> pkg_invariants
+  pkg_api_remotes --> pkg_llm
+  pkg_api_remotes --> pkg_message_feedback
+  pkg_api_remotes --> pkg_session
+  pkg_api_remotes --> pkg_session_persistence
+  pkg_api_remotes --> pkg_settings
+  pkg_api_remotes --> pkg_typert_registry
   pkg_web_app --> pkg_invariants
   pkg_web_app --> pkg_shell_env
   pkg_web_app --> pkg_system_prompt
-  pkg_client_ui_settings --> pkg_api_remotes
-  pkg_client_ui_settings --> pkg_client_connection
-  pkg_client_ui_settings --> pkg_client_runtime
-  pkg_client_ui_settings --> pkg_client_schema_form
-  pkg_client_ui_settings --> pkg_client_ui_slots
-  pkg_client_ui_settings --> pkg_invariants
-  pkg_client_ui_settings --> pkg_settings
-  pkg_client_ui_settings_models --> pkg_api_remotes
-  pkg_client_ui_settings_models --> pkg_client_connection
-  pkg_client_ui_settings_models --> pkg_client_runtime
-  pkg_client_ui_settings_models --> pkg_client_schema_form
-  pkg_client_ui_settings_models --> pkg_client_ui_primitives
-  pkg_client_ui_settings_models --> pkg_client_ui_slots
-  pkg_client_ui_settings_models --> pkg_client_web_react
-  pkg_client_ui_settings_models --> pkg_invariants
   pkg_compaction_tool_result_pruner --> pkg_compaction
   pkg_compaction_tool_result_pruner --> pkg_invariants
   pkg_compaction_tool_result_pruner --> pkg_llm
   pkg_compaction_tool_result_pruner --> pkg_session
   pkg_compaction_tool_result_pruner --> pkg_token_meter
+  pkg_tool_cordis --> pkg_agent
+  pkg_tool_cordis --> pkg_cordis_host_runner
+  pkg_tool_cordis --> pkg_invariants
+  pkg_tool_cordis --> pkg_llm
+  pkg_tool_cordis --> pkg_scope
+  pkg_tool_cordis --> pkg_session
+  pkg_tool_cordis --> pkg_system_prompt
+  pkg_tool_cordis --> pkg_tools
+  pkg_host_apiproxy --> pkg_agent_presets
+  pkg_host_apiproxy --> pkg_cordis_host_runner
+  pkg_host_apiproxy --> pkg_invariants
   pkg_sdk_protocol --> pkg_invariants
   pkg_sdk_protocol --> pkg_llm
   pkg_sdk_protocol --> pkg_session
@@ -1060,11 +1059,6 @@ flowchart TD
   pkg_tool_pwsh --> pkg_system_prompt
   pkg_tool_pwsh --> pkg_tools
   pkg_tool_pwsh --> pkg_user_approval
-  pkg_client_test_runtime --> pkg_client_runtime
-  pkg_client_test_runtime --> pkg_client_ui_slots
-  pkg_client_test_runtime --> pkg_client_web_react
-  pkg_client_test_runtime --> pkg_host_apiproxy
-  pkg_client_test_runtime --> pkg_invariants
   pkg_tool_ralph --> pkg_agent
   pkg_tool_ralph --> pkg_invariants
   pkg_tool_ralph --> pkg_llm
@@ -1095,13 +1089,10 @@ flowchart TD
   pkg_subagent_spawn_in_process --> pkg_invariants
   pkg_subagent_spawn_in_process --> pkg_subagent
   pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
-  pkg_client_locale --> pkg_api_remotes
-  pkg_client_locale --> pkg_client_connection
-  pkg_client_locale --> pkg_client_runtime
-  pkg_client_locale --> pkg_client_ui_primitives
-  pkg_client_locale --> pkg_client_ui_settings
-  pkg_client_locale --> pkg_client_ui_slots
-  pkg_client_locale --> pkg_invariants
+  pkg_client_runtime --> pkg_api_remotes
+  pkg_client_runtime --> pkg_invariants
+  pkg_client_runtime --> pkg_typert_protocol
+  pkg_client_runtime --> pkg_typert_registry
   pkg_compaction_basic --> pkg_agent
   pkg_compaction_basic --> pkg_commands
   pkg_compaction_basic --> pkg_compaction
@@ -1151,6 +1142,43 @@ flowchart TD
   pkg_subagent_dsh_sdk --> pkg_session
   pkg_subagent_dsh_sdk --> pkg_subagent
   pkg_subagent_dsh_sdk --> pkg_subprocess
+  pkg_client_ui_settings --> pkg_api_remotes
+  pkg_client_ui_settings --> pkg_client_connection
+  pkg_client_ui_settings --> pkg_client_runtime
+  pkg_client_ui_settings --> pkg_client_schema_form
+  pkg_client_ui_settings --> pkg_client_ui_slots
+  pkg_client_ui_settings --> pkg_invariants
+  pkg_client_ui_settings --> pkg_settings
+  pkg_client_ui_settings_models --> pkg_api_remotes
+  pkg_client_ui_settings_models --> pkg_client_connection
+  pkg_client_ui_settings_models --> pkg_client_runtime
+  pkg_client_ui_settings_models --> pkg_client_schema_form
+  pkg_client_ui_settings_models --> pkg_client_ui_primitives
+  pkg_client_ui_settings_models --> pkg_client_ui_slots
+  pkg_client_ui_settings_models --> pkg_client_web_react
+  pkg_client_ui_settings_models --> pkg_invariants
+  pkg_acp_demo --> pkg_acp
+  pkg_acp_demo --> pkg_agent_instructions
+  pkg_acp_demo --> pkg_agent_spine_demo
+  pkg_acp_demo --> pkg_app_boot
+  pkg_acp_demo --> pkg_invariants
+  pkg_acp_demo --> pkg_session_checkpoint_policy
+  pkg_acp_demo --> pkg_session_persistence_jsonl
+  pkg_acp_demo --> pkg_session_query
+  pkg_acp_demo --> pkg_session_query_sqlite
+  pkg_acp_demo --> pkg_tools
+  pkg_client_test_runtime --> pkg_client_runtime
+  pkg_client_test_runtime --> pkg_client_ui_slots
+  pkg_client_test_runtime --> pkg_client_web_react
+  pkg_client_test_runtime --> pkg_host_apiproxy
+  pkg_client_test_runtime --> pkg_invariants
+  pkg_client_locale --> pkg_api_remotes
+  pkg_client_locale --> pkg_client_connection
+  pkg_client_locale --> pkg_client_runtime
+  pkg_client_locale --> pkg_client_ui_primitives
+  pkg_client_locale --> pkg_client_ui_settings
+  pkg_client_locale --> pkg_client_ui_slots
+  pkg_client_locale --> pkg_invariants
   pkg_client_ui_input_trigger --> pkg_client_locale
   pkg_client_ui_input_trigger --> pkg_client_runtime
   pkg_client_ui_input_trigger --> pkg_client_ui_primitives
@@ -1201,16 +1229,6 @@ flowchart TD
   pkg_client_ui_workspace --> pkg_client_ui_primitives
   pkg_client_ui_workspace --> pkg_client_ui_slots
   pkg_client_ui_workspace --> pkg_invariants
-  pkg_acp_demo --> pkg_acp
-  pkg_acp_demo --> pkg_agent_instructions
-  pkg_acp_demo --> pkg_agent_spine_demo
-  pkg_acp_demo --> pkg_app_boot
-  pkg_acp_demo --> pkg_invariants
-  pkg_acp_demo --> pkg_session_checkpoint_policy
-  pkg_acp_demo --> pkg_session_persistence_jsonl
-  pkg_acp_demo --> pkg_session_query
-  pkg_acp_demo --> pkg_session_query_sqlite
-  pkg_acp_demo --> pkg_tools
   pkg_client_ui_conversation --> pkg_agent
   pkg_client_ui_conversation --> pkg_api_remotes
   pkg_client_ui_conversation --> pkg_attachment
@@ -1254,6 +1272,13 @@ flowchart TD
   pkg_client_ui_settings_general --> pkg_client_ui_slots
   pkg_client_ui_settings_general --> pkg_client_web_react
   pkg_client_ui_settings_general --> pkg_invariants
+  pkg_cordis_client_runner --> pkg_api_remotes
+  pkg_cordis_client_runner --> pkg_client_connection
+  pkg_cordis_client_runner --> pkg_client_modules
+  pkg_cordis_client_runner --> pkg_client_runtime
+  pkg_cordis_client_runner --> pkg_client_ui_slots
+  pkg_cordis_client_runner --> pkg_client_ui_theme
+  pkg_cordis_client_runner --> pkg_invariants
   pkg_client_ui_agent_preset --> pkg_api_remotes
   pkg_client_ui_agent_preset --> pkg_client_connection
   pkg_client_ui_agent_preset --> pkg_client_locale
@@ -1344,14 +1369,14 @@ flowchart TD
   pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
   pkg_host_directory_picker_auto --> pkg_host_webserver
   pkg_host_directory_picker_auto --> pkg_invariants
-  pkg_session_log_download --> pkg_client_locale
-  pkg_session_log_download --> pkg_client_runtime
-  pkg_session_log_download --> pkg_client_ui_commands
-  pkg_session_log_download --> pkg_client_ui_conversation
-  pkg_session_log_download --> pkg_client_ui_primitives
-  pkg_session_log_download --> pkg_client_ui_slots
-  pkg_session_log_download --> pkg_commands
-  pkg_session_log_download --> pkg_invariants
+  pkg_session_log_export --> pkg_client_locale
+  pkg_session_log_export --> pkg_client_runtime
+  pkg_session_log_export --> pkg_client_ui_commands
+  pkg_session_log_export --> pkg_client_ui_conversation
+  pkg_session_log_export --> pkg_client_ui_primitives
+  pkg_session_log_export --> pkg_client_ui_slots
+  pkg_session_log_export --> pkg_commands
+  pkg_session_log_export --> pkg_invariants
   pkg_client_ui_model_selection --> pkg_api_remotes
   pkg_client_ui_model_selection --> pkg_client_connection
   pkg_client_ui_model_selection --> pkg_client_locale
@@ -1383,6 +1408,17 @@ flowchart TD
   pkg_client_ui_skill --> pkg_client_ui_slots
   pkg_client_ui_skill --> pkg_client_ui_tool
   pkg_client_ui_skill --> pkg_invariants
+  pkg_client_ui_cordis --> pkg_api_remotes
+  pkg_client_ui_cordis --> pkg_client_connection
+  pkg_client_ui_cordis --> pkg_client_locale
+  pkg_client_ui_cordis --> pkg_client_runtime
+  pkg_client_ui_cordis --> pkg_client_ui_input_trigger
+  pkg_client_ui_cordis --> pkg_client_ui_primitives
+  pkg_client_ui_cordis --> pkg_client_ui_sidebar
+  pkg_client_ui_cordis --> pkg_client_ui_slots
+  pkg_client_ui_cordis --> pkg_client_ui_tool
+  pkg_client_ui_cordis --> pkg_cordis_client_runner
+  pkg_client_ui_cordis --> pkg_invariants
 ```
 
 | Package | Group | Depends on |
@@ -1493,13 +1529,11 @@ flowchart TD
 | [`hook-protocol`](../packages/hooks/hook-protocol) | `hooks` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
 | [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-title`](../packages/session/session-title) |
 | [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`user-approval`](../packages/interaction/user-approval) |
-| [`api-remotes`](../packages/api/remotes) | `api` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`settings`](../packages/settings/settings), [`typert-registry`](../packages/typert/registry) |
 | [`headless`](../packages/bundle/headless) | `bundle` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
 | [`compaction`](../packages/compaction/compaction) | `compaction` | [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
 | [`tmux-context`](../packages/context/tmux-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
 | [`fs-e2b`](../packages/e2b/fs-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`fs`](../packages/fs/fs), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`command-feedback`](../packages/feedback/command-feedback) | `feedback` | [`anonymous-user-id`](../packages/identity/anonymous-user-id), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-telemetry`](../packages/session/session-telemetry) |
-| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`settings`](../packages/settings/settings), [`shell`](../packages/shell/shell), [`user-approval`](../packages/interaction/user-approval) |
 | [`jobs-local`](../packages/jobs/jobs-local) | `jobs` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`scope`](../packages/core/scope), [`timeout`](../packages/util/timeout) |
 | [`lsp-stdio`](../packages/lsp/lsp-stdio) | `lsp` | [`brand`](../packages/util/brand), [`fs`](../packages/fs/fs), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`lsp`](../packages/lsp/lsp), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
@@ -1524,11 +1558,10 @@ flowchart TD
 | [`hooks-codex`](../packages/hooks/hooks-codex) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`tools`](../packages/core/tools) |
 | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
 | [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
-| [`client-runtime`](../packages/client/runtime) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry) |
 | [`command-compact`](../packages/compaction/command-compact) | `compaction` | [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`agent-instructions`](../packages/context/agent-instructions) | `context` | [`agent`](../packages/core/agent), [`fs`](../packages/fs/fs), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
 | [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query) |
-| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`invariants`](../packages/runtime-diagnostics/invariants), [`scope`](../packages/core/scope), [`tools`](../packages/core/tools) |
+| [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | `extensions` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol) |
 | [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder) | `guard` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools) |
 | [`tool-call-timeout-policy`](../packages/guard/timeout-policy) | `guard` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
 | [`tool-ask-user`](../packages/interaction/tool-ask-user) | `interaction` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools), [`user-questions`](../packages/interaction/user-questions) |
@@ -1556,25 +1589,30 @@ flowchart TD
 | [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
 | [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
 | [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
+| [`api-remotes`](../packages/api/remotes) | `api` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`settings`](../packages/settings/settings), [`typert-registry`](../packages/typert/registry) |
 | [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
-| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
-| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
+| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
 | [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
 | [`tool-pwsh`](../packages/shell/tool-pwsh) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
-| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`host-apiproxy`](../packages/host/apiproxy), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
 | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
 | [`subagent-codex`](../packages/subagent/subagent-codex) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
 | [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
 | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
-| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-runtime`](../packages/client/runtime) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry) |
 | [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
 | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
 | [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
 | [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
 | [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
+| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
+| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`acp-demo`](../packages/examples/acp-demo) | `examples` | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/boot/app-boot), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`tools`](../packages/core/tools) |
+| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`host-apiproxy`](../packages/host/apiproxy), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
@@ -1583,12 +1621,12 @@ flowchart TD
 | [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools) |
 | [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`acp-demo`](../packages/examples/acp-demo) | `examples` | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/boot/app-boot), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`tools`](../packages/core/tools) |
 | [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-attachment`](../packages/client/ui-attachment), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm-retry`](../packages/llm/llm-retry), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
 | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
@@ -1600,7 +1638,8 @@ flowchart TD
 | [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
 | [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`session-log-download`](../packages/session-query/session-log-download) | `session-query` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
 | [`client-ui-skill`](../packages/client/ui-skill) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-tool`](../packages/client/ui-tool), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-tool`](../packages/client/ui-tool), [`cordis-client-runner`](../packages/extensions/cordis-client-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |

+ 118 - 79
docs/module-graph.zh.md

@@ -94,7 +94,7 @@ flowchart TD
     pkg_hooks_codex["hooks-codex"]
   end
   subgraph group_session_query["packages/session-query"]
-    pkg_session_log_download["session-log-download"]
+    pkg_session_log_export["session-log-export"]
     pkg_session_query["session-query"]
     pkg_session_query_sqlite["session-query-sqlite"]
     pkg_tool_session_query["tool-session-query"]
@@ -191,6 +191,9 @@ flowchart TD
     pkg_sdk_jsonrpc_demo["sdk-jsonrpc-demo"]
   end
   subgraph group_extensions["packages/extensions"]
+    pkg_client_ui_cordis["client-ui-cordis"]
+    pkg_cordis_client_runner["cordis-client-runner"]
+    pkg_cordis_host_runner["cordis-host-runner"]
     pkg_tool_cordis["tool-cordis"]
   end
   subgraph group_feedback["packages/feedback"]
@@ -640,20 +643,6 @@ flowchart TD
   pkg_acp --> pkg_invariants
   pkg_acp --> pkg_session
   pkg_acp --> pkg_user_approval
-  pkg_api_remotes --> pkg_agent
-  pkg_api_remotes --> pkg_agent_presets
-  pkg_api_remotes --> pkg_api_gateway
-  pkg_api_remotes --> pkg_commands
-  pkg_api_remotes --> pkg_credentials
-  pkg_api_remotes --> pkg_goal
-  pkg_api_remotes --> pkg_host_plugin_inventory
-  pkg_api_remotes --> pkg_invariants
-  pkg_api_remotes --> pkg_llm
-  pkg_api_remotes --> pkg_message_feedback
-  pkg_api_remotes --> pkg_session
-  pkg_api_remotes --> pkg_session_persistence
-  pkg_api_remotes --> pkg_settings
-  pkg_api_remotes --> pkg_typert_registry
   pkg_headless --> pkg_agent
   pkg_headless --> pkg_agent_default_model
   pkg_headless --> pkg_invariants
@@ -676,8 +665,6 @@ flowchart TD
   pkg_command_feedback --> pkg_invariants
   pkg_command_feedback --> pkg_session
   pkg_command_feedback --> pkg_session_telemetry
-  pkg_host_apiproxy --> pkg_agent_presets
-  pkg_host_apiproxy --> pkg_invariants
   pkg_permission_presets --> pkg_commands
   pkg_permission_presets --> pkg_invariants
   pkg_permission_presets --> pkg_sandbox
@@ -836,10 +823,6 @@ flowchart TD
   pkg_tool_session_query --> pkg_system_prompt
   pkg_tool_session_query --> pkg_timeout
   pkg_tool_session_query --> pkg_tools
-  pkg_client_runtime --> pkg_api_remotes
-  pkg_client_runtime --> pkg_invariants
-  pkg_client_runtime --> pkg_typert_protocol
-  pkg_client_runtime --> pkg_typert_registry
   pkg_command_compact --> pkg_commands
   pkg_command_compact --> pkg_compaction
   pkg_command_compact --> pkg_invariants
@@ -857,9 +840,14 @@ flowchart TD
   pkg_session_reference --> pkg_output_retention
   pkg_session_reference --> pkg_session
   pkg_session_reference --> pkg_session_query
-  pkg_tool_cordis --> pkg_invariants
-  pkg_tool_cordis --> pkg_scope
-  pkg_tool_cordis --> pkg_tools
+  pkg_cordis_host_runner --> pkg_agent
+  pkg_cordis_host_runner --> pkg_brand
+  pkg_cordis_host_runner --> pkg_invariants
+  pkg_cordis_host_runner --> pkg_llm
+  pkg_cordis_host_runner --> pkg_scope
+  pkg_cordis_host_runner --> pkg_session
+  pkg_cordis_host_runner --> pkg_tools
+  pkg_cordis_host_runner --> pkg_typert_protocol
   pkg_repeat_tool_reminder --> pkg_agent
   pkg_repeat_tool_reminder --> pkg_invariants
   pkg_repeat_tool_reminder --> pkg_tools
@@ -1013,29 +1001,40 @@ flowchart TD
   pkg_hooks_claude_code --> pkg_session_persistence
   pkg_hooks_claude_code --> pkg_subagent
   pkg_hooks_claude_code --> pkg_tools
+  pkg_api_remotes --> pkg_agent
+  pkg_api_remotes --> pkg_agent_presets
+  pkg_api_remotes --> pkg_api_gateway
+  pkg_api_remotes --> pkg_commands
+  pkg_api_remotes --> pkg_cordis_host_runner
+  pkg_api_remotes --> pkg_credentials
+  pkg_api_remotes --> pkg_goal
+  pkg_api_remotes --> pkg_host_plugin_inventory
+  pkg_api_remotes --> pkg_invariants
+  pkg_api_remotes --> pkg_llm
+  pkg_api_remotes --> pkg_message_feedback
+  pkg_api_remotes --> pkg_session
+  pkg_api_remotes --> pkg_session_persistence
+  pkg_api_remotes --> pkg_settings
+  pkg_api_remotes --> pkg_typert_registry
   pkg_web_app --> pkg_invariants
   pkg_web_app --> pkg_shell_env
   pkg_web_app --> pkg_system_prompt
-  pkg_client_ui_settings --> pkg_api_remotes
-  pkg_client_ui_settings --> pkg_client_connection
-  pkg_client_ui_settings --> pkg_client_runtime
-  pkg_client_ui_settings --> pkg_client_schema_form
-  pkg_client_ui_settings --> pkg_client_ui_slots
-  pkg_client_ui_settings --> pkg_invariants
-  pkg_client_ui_settings --> pkg_settings
-  pkg_client_ui_settings_models --> pkg_api_remotes
-  pkg_client_ui_settings_models --> pkg_client_connection
-  pkg_client_ui_settings_models --> pkg_client_runtime
-  pkg_client_ui_settings_models --> pkg_client_schema_form
-  pkg_client_ui_settings_models --> pkg_client_ui_primitives
-  pkg_client_ui_settings_models --> pkg_client_ui_slots
-  pkg_client_ui_settings_models --> pkg_client_web_react
-  pkg_client_ui_settings_models --> pkg_invariants
   pkg_compaction_tool_result_pruner --> pkg_compaction
   pkg_compaction_tool_result_pruner --> pkg_invariants
   pkg_compaction_tool_result_pruner --> pkg_llm
   pkg_compaction_tool_result_pruner --> pkg_session
   pkg_compaction_tool_result_pruner --> pkg_token_meter
+  pkg_tool_cordis --> pkg_agent
+  pkg_tool_cordis --> pkg_cordis_host_runner
+  pkg_tool_cordis --> pkg_invariants
+  pkg_tool_cordis --> pkg_llm
+  pkg_tool_cordis --> pkg_scope
+  pkg_tool_cordis --> pkg_session
+  pkg_tool_cordis --> pkg_system_prompt
+  pkg_tool_cordis --> pkg_tools
+  pkg_host_apiproxy --> pkg_agent_presets
+  pkg_host_apiproxy --> pkg_cordis_host_runner
+  pkg_host_apiproxy --> pkg_invariants
   pkg_sdk_protocol --> pkg_invariants
   pkg_sdk_protocol --> pkg_llm
   pkg_sdk_protocol --> pkg_session
@@ -1062,11 +1061,6 @@ flowchart TD
   pkg_tool_pwsh --> pkg_system_prompt
   pkg_tool_pwsh --> pkg_tools
   pkg_tool_pwsh --> pkg_user_approval
-  pkg_client_test_runtime --> pkg_client_runtime
-  pkg_client_test_runtime --> pkg_client_ui_slots
-  pkg_client_test_runtime --> pkg_client_web_react
-  pkg_client_test_runtime --> pkg_host_apiproxy
-  pkg_client_test_runtime --> pkg_invariants
   pkg_tool_ralph --> pkg_agent
   pkg_tool_ralph --> pkg_invariants
   pkg_tool_ralph --> pkg_llm
@@ -1097,13 +1091,10 @@ flowchart TD
   pkg_subagent_spawn_in_process --> pkg_invariants
   pkg_subagent_spawn_in_process --> pkg_subagent
   pkg_subagent_spawn_in_process --> pkg_subagent_in_process_driver
-  pkg_client_locale --> pkg_api_remotes
-  pkg_client_locale --> pkg_client_connection
-  pkg_client_locale --> pkg_client_runtime
-  pkg_client_locale --> pkg_client_ui_primitives
-  pkg_client_locale --> pkg_client_ui_settings
-  pkg_client_locale --> pkg_client_ui_slots
-  pkg_client_locale --> pkg_invariants
+  pkg_client_runtime --> pkg_api_remotes
+  pkg_client_runtime --> pkg_invariants
+  pkg_client_runtime --> pkg_typert_protocol
+  pkg_client_runtime --> pkg_typert_registry
   pkg_compaction_basic --> pkg_agent
   pkg_compaction_basic --> pkg_commands
   pkg_compaction_basic --> pkg_compaction
@@ -1153,6 +1144,43 @@ flowchart TD
   pkg_subagent_dsh_sdk --> pkg_session
   pkg_subagent_dsh_sdk --> pkg_subagent
   pkg_subagent_dsh_sdk --> pkg_subprocess
+  pkg_client_ui_settings --> pkg_api_remotes
+  pkg_client_ui_settings --> pkg_client_connection
+  pkg_client_ui_settings --> pkg_client_runtime
+  pkg_client_ui_settings --> pkg_client_schema_form
+  pkg_client_ui_settings --> pkg_client_ui_slots
+  pkg_client_ui_settings --> pkg_invariants
+  pkg_client_ui_settings --> pkg_settings
+  pkg_client_ui_settings_models --> pkg_api_remotes
+  pkg_client_ui_settings_models --> pkg_client_connection
+  pkg_client_ui_settings_models --> pkg_client_runtime
+  pkg_client_ui_settings_models --> pkg_client_schema_form
+  pkg_client_ui_settings_models --> pkg_client_ui_primitives
+  pkg_client_ui_settings_models --> pkg_client_ui_slots
+  pkg_client_ui_settings_models --> pkg_client_web_react
+  pkg_client_ui_settings_models --> pkg_invariants
+  pkg_acp_demo --> pkg_acp
+  pkg_acp_demo --> pkg_agent_instructions
+  pkg_acp_demo --> pkg_agent_spine_demo
+  pkg_acp_demo --> pkg_app_boot
+  pkg_acp_demo --> pkg_invariants
+  pkg_acp_demo --> pkg_session_checkpoint_policy
+  pkg_acp_demo --> pkg_session_persistence_jsonl
+  pkg_acp_demo --> pkg_session_query
+  pkg_acp_demo --> pkg_session_query_sqlite
+  pkg_acp_demo --> pkg_tools
+  pkg_client_test_runtime --> pkg_client_runtime
+  pkg_client_test_runtime --> pkg_client_ui_slots
+  pkg_client_test_runtime --> pkg_client_web_react
+  pkg_client_test_runtime --> pkg_host_apiproxy
+  pkg_client_test_runtime --> pkg_invariants
+  pkg_client_locale --> pkg_api_remotes
+  pkg_client_locale --> pkg_client_connection
+  pkg_client_locale --> pkg_client_runtime
+  pkg_client_locale --> pkg_client_ui_primitives
+  pkg_client_locale --> pkg_client_ui_settings
+  pkg_client_locale --> pkg_client_ui_slots
+  pkg_client_locale --> pkg_invariants
   pkg_client_ui_input_trigger --> pkg_client_locale
   pkg_client_ui_input_trigger --> pkg_client_runtime
   pkg_client_ui_input_trigger --> pkg_client_ui_primitives
@@ -1203,16 +1231,6 @@ flowchart TD
   pkg_client_ui_workspace --> pkg_client_ui_primitives
   pkg_client_ui_workspace --> pkg_client_ui_slots
   pkg_client_ui_workspace --> pkg_invariants
-  pkg_acp_demo --> pkg_acp
-  pkg_acp_demo --> pkg_agent_instructions
-  pkg_acp_demo --> pkg_agent_spine_demo
-  pkg_acp_demo --> pkg_app_boot
-  pkg_acp_demo --> pkg_invariants
-  pkg_acp_demo --> pkg_session_checkpoint_policy
-  pkg_acp_demo --> pkg_session_persistence_jsonl
-  pkg_acp_demo --> pkg_session_query
-  pkg_acp_demo --> pkg_session_query_sqlite
-  pkg_acp_demo --> pkg_tools
   pkg_client_ui_conversation --> pkg_agent
   pkg_client_ui_conversation --> pkg_api_remotes
   pkg_client_ui_conversation --> pkg_attachment
@@ -1256,6 +1274,13 @@ flowchart TD
   pkg_client_ui_settings_general --> pkg_client_ui_slots
   pkg_client_ui_settings_general --> pkg_client_web_react
   pkg_client_ui_settings_general --> pkg_invariants
+  pkg_cordis_client_runner --> pkg_api_remotes
+  pkg_cordis_client_runner --> pkg_client_connection
+  pkg_cordis_client_runner --> pkg_client_modules
+  pkg_cordis_client_runner --> pkg_client_runtime
+  pkg_cordis_client_runner --> pkg_client_ui_slots
+  pkg_cordis_client_runner --> pkg_client_ui_theme
+  pkg_cordis_client_runner --> pkg_invariants
   pkg_client_ui_agent_preset --> pkg_api_remotes
   pkg_client_ui_agent_preset --> pkg_client_connection
   pkg_client_ui_agent_preset --> pkg_client_locale
@@ -1346,14 +1371,14 @@ flowchart TD
   pkg_host_directory_picker_auto --> pkg_host_directory_picker_native
   pkg_host_directory_picker_auto --> pkg_host_webserver
   pkg_host_directory_picker_auto --> pkg_invariants
-  pkg_session_log_download --> pkg_client_locale
-  pkg_session_log_download --> pkg_client_runtime
-  pkg_session_log_download --> pkg_client_ui_commands
-  pkg_session_log_download --> pkg_client_ui_conversation
-  pkg_session_log_download --> pkg_client_ui_primitives
-  pkg_session_log_download --> pkg_client_ui_slots
-  pkg_session_log_download --> pkg_commands
-  pkg_session_log_download --> pkg_invariants
+  pkg_session_log_export --> pkg_client_locale
+  pkg_session_log_export --> pkg_client_runtime
+  pkg_session_log_export --> pkg_client_ui_commands
+  pkg_session_log_export --> pkg_client_ui_conversation
+  pkg_session_log_export --> pkg_client_ui_primitives
+  pkg_session_log_export --> pkg_client_ui_slots
+  pkg_session_log_export --> pkg_commands
+  pkg_session_log_export --> pkg_invariants
   pkg_client_ui_model_selection --> pkg_api_remotes
   pkg_client_ui_model_selection --> pkg_client_connection
   pkg_client_ui_model_selection --> pkg_client_locale
@@ -1385,6 +1410,17 @@ flowchart TD
   pkg_client_ui_skill --> pkg_client_ui_slots
   pkg_client_ui_skill --> pkg_client_ui_tool
   pkg_client_ui_skill --> pkg_invariants
+  pkg_client_ui_cordis --> pkg_api_remotes
+  pkg_client_ui_cordis --> pkg_client_connection
+  pkg_client_ui_cordis --> pkg_client_locale
+  pkg_client_ui_cordis --> pkg_client_runtime
+  pkg_client_ui_cordis --> pkg_client_ui_input_trigger
+  pkg_client_ui_cordis --> pkg_client_ui_primitives
+  pkg_client_ui_cordis --> pkg_client_ui_sidebar
+  pkg_client_ui_cordis --> pkg_client_ui_slots
+  pkg_client_ui_cordis --> pkg_client_ui_tool
+  pkg_client_ui_cordis --> pkg_cordis_client_runner
+  pkg_client_ui_cordis --> pkg_invariants
 ```
 
 | Package | Group | Depends on |
@@ -1495,13 +1531,11 @@ flowchart TD
 | [`hook-protocol`](../packages/hooks/hook-protocol) | `hooks` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
 | [`session-query`](../packages/session-query/session-query) | `session-query` | [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-title`](../packages/session/session-title) |
 | [`acp`](../packages/acp/acp) | `acp` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`user-approval`](../packages/interaction/user-approval) |
-| [`api-remotes`](../packages/api/remotes) | `api` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`commands`](../packages/interaction/commands), [`credentials`](../packages/credentials/credentials), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`settings`](../packages/settings/settings), [`typert-registry`](../packages/typert/registry) |
 | [`headless`](../packages/bundle/headless) | `bundle` | [`agent`](../packages/core/agent), [`agent-default-model`](../packages/core/agent-default-model), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
 | [`compaction`](../packages/compaction/compaction) | `compaction` | [`brand`](../packages/util/brand), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session) |
 | [`tmux-context`](../packages/context/tmux-context) | `context` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`shell`](../packages/shell/shell) |
 | [`fs-e2b`](../packages/e2b/fs-e2b) | `e2b` | [`e2b`](../packages/e2b/e2b), [`fs`](../packages/fs/fs), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`command-feedback`](../packages/feedback/command-feedback) | `feedback` | [`anonymous-user-id`](../packages/identity/anonymous-user-id), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-telemetry`](../packages/session/session-telemetry) |
-| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`permission-presets`](../packages/interaction/permission-presets) | `interaction` | [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`session`](../packages/core/session), [`session-projection`](../packages/session/session-projection), [`settings`](../packages/settings/settings), [`shell`](../packages/shell/shell), [`user-approval`](../packages/interaction/user-approval) |
 | [`jobs-local`](../packages/jobs/jobs-local) | `jobs` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`scope`](../packages/core/scope), [`timeout`](../packages/util/timeout) |
 | [`lsp-stdio`](../packages/lsp/lsp-stdio) | `lsp` | [`brand`](../packages/util/brand), [`fs`](../packages/fs/fs), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`lsp`](../packages/lsp/lsp), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
@@ -1526,11 +1560,10 @@ flowchart TD
 | [`hooks-codex`](../packages/hooks/hooks-codex) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`tools`](../packages/core/tools) |
 | [`session-query-sqlite`](../packages/session-query/session-query-sqlite) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`session-query`](../packages/session-query/session-query) |
 | [`tool-session-query`](../packages/session-query/tool-session-query) | `session-query` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query), [`system-prompt`](../packages/core/system-prompt), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
-| [`client-runtime`](../packages/client/runtime) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry) |
 | [`command-compact`](../packages/compaction/command-compact) | `compaction` | [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`agent-instructions`](../packages/context/agent-instructions) | `context` | [`agent`](../packages/core/agent), [`fs`](../packages/fs/fs), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`tools`](../packages/core/tools) |
 | [`session-reference`](../packages/context/session-reference) | `context` | [`agent`](../packages/core/agent), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`output-retention`](../packages/util/output-retention), [`session`](../packages/core/session), [`session-query`](../packages/session-query/session-query) |
-| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`invariants`](../packages/runtime-diagnostics/invariants), [`scope`](../packages/core/scope), [`tools`](../packages/core/tools) |
+| [`cordis-host-runner`](../packages/extensions/cordis-host-runner) | `extensions` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`tools`](../packages/core/tools), [`typert-protocol`](../packages/typert/protocol) |
 | [`repeat-tool-reminder`](../packages/guard/repeat-tool-reminder) | `guard` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools) |
 | [`tool-call-timeout-policy`](../packages/guard/timeout-policy) | `guard` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`timeout`](../packages/util/timeout), [`tools`](../packages/core/tools) |
 | [`tool-ask-user`](../packages/interaction/tool-ask-user) | `interaction` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools), [`user-questions`](../packages/interaction/user-questions) |
@@ -1558,25 +1591,30 @@ flowchart TD
 | [`tool-subagent-control`](../packages/subagent/tool-subagent-control) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
 | [`tool-subagent-report`](../packages/subagent/tool-subagent-report) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
 | [`hooks-claude-code`](../packages/hooks/hooks-claude-code) | `hooks` | [`agent`](../packages/core/agent), [`hook-protocol`](../packages/hooks/hook-protocol), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools) |
+| [`api-remotes`](../packages/api/remotes) | `api` | [`agent`](../packages/core/agent), [`agent-presets`](../packages/preset/agent-presets), [`api-gateway`](../packages/api/gateway), [`commands`](../packages/interaction/commands), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`credentials`](../packages/credentials/credentials), [`goal`](../packages/goal/goal), [`host-plugin-inventory`](../packages/host/plugin-inventory), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`message-feedback`](../packages/feedback/message-feedback), [`session`](../packages/core/session), [`session-persistence`](../packages/session/session-persistence), [`settings`](../packages/settings/settings), [`typert-registry`](../packages/typert/registry) |
 | [`web-app`](../packages/bundle/web-app) | `bundle` | [`invariants`](../packages/runtime-diagnostics/invariants), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt) |
-| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
-| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner) | `compaction` | [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
+| [`tool-cordis`](../packages/extensions/tool-cordis) | `extensions` | [`agent`](../packages/core/agent), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools) |
+| [`host-apiproxy`](../packages/host/apiproxy) | `host` | [`agent-presets`](../packages/preset/agent-presets), [`cordis-host-runner`](../packages/extensions/cordis-host-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`sdk-protocol`](../packages/sdk/protocol) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
 | [`tool-bash`](../packages/shell/tool-bash) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
 | [`tool-pwsh`](../packages/shell/tool-pwsh) | `shell` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs`](../packages/jobs/jobs), [`llm`](../packages/llm/llm), [`sandbox`](../packages/sandbox/sandbox), [`sandbox-policy`](../packages/sandbox/sandbox-policy), [`shell`](../packages/shell/shell), [`shell-env`](../packages/shell/shell-env), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`user-approval`](../packages/interaction/user-approval) |
-| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`host-apiproxy`](../packages/host/apiproxy), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`tool-ralph`](../packages/workflow/tool-ralph) | `workflow` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`subagent`](../packages/subagent/subagent), [`system-prompt`](../packages/core/system-prompt), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
 | [`workflow-worker-thread`](../packages/workflow/workflow-worker-thread) | `workflow` | [`agent`](../packages/core/agent), [`brand`](../packages/util/brand), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`tools`](../packages/core/tools), [`workflow`](../packages/workflow/workflow) |
 | [`subagent-codex`](../packages/subagent/subagent-codex) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess), [`timeout`](../packages/util/timeout) |
 | [`subagent-fork-in-process`](../packages/subagent/subagent-fork-in-process) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
 | [`subagent-spawn-in-process`](../packages/subagent/subagent-spawn-in-process) | `subagent` | [`invariants`](../packages/runtime-diagnostics/invariants), [`subagent`](../packages/subagent/subagent), [`subagent-in-process-driver`](../packages/subagent/subagent-in-process-driver) |
-| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-runtime`](../packages/client/runtime) | `client` | [`api-remotes`](../packages/api/remotes), [`invariants`](../packages/runtime-diagnostics/invariants), [`typert-protocol`](../packages/typert/protocol), [`typert-registry`](../packages/typert/registry) |
 | [`compaction-basic`](../packages/compaction/compaction-basic) | `compaction` | [`agent`](../packages/core/agent), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`compaction-tool-result-pruner`](../packages/compaction/compaction-tool-result-pruner), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`session`](../packages/core/session), [`token-meter`](../packages/llm/token-meter) |
 | [`agent-spine-demo`](../packages/examples/agent-spine-demo) | `examples` | [`agent`](../packages/core/agent), [`agent-instructions`](../packages/context/agent-instructions), [`agent-loop`](../packages/core/agent-loop), [`goal`](../packages/goal/goal), [`goal-round-driver`](../packages/goal/goal-round-driver), [`home-paths`](../packages/util/home-paths), [`invariants`](../packages/runtime-diagnostics/invariants), [`jobs-local`](../packages/jobs/jobs-local), [`llm`](../packages/llm/llm), [`llm-retry`](../packages/llm/llm-retry), [`scope`](../packages/core/scope), [`session`](../packages/core/session), [`session-title`](../packages/session/session-title), [`shell-env`](../packages/shell/shell-env), [`skill`](../packages/skill/skill), [`skill-filesystem`](../packages/skill/skill-filesystem), [`system-prompt`](../packages/core/system-prompt), [`tool-bash`](../packages/shell/tool-bash), [`tool-goal`](../packages/goal/tool-goal), [`tool-jobs`](../packages/jobs/tool-jobs), [`tool-skill`](../packages/skill/tool-skill), [`tools`](../packages/core/tools) |
 | [`sdk-client`](../packages/sdk/client) | `sdk` | [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session) |
 | [`sdk-jsonrpc-server`](../packages/sdk/server) | `sdk` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`llm-deepseek`](../packages/llm/llm-deepseek), [`scope`](../packages/core/scope), [`sdk-protocol`](../packages/sdk/protocol), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent) |
 | [`subagent-dsh-sdk`](../packages/subagent/subagent-dsh-sdk) | `subagent` | [`agent`](../packages/core/agent), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm`](../packages/llm/llm), [`sdk-client`](../packages/sdk/client), [`session`](../packages/core/session), [`subagent`](../packages/subagent/subagent), [`subprocess`](../packages/subprocess/subprocess) |
+| [`client-ui-settings`](../packages/client/ui-settings) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`settings`](../packages/settings/settings) |
+| [`client-ui-settings-models`](../packages/client/ui-settings-models) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`acp-demo`](../packages/examples/acp-demo) | `examples` | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/boot/app-boot), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`tools`](../packages/core/tools) |
+| [`client-test-runtime`](../packages/test-support/client-runtime) | `test-support` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`host-apiproxy`](../packages/host/apiproxy), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-locale`](../packages/client/locale) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-input-trigger`](../packages/client/ui-input-trigger) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-plugin-inventory`](../packages/client/ui-settings-plugin-inventory) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-plugins`](../packages/client/ui-settings-plugins) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
@@ -1585,12 +1623,12 @@ flowchart TD
 | [`client-ui-trajectory`](../packages/client/ui-trajectory) | `client` | [`agent`](../packages/core/agent), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`tools`](../packages/core/tools) |
 | [`client-ui-user-questions`](../packages/client/ui-user-questions) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-workspace`](../packages/client/ui-workspace) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`acp-demo`](../packages/examples/acp-demo) | `examples` | [`acp`](../packages/acp/acp), [`agent-instructions`](../packages/context/agent-instructions), [`agent-spine-demo`](../packages/examples/agent-spine-demo), [`app-boot`](../packages/boot/app-boot), [`invariants`](../packages/runtime-diagnostics/invariants), [`session-checkpoint-policy`](../packages/session/session-checkpoint-policy), [`session-persistence-jsonl`](../packages/session/session-persistence-jsonl), [`session-query`](../packages/session-query/session-query), [`session-query-sqlite`](../packages/session-query/session-query-sqlite), [`tools`](../packages/core/tools) |
 | [`client-ui-conversation`](../packages/client/ui-conversation) | `client` | [`agent`](../packages/core/agent), [`api-remotes`](../packages/api/remotes), [`attachment`](../packages/attachment/attachment), [`brand`](../packages/util/brand), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-attachment`](../packages/client/ui-attachment), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`compaction`](../packages/compaction/compaction), [`invariants`](../packages/runtime-diagnostics/invariants), [`llm-retry`](../packages/llm/llm-retry), [`session-stats`](../packages/session/session-stats), [`token-meter`](../packages/llm/token-meter), [`tools`](../packages/core/tools) |
 | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-workspace`](../packages/client/ui-workspace), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-layout`](../packages/client/ui-layout) | `client` | [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-settings-general`](../packages/client/ui-settings-general) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`cordis-client-runner`](../packages/extensions/cordis-client-runner) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-modules`](../packages/client/modules), [`client-runtime`](../packages/client/runtime), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-theme`](../packages/client/ui-theme), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-agent-preset`](../packages/client/ui-agent-preset) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`client-web-react`](../packages/client/web-react), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-commands`](../packages/client/ui-commands) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-deliverables`](../packages/client/ui-deliverables) | `client` | [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`system-prompt`](../packages/core/system-prompt) |
@@ -1602,7 +1640,8 @@ flowchart TD
 | [`client-ui-tool`](../packages/client/ui-tool) | `client` | [`api-remotes`](../packages/api/remotes), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-workflow-run`](../packages/client/ui-workflow-run) | `client` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`session`](../packages/core/session), [`tool-workflow`](../packages/workflow/tool-workflow), [`workflow`](../packages/workflow/workflow) |
 | [`host-directory-picker-auto`](../packages/host/directory-picker-auto) | `host` | [`client-ui-directory-picker-browse`](../packages/client/ui-directory-picker-browse), [`client-ui-directory-picker-native`](../packages/client/ui-directory-picker-native), [`host-directory-picker-browse`](../packages/host/directory-picker-browse), [`host-directory-picker-native`](../packages/host/directory-picker-native), [`host-webserver`](../packages/host/webserver), [`invariants`](../packages/runtime-diagnostics/invariants) |
-| [`session-log-download`](../packages/session-query/session-log-download) | `session-query` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`session-log-export`](../packages/session-query/session-log-export) | `session-query` | [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`commands`](../packages/interaction/commands), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-model-selection`](../packages/client/ui-model-selection) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-conversation`](../packages/client/ui-conversation), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants) |
 | [`client-ui-permission-presets`](../packages/client/ui-permission-presets) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-schema-form`](../packages/client/schema-form), [`client-ui-commands`](../packages/client/ui-commands), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-settings`](../packages/client/ui-settings), [`client-ui-slots`](../packages/client/ui-slots), [`invariants`](../packages/runtime-diagnostics/invariants), [`permission-presets`](../packages/interaction/permission-presets) |
 | [`client-ui-skill`](../packages/client/ui-skill) | `client` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-tool`](../packages/client/ui-tool), [`invariants`](../packages/runtime-diagnostics/invariants) |
+| [`client-ui-cordis`](../packages/extensions/ui-cordis) | `extensions` | [`api-remotes`](../packages/api/remotes), [`client-connection`](../packages/client/connection), [`client-locale`](../packages/client/locale), [`client-runtime`](../packages/client/runtime), [`client-ui-input-trigger`](../packages/client/ui-input-trigger), [`client-ui-primitives`](../packages/client/ui-primitives), [`client-ui-sidebar`](../packages/client/ui-sidebar), [`client-ui-slots`](../packages/client/ui-slots), [`client-ui-tool`](../packages/client/ui-tool), [`cordis-client-runner`](../packages/extensions/cordis-client-runner), [`invariants`](../packages/runtime-diagnostics/invariants) |

+ 2 - 2
docs/subsystems/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/subsystems/README.md
-README.md: 9dafb548060f884ab98b20d64896a974a0ad6e81
-README.zh.md: f5298e7c0268d53da4322aadbe960a2f622ce8f1
+README.md: a1c2262f40aebdf4b0fdcdca4b0c05bae443fe2f
+README.zh.md: 0b5c00e6321a67a11dc6f98caedc7e26fb98eec2

+ 1 - 0
docs/subsystems/README.md

@@ -32,6 +32,7 @@ One page per subsystem of the DeepSeek Harness: what it is, the data structures
 | [terminal.md](terminal.md) | persistent terminal ids, backend/session contracts, send readiness, bounded reads, and owner-visible snapshots |
 | [sandbox.md](sandbox.md) | per-session policy resolution and the process-confinement seam: file-effect modes, execution/provider policies, `ConfinedArgv`, enforcement and fail-closed errors |
 | [code-runtime.md](code-runtime.md) | the code-execution seam: `CodeRunRequest`/`Result`, binding namespaces, captured logs, the `CodeRunFailure` taxonomy |
+| [extensions.md](extensions.md) | versioned dynamic Cordis Plugins and Packages, Host/Client activation, approval, runtime inspection, and lifecycle teardown |
 | [filesystem.md](filesystem.md) | the filesystem seam: `FsTarget`, read/write/edit outcomes, observed-file state, `FsErrorCode` |
 | [lsp.md](lsp.md) | the LSP navigation seam: `LspQueryRequest`/`Result`, `LspProvider`/`Service`, four operations, `LspError` |
 | [skills.md](skills.md) | the skill service: discovery priority, `SkillSummary`/`SkillDefinition`, session-prefix catalog, model-facing `skill` loading |

+ 1 - 0
docs/subsystems/README.zh.md

@@ -32,6 +32,7 @@
 | [terminal.md](terminal.md) | 持久化终端 ID、后端/会话约定、发送就绪状态、有界读取与 owner 可见快照 |
 | [sandbox.md](sandbox.md) | 每会话策略解析与进程约束 seam:文件效果模式、执行/提供方策略、`ConfinedArgv`、强制执行与故障关闭错误 |
 | [code-runtime.md](code-runtime.md) | 代码执行 seam:`CodeRunRequest`/`Result`、绑定命名空间、捕获日志、`CodeRunFailure` 分类体系 |
+| [extensions.md](extensions.md) | 带版本的动态 Cordis Plugin 与 Package、Host/Client 激活、审批、运行时检查和生命周期撤销 |
 | [filesystem.md](filesystem.md) | 文件系统 seam:`FsTarget`、读/写/编辑结果、观测到的文件状态、`FsErrorCode` |
 | [lsp.md](lsp.md) | LSP 导航 seam:`LspQueryRequest`/`Result`、`LspProvider`/`Service`、四种操作、`LspError` |
 | [skills.md](skills.md) | skill(技能)服务:发现优先级、`SkillSummary`/`SkillDefinition`、会话前缀目录、面向模型的 `skill` 加载 |

+ 6 - 0
docs/subsystems/extensions.i18n.yaml

@@ -0,0 +1,6 @@
+# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
+# side as of the last confirmed-consistent state. Both languages carry equal authority;
+# after editing either side, bring the other along and re-record with:
+#   pnpm run verify-translation-pairing --write docs/subsystems/extensions.md
+extensions.md: f212f99704cb1cc871a77ee6cc10188746771958
+extensions.zh.md: 717b14951dd262213cfc42a380777d233fb6eea5

+ 364 - 0
docs/subsystems/extensions.md

@@ -0,0 +1,364 @@
+# Extensions
+
+English | [中文](extensions.zh.md)
+
+The extensions subsystem lets an agent define versioned Cordis packages, run their host and browser halves, and query approved runtime metadata before writing code. Package lifecycle and sandbox behavior belong to the [`packages/extensions`](../../packages/extensions/README.md) package group.
+
+<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
+
+<a id="cordis-surface"></a>
+
+## Cordis API
+
+Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+<a id="ctxcordisinspect--cordisinspectregistryservice"></a>
+
+### `ctx.cordisInspect` — `CordisInspectRegistryService`
+
+Registry and cross-page router behind the two model-facing inspect tools.
+
+```ts cordis-catalog
+/**
+ * Register one Host provider.
+ * @param registration - manifest and local query handler.
+ * @returns idempotent disposer.
+ */
+register(registration: HostCordisInspectProviderRegistration): () => void
+
+/**
+ * Replace the mirrored Client provider directory.
+ * @param providers - complete Client manifest snapshot.
+ */
+syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void
+
+/**
+ * Return the complete known Host and Client provider directory.
+ * @returns Host providers followed by the Client providers.
+ */
+list(): CordisInspectProviderView[]
+
+/**
+ * Execute one provider query on its owning platform.
+ * @param platform - Host or Client runtime.
+ * @param providerId - provider selected from {@link list}.
+ * @param methodName - declared method name.
+ * @param input - optional lossless JSON input.
+ * @param agent - requesting Agent and scope.
+ * @param signal - tool-call cancellation.
+ * @returns provider JSON data.
+ */
+async query( platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal, ): Promise<JsonValue>
+
+/**
+ * Accept the first valid Client response for a pending query.
+ * @param agent - Agent whose Session owns the query.
+ * @param requestId - Pending Client query identity.
+ * @param resolution - Client provider result or failure.
+ * @returns whether this response settled the still-pending query.
+ */
+resolveClientQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck
+```
+
+Types: [Agent](core.md)
+
+Source: [`packages/extensions/cordis-host-runner/src/inspect-registry.ts:46`](../../packages/extensions/cordis-host-runner/src/inspect-registry.ts)
+
+<a id="ctxdynamiccordisrunner--dynamiccordisrunnerservice"></a>
+
+### `ctx.dynamicCordisRunner` — `DynamicCordisRunnerService`
+
+Dynamic Plugin registry and Host-half lifecycle.
+
+```ts cordis-catalog
+/**
+ * Define a new Plugin's first Package or append a Package to an existing Plugin.
+ * @param request - Session ownership, Plugin selection, metadata, and source code.
+ * @returns Host-minted Plugin and Package identities with declared-half metadata.
+ */
+define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt
+
+/**
+ * Remove a Plugin, its active run, and all immutable Packages.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to remove.
+ * @returns Whether removal succeeded and whether it stopped an active run.
+ */
+async undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisUndefineReceipt>
+
+/**
+ * Remove a Plugin from the user panel and queue the resulting state change for the model's next step.
+ * @param agent - Agent whose Session owns the Plugin and receives the context.
+ * @param pluginId - Stable Plugin identity to remove.
+ * @returns Whether removal succeeded and whether it stopped an active run.
+ */
+@Remote('undefineFromPanel') async undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisUndefineReceipt>
+
+/**
+ * Start or update one Package for a model tool call. An unauthorized Client
+ * Package waits for approval; Plugin-wide authorization covers later versions.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to activate.
+ * @param packageId - Immutable Package version to activate.
+ * @param mode - Whether to run the current version or switch versions.
+ * @param signal - Tool-call cancellation signal while the activation request is being created.
+ * @returns The successful activation identity or an actionable refusal.
+ */
+async run( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal, ): Promise<DynamicCordisRunResponse>
+
+/**
+ * Start Host code for an approved request or a direct panel gesture.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to activate.
+ * @param packageId - Immutable Package version to activate.
+ * @param mode - Whether to run the current version or switch versions.
+ * @param requestId - Model-driven request identity, or null for a direct user gesture.
+ * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin.
+ * @returns The exact Host activation or a failure message.
+ */
+@Remote('runHostHalf') async runHostHalf( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean, ): Promise<DynamicCordisHostHalfResult>
+
+/**
+ * Fetch Client code for the exact active run.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to read.
+ * @param pluginRunId - Exact active run authorized to receive source.
+ * @returns Client source and its Plugin, Package, and run identities.
+ */
+@Remote('getClientCode') getClientCode( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, ): DynamicCordisClientSource
+
+/**
+ * Resolve one model-driven Client activation request.
+ * @param requestId - Request identity to settle once.
+ * @param resolution - Browser refusal or exact Client activation result.
+ * @returns Whether the still-pending request accepted this resolution.
+ */
+@Remote('resolveRequestRun') async resolveRequestRun( requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution, ): Promise<DynamicCordisResolveAck>
+
+/**
+ * Settle a direct panel run after this page loaded or failed its Client half.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity being settled.
+ * @param resolution - Exact Client activation result from the acting page.
+ * @returns The committed activation or its failure.
+ */
+@Remote('settleUserRun') async settleUserRun( agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution, ): Promise<DynamicCordisRunResponse>
+
+/**
+ * Stop the active run while retaining every Package version.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to stop.
+ * @returns Success or the reason no run was stopped.
+ */
+async stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisStopResponse>
+
+/**
+ * Stop a Plugin from the user panel and queue the resulting state change for the model's next step.
+ * @param agent - Agent whose Session owns the Plugin and receives the context.
+ * @param pluginId - Stable Plugin identity to stop.
+ * @returns Success or the reason no run was stopped.
+ */
+@Remote('stopFromPanel') async stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisStopResponse>
+
+/**
+ * Replace the Host mirror of the Client inspect provider directory.
+ * @param providers - complete Client provider manifest.
+ * @returns null after accepting the manifest.
+ */
+@Remote('syncInspectManifest') syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null
+
+/**
+ * Claim one pending Client inspect query with its live result.
+ * @param agent - Session that owns the query.
+ * @param requestId - exact pending query identity.
+ * @param resolution - provider result or structured refusal.
+ * @returns whether this answer won the query.
+ */
+@Remote('resolveInspectQuery') resolveInspectQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck
+
+/**
+ * Frame-wide inventory, grouped as one row per stable Plugin.
+ * @returns Source-free metadata for every process-local Plugin.
+ */
+@Remote('inventory') inventory(): DynamicCordisInventoryRow[]
+
+/**
+ * Read one Session's Host-rich state for inspection and result rendering.
+ * @param agent - Agent whose Session selects visible Plugins.
+ * @returns Plugin versions, active runs, Host fibers, and render failures.
+ */
+snapshot(agent: Agent): DynamicCordisSnapshotRow[]
+
+/**
+ * Read source-free context for an explicit `@pluginId` user gesture.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity referenced by the user.
+ * @returns The preferred modification base, or undefined when unavailable.
+ */
+reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined
+
+/**
+ * List source-free Plugin summaries owned by one Session.
+ * @param agent - Agent whose Session selects visible Plugins.
+ * @returns one summary per Plugin in creation order.
+ */
+listPlugins(agent: Agent): DynamicCordisPluginInspection[]
+
+/**
+ * Inspect one Plugin without returning Package source.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - stable Plugin identity.
+ * @returns version pointers, latest run, and all Package summaries.
+ */
+inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection
+
+/**
+ * Read one exact immutable Package and its Host and Client source.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity that owns the Package.
+ * @param packageId - Exact immutable Package identity to inspect.
+ * @returns Package metadata, source, and the Plugin's lifecycle pointers.
+ */
+inspectPackage( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, ): DynamicCordisPackageInspection
+
+/**
+ * Record a post-load render failure for the exact active run.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity that rendered.
+ * @param pluginRunId - Exact active run that produced the failure.
+ * @param failure - Slot, message, and entry-retirement result.
+ * @returns Null after recording or ignoring a stale report.
+ */
+@Remote('reportRenderFailure') async reportRenderFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure, ): Promise<null>
+
+/**
+ * Report a Client guard rejection that happened after the Package completed activation.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity whose Client code was rejected.
+ * @param pluginRunId - Exact active run that produced the rejection.
+ * @param failure - Original guard message and stack.
+ * @returns Null after reporting or ignoring a stale/startup failure.
+ */
+@Remote('reportClientGuardFailure') async reportClientGuardFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails, ): Promise<null>
+
+/**
+ * Invoke an active Host method while rejecting stale Client runs.
+ * @param pluginId - Stable Plugin identity that owns the method.
+ * @param pluginRunId - Exact active run authorizing the call.
+ * @param method - Registered Host handler name.
+ * @param args - JSON argument delivered to the handler.
+ * @returns The JSON result or a typed invocation failure.
+ */
+@Remote('invoke') async invoke( pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue, ): Promise<DynamicCordisInvokeResult>
+```
+
+Types: [Agent](core.md)
+
+Source: [`packages/extensions/cordis-host-runner/src/index.ts:124`](../../packages/extensions/cordis-host-runner/src/index.ts)
+
+<a id="cordis-events"></a>
+
+### `cordis/*` events
+
+<a id="cordisdynamic-package--emit"></a>
+
+#### `cordis/dynamic-package` — emit
+
+One exact Plugin/Package activation is now live in the Host.
+
+```ts cordis-catalog
+/**
+ * One exact Plugin/Package activation is now live in the Host.
+ * @param pkg - stable plugin, immutable package, run identity, and label.
+ * @mode emit
+ */
+'cordis/dynamic-package'(pkg: DynamicCordisPackage): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:379`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisdynamic-retract--emit"></a>
+
+#### `cordis/dynamic-retract` — emit
+
+One exact activation was withdrawn.
+
+```ts cordis-catalog
+/**
+ * One exact activation was withdrawn.
+ * @param retracted - plugin, package, and run identity.
+ * @mode emit
+ */
+'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:385`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisinspect-query--emit"></a>
+
+#### `cordis/inspect-query` — emit
+
+Request a live read-only query from the Client inspect registry.
+
+```ts cordis-catalog
+/**
+ * Request a live read-only query from the Client inspect registry.
+ * @param request - correlation, Session, provider, method, and JSON input.
+ * @mode emit
+ */
+'cordis/inspect-query'(request: CordisInspectQueryRequest): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:391`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisinspect-query-resolved--emit"></a>
+
+#### `cordis/inspect-query-resolved` — emit
+
+Notify every Client that an inspect query has settled or been cancelled.
+
+```ts cordis-catalog
+/**
+ * Notify every Client that an inspect query has settled or been cancelled.
+ * @param resolved - exact query identity that is no longer answerable.
+ * @mode emit
+ */
+'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:397`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisrequest-run--emit"></a>
+
+#### `cordis/request-run` — emit
+
+A Client-bearing activation needs a browser page, and may require a user decision.
+
+```ts cordis-catalog
+/**
+ * A Client-bearing activation needs a browser page, and may require a user decision.
+ * @param request - correlation identity, owner, target version, mode, and approval requirement.
+ * @mode emit
+ */
+'cordis/request-run'(request: DynamicCordisRunRequest): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:367`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisrequest-run-resolved--emit"></a>
+
+#### `cordis/request-run-resolved` — emit
+
+A pending Client activation request left the answerable state.
+
+```ts cordis-catalog
+/**
+ * A pending Client activation request left the answerable state.
+ * @param resolved - request identity and outcome.
+ * @mode emit
+ */
+'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:373`](../../packages/extensions/cordis-host-runner/src/types.ts)
+<!-- END GENERATED cordis-surface -->

+ 364 - 0
docs/subsystems/extensions.zh.md

@@ -0,0 +1,364 @@
+# 扩展
+
+[English](extensions.md) | 中文
+
+extensions 子系统允许 agent(智能体)定义带版本的 Cordis 包、运行其 host 与浏览器两半,并在编写代码前查询获准公开的运行时元数据。包生命周期与沙箱行为由 [`packages/extensions`](../../packages/extensions/README.md) 包组说明。
+
+<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
+
+<a id="cordis-surface"></a>
+
+## Cordis API
+
+Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+<a id="ctxcordisinspect--cordisinspectregistryservice"></a>
+
+### `ctx.cordisInspect` — `CordisInspectRegistryService`
+
+Registry and cross-page router behind the two model-facing inspect tools.
+
+```ts cordis-catalog
+/**
+ * Register one Host provider.
+ * @param registration - manifest and local query handler.
+ * @returns idempotent disposer.
+ */
+register(registration: HostCordisInspectProviderRegistration): () => void
+
+/**
+ * Replace the mirrored Client provider directory.
+ * @param providers - complete Client manifest snapshot.
+ */
+syncClientManifest(providers: readonly CordisInspectProviderManifest[]): void
+
+/**
+ * Return the complete known Host and Client provider directory.
+ * @returns Host providers followed by the Client providers.
+ */
+list(): CordisInspectProviderView[]
+
+/**
+ * Execute one provider query on its owning platform.
+ * @param platform - Host or Client runtime.
+ * @param providerId - provider selected from {@link list}.
+ * @param methodName - declared method name.
+ * @param input - optional lossless JSON input.
+ * @param agent - requesting Agent and scope.
+ * @param signal - tool-call cancellation.
+ * @returns provider JSON data.
+ */
+async query( platform: CordisInspectPlatform, providerId: string, methodName: string, input: JsonValue | undefined, agent: Agent, signal: AbortSignal, ): Promise<JsonValue>
+
+/**
+ * Accept the first valid Client response for a pending query.
+ * @param agent - Agent whose Session owns the query.
+ * @param requestId - Pending Client query identity.
+ * @param resolution - Client provider result or failure.
+ * @returns whether this response settled the still-pending query.
+ */
+resolveClientQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck
+```
+
+Types: [Agent](core.md)
+
+Source: [`packages/extensions/cordis-host-runner/src/inspect-registry.ts:46`](../../packages/extensions/cordis-host-runner/src/inspect-registry.ts)
+
+<a id="ctxdynamiccordisrunner--dynamiccordisrunnerservice"></a>
+
+### `ctx.dynamicCordisRunner` — `DynamicCordisRunnerService`
+
+Dynamic Plugin registry and Host-half lifecycle.
+
+```ts cordis-catalog
+/**
+ * Define a new Plugin's first Package or append a Package to an existing Plugin.
+ * @param request - Session ownership, Plugin selection, metadata, and source code.
+ * @returns Host-minted Plugin and Package identities with declared-half metadata.
+ */
+define(request: DynamicCordisDefineRequest): DynamicCordisDefineReceipt
+
+/**
+ * Remove a Plugin, its active run, and all immutable Packages.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to remove.
+ * @returns Whether removal succeeded and whether it stopped an active run.
+ */
+async undefine(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisUndefineReceipt>
+
+/**
+ * Remove a Plugin from the user panel and queue the resulting state change for the model's next step.
+ * @param agent - Agent whose Session owns the Plugin and receives the context.
+ * @param pluginId - Stable Plugin identity to remove.
+ * @returns Whether removal succeeded and whether it stopped an active run.
+ */
+@Remote('undefineFromPanel') async undefineFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisUndefineReceipt>
+
+/**
+ * Start or update one Package for a model tool call. An unauthorized Client
+ * Package waits for approval; Plugin-wide authorization covers later versions.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to activate.
+ * @param packageId - Immutable Package version to activate.
+ * @param mode - Whether to run the current version or switch versions.
+ * @param signal - Tool-call cancellation signal while the activation request is being created.
+ * @returns The successful activation identity or an actionable refusal.
+ */
+async run( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, signal?: AbortSignal, ): Promise<DynamicCordisRunResponse>
+
+/**
+ * Start Host code for an approved request or a direct panel gesture.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to activate.
+ * @param packageId - Immutable Package version to activate.
+ * @param mode - Whether to run the current version or switch versions.
+ * @param requestId - Model-driven request identity, or null for a direct user gesture.
+ * @param approveFutureVersions - Whether this approval covers later Packages of the same Plugin.
+ * @returns The exact Host activation or a failure message.
+ */
+@Remote('runHostHalf') async runHostHalf( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, mode: CordisDynamicRunMode, requestId: ApprovalRequestId | null, approveFutureVersions: boolean, ): Promise<DynamicCordisHostHalfResult>
+
+/**
+ * Fetch Client code for the exact active run.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to read.
+ * @param pluginRunId - Exact active run authorized to receive source.
+ * @returns Client source and its Plugin, Package, and run identities.
+ */
+@Remote('getClientCode') getClientCode( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, ): DynamicCordisClientSource
+
+/**
+ * Resolve one model-driven Client activation request.
+ * @param requestId - Request identity to settle once.
+ * @param resolution - Browser refusal or exact Client activation result.
+ * @returns Whether the still-pending request accepted this resolution.
+ */
+@Remote('resolveRequestRun') async resolveRequestRun( requestId: ApprovalRequestId, resolution: DynamicCordisRunResolution, ): Promise<DynamicCordisResolveAck>
+
+/**
+ * Settle a direct panel run after this page loaded or failed its Client half.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity being settled.
+ * @param resolution - Exact Client activation result from the acting page.
+ * @returns The committed activation or its failure.
+ */
+@Remote('settleUserRun') async settleUserRun( agent: Agent, pluginId: CordisDynamicPluginId, resolution: DynamicCordisRunResolution, ): Promise<DynamicCordisRunResponse>
+
+/**
+ * Stop the active run while retaining every Package version.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity to stop.
+ * @returns Success or the reason no run was stopped.
+ */
+async stop(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisStopResponse>
+
+/**
+ * Stop a Plugin from the user panel and queue the resulting state change for the model's next step.
+ * @param agent - Agent whose Session owns the Plugin and receives the context.
+ * @param pluginId - Stable Plugin identity to stop.
+ * @returns Success or the reason no run was stopped.
+ */
+@Remote('stopFromPanel') async stopFromPanel(agent: Agent, pluginId: CordisDynamicPluginId): Promise<DynamicCordisStopResponse>
+
+/**
+ * Replace the Host mirror of the Client inspect provider directory.
+ * @param providers - complete Client provider manifest.
+ * @returns null after accepting the manifest.
+ */
+@Remote('syncInspectManifest') syncInspectManifest(providers: readonly CordisInspectProviderManifest[]): null
+
+/**
+ * Claim one pending Client inspect query with its live result.
+ * @param agent - Session that owns the query.
+ * @param requestId - exact pending query identity.
+ * @param resolution - provider result or structured refusal.
+ * @returns whether this answer won the query.
+ */
+@Remote('resolveInspectQuery') resolveInspectQuery( agent: Agent, requestId: CordisInspectRequestId, resolution: CordisInspectQueryResolution, ): CordisInspectResolveAck
+
+/**
+ * Frame-wide inventory, grouped as one row per stable Plugin.
+ * @returns Source-free metadata for every process-local Plugin.
+ */
+@Remote('inventory') inventory(): DynamicCordisInventoryRow[]
+
+/**
+ * Read one Session's Host-rich state for inspection and result rendering.
+ * @param agent - Agent whose Session selects visible Plugins.
+ * @returns Plugin versions, active runs, Host fibers, and render failures.
+ */
+snapshot(agent: Agent): DynamicCordisSnapshotRow[]
+
+/**
+ * Read source-free context for an explicit `@pluginId` user gesture.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity referenced by the user.
+ * @returns The preferred modification base, or undefined when unavailable.
+ */
+reference(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisReference | undefined
+
+/**
+ * List source-free Plugin summaries owned by one Session.
+ * @param agent - Agent whose Session selects visible Plugins.
+ * @returns one summary per Plugin in creation order.
+ */
+listPlugins(agent: Agent): DynamicCordisPluginInspection[]
+
+/**
+ * Inspect one Plugin without returning Package source.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - stable Plugin identity.
+ * @returns version pointers, latest run, and all Package summaries.
+ */
+inspectPlugin(agent: Agent, pluginId: CordisDynamicPluginId): DynamicCordisPluginInspection
+
+/**
+ * Read one exact immutable Package and its Host and Client source.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity that owns the Package.
+ * @param packageId - Exact immutable Package identity to inspect.
+ * @returns Package metadata, source, and the Plugin's lifecycle pointers.
+ */
+inspectPackage( agent: Agent, pluginId: CordisDynamicPluginId, packageId: CordisDynamicPackageId, ): DynamicCordisPackageInspection
+
+/**
+ * Record a post-load render failure for the exact active run.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity that rendered.
+ * @param pluginRunId - Exact active run that produced the failure.
+ * @param failure - Slot, message, and entry-retirement result.
+ * @returns Null after recording or ignoring a stale report.
+ */
+@Remote('reportRenderFailure') async reportRenderFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: DynamicCordisRenderFailure, ): Promise<null>
+
+/**
+ * Report a Client guard rejection that happened after the Package completed activation.
+ * @param agent - Agent whose Session must own the Plugin.
+ * @param pluginId - Stable Plugin identity whose Client code was rejected.
+ * @param pluginRunId - Exact active run that produced the rejection.
+ * @param failure - Original guard message and stack.
+ * @returns Null after reporting or ignoring a stale/startup failure.
+ */
+@Remote('reportClientGuardFailure') async reportClientGuardFailure( agent: Agent, pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, failure: CordisErrorDetails, ): Promise<null>
+
+/**
+ * Invoke an active Host method while rejecting stale Client runs.
+ * @param pluginId - Stable Plugin identity that owns the method.
+ * @param pluginRunId - Exact active run authorizing the call.
+ * @param method - Registered Host handler name.
+ * @param args - JSON argument delivered to the handler.
+ * @returns The JSON result or a typed invocation failure.
+ */
+@Remote('invoke') async invoke( pluginId: CordisDynamicPluginId, pluginRunId: CordisDynamicPluginRunId, method: string, args: JsonValue, ): Promise<DynamicCordisInvokeResult>
+```
+
+Types: [Agent](core.md)
+
+Source: [`packages/extensions/cordis-host-runner/src/index.ts:124`](../../packages/extensions/cordis-host-runner/src/index.ts)
+
+<a id="cordis-events"></a>
+
+### `cordis/*` events
+
+<a id="cordisdynamic-package--emit"></a>
+
+#### `cordis/dynamic-package` — emit
+
+One exact Plugin/Package activation is now live in the Host.
+
+```ts cordis-catalog
+/**
+ * One exact Plugin/Package activation is now live in the Host.
+ * @param pkg - stable plugin, immutable package, run identity, and label.
+ * @mode emit
+ */
+'cordis/dynamic-package'(pkg: DynamicCordisPackage): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:379`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisdynamic-retract--emit"></a>
+
+#### `cordis/dynamic-retract` — emit
+
+One exact activation was withdrawn.
+
+```ts cordis-catalog
+/**
+ * One exact activation was withdrawn.
+ * @param retracted - plugin, package, and run identity.
+ * @mode emit
+ */
+'cordis/dynamic-retract'(retracted: DynamicCordisRetracted): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:385`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisinspect-query--emit"></a>
+
+#### `cordis/inspect-query` — emit
+
+Request a live read-only query from the Client inspect registry.
+
+```ts cordis-catalog
+/**
+ * Request a live read-only query from the Client inspect registry.
+ * @param request - correlation, Session, provider, method, and JSON input.
+ * @mode emit
+ */
+'cordis/inspect-query'(request: CordisInspectQueryRequest): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:391`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisinspect-query-resolved--emit"></a>
+
+#### `cordis/inspect-query-resolved` — emit
+
+Notify every Client that an inspect query has settled or been cancelled.
+
+```ts cordis-catalog
+/**
+ * Notify every Client that an inspect query has settled or been cancelled.
+ * @param resolved - exact query identity that is no longer answerable.
+ * @mode emit
+ */
+'cordis/inspect-query-resolved'(resolved: CordisInspectQueryResolved): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:397`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisrequest-run--emit"></a>
+
+#### `cordis/request-run` — emit
+
+A Client-bearing activation needs a browser page, and may require a user decision.
+
+```ts cordis-catalog
+/**
+ * A Client-bearing activation needs a browser page, and may require a user decision.
+ * @param request - correlation identity, owner, target version, mode, and approval requirement.
+ * @mode emit
+ */
+'cordis/request-run'(request: DynamicCordisRunRequest): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:367`](../../packages/extensions/cordis-host-runner/src/types.ts)
+
+<a id="cordisrequest-run-resolved--emit"></a>
+
+#### `cordis/request-run-resolved` — emit
+
+A pending Client activation request left the answerable state.
+
+```ts cordis-catalog
+/**
+ * A pending Client activation request left the answerable state.
+ * @param resolved - request identity and outcome.
+ * @mode emit
+ */
+'cordis/request-run-resolved'(resolved: DynamicCordisRequestResolved): void
+```
+
+Source: [`packages/extensions/cordis-host-runner/src/types.ts:373`](../../packages/extensions/cordis-host-runner/src/types.ts)
+<!-- END GENERATED cordis-surface -->

+ 2 - 2
docs/subsystems/lsp.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/subsystems/lsp.md
-lsp.md: fe2d30c84b3e2ccea82b9fb1edd370845267b6d9
-lsp.zh.md: d821a2493b78f8637d9917241838eaedf6e0af8b
+lsp.md: 66317acc25860cfeaa3d8fb35daf2947e811e18c
+lsp.zh.md: 8d975e30cb5065fd89645166c657050233eb81da

+ 37 - 0
docs/subsystems/lsp.md

@@ -163,3 +163,40 @@ interface LspService {
 ```
 
 `LspProviderId` is the seam's branded id (`Branded<'LspProviderId'>` from [dsh-brand](../../packages/util/brand)); `LspError` extends `HarnessError` with stable codes such as `LSP_INVALID_PROVIDER`, `LSP_CONFLICT`, `LSP_UNAVAILABLE`, `LSP_DISPOSED`, `LSP_UNSUPPORTED_OPERATION`, and `LSP_MALFORMED_RESPONSE`, which callers route on instead of parsing `message`.
+
+<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
+
+<a id="cordis-surface"></a>
+
+## Cordis API
+
+Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+<a id="ctxlsp--lspservice"></a>
+
+### `ctx.lsp` — `LspService`
+
+The LSP capability seam (`ctx.lsp`). Owns provider registration/selection and normalized query execution; exposes exactly the four operations and no protocol escape hatch.
+
+```ts cordis-catalog
+/**
+ * Register a provider, atomically reserving its id and every normalized extension. Any conflict
+ * or invalid input publishes nothing and throws `LspError`; the returned disposer releases all
+ * reservations. Disposed with the calling fiber.
+ * @param provider - the backend to register.
+ * @returns a synchronous disposer releasing the id and all extension reservations.
+ */
+registerProvider(provider: LspProvider): () => void
+
+/**
+ * Select a provider by the file's extension and run one query. Selection is per-query and
+ * order-independent; no match throws `LspError` `LSP_UNAVAILABLE`.
+ * @param request - the normalized query.
+ * @param signal - optional cancellation forwarded to the selected provider.
+ * @returns the normalized, closed-union result.
+ */
+query(request: LspQueryRequest, signal?: AbortSignal): Promise<LspQueryResult>
+```
+
+Source: [`packages/lsp/lsp/src/types.ts:113`](../../packages/lsp/lsp/src/types.ts)
+<!-- END GENERATED cordis-surface -->

+ 37 - 0
docs/subsystems/lsp.zh.md

@@ -163,3 +163,40 @@ interface LspService {
 ```
 
 `LspProviderId` 是该 seam 的品牌化 id(来自 [dsh-brand](../../packages/util/brand) 的 `Branded<'LspProviderId'>`);`LspError` 扩展 `HarnessError`,提供 `LSP_INVALID_PROVIDER`、`LSP_CONFLICT`、`LSP_UNAVAILABLE`、`LSP_DISPOSED`、`LSP_UNSUPPORTED_OPERATION` 和 `LSP_MALFORMED_RESPONSE` 等稳定错误码,调用方应按错误码路由,而不是解析 `message`。
+
+<!-- BEGIN GENERATED cordis-surface (gen-cordis-catalog.ts) — do not edit between markers -->
+
+<a id="cordis-surface"></a>
+
+## Cordis API
+
+Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
+
+<a id="ctxlsp--lspservice"></a>
+
+### `ctx.lsp` — `LspService`
+
+The LSP capability seam (`ctx.lsp`). Owns provider registration/selection and normalized query execution; exposes exactly the four operations and no protocol escape hatch.
+
+```ts cordis-catalog
+/**
+ * Register a provider, atomically reserving its id and every normalized extension. Any conflict
+ * or invalid input publishes nothing and throws `LspError`; the returned disposer releases all
+ * reservations. Disposed with the calling fiber.
+ * @param provider - the backend to register.
+ * @returns a synchronous disposer releasing the id and all extension reservations.
+ */
+registerProvider(provider: LspProvider): () => void
+
+/**
+ * Select a provider by the file's extension and run one query. Selection is per-query and
+ * order-independent; no match throws `LspError` `LSP_UNAVAILABLE`.
+ * @param request - the normalized query.
+ * @param signal - optional cancellation forwarded to the selected provider.
+ * @returns the normalized, closed-union result.
+ */
+query(request: LspQueryRequest, signal?: AbortSignal): Promise<LspQueryResult>
+```
+
+Source: [`packages/lsp/lsp/src/types.ts:113`](../../packages/lsp/lsp/src/types.ts)
+<!-- END GENERATED cordis-surface -->

+ 2 - 2
docs/subsystems/system-prompt.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/subsystems/system-prompt.md
-system-prompt.md: f03d11866bcdcf3bcb5c5fe96931b059cb8d0336
-system-prompt.zh.md: 23b3e0b20cc4772baf22727d2e57866aa7cbbeb0
+system-prompt.md: 8a6006d0b96552b52d0b050c304a11a95add8d9e
+system-prompt.zh.md: 02be9eed795d3a6c8e43403048f135d493b6509d

+ 9 - 1
docs/subsystems/system-prompt.md

@@ -117,6 +117,14 @@ section(section: PromptSection): () => void
  */
 context(context: PromptContext): () => void
 
+/**
+ * Suppress every dynamic runtime-context contribution in the calling
+ * context's scope without changing the services that own or enforce those
+ * facts. Multiple suppressors remain independently disposable.
+ * @returns the exact Cordis effect disposer.
+ */
+suppressRuntimeContext(): () => void
+
 /**
  * Register a tool-schema provider in the calling context's scope. Global and
  * matching scoped providers both contribute; returning the reserved
@@ -148,7 +156,7 @@ variable(name: string, provider: (context: AssembleContext) => string | undefine
 async assemble(context: AssembleContext = {}): Promise<PromptAssembly>
 ```
 
-Source: [`packages/core/system-prompt/src/index.ts:334`](../../packages/core/system-prompt/src/index.ts)
+Source: [`packages/core/system-prompt/src/index.ts:338`](../../packages/core/system-prompt/src/index.ts)
 
 <a id="system-prompt-events"></a>
 

+ 9 - 1
docs/subsystems/system-prompt.zh.md

@@ -117,6 +117,14 @@ section(section: PromptSection): () => void
  */
 context(context: PromptContext): () => void
 
+/**
+ * Suppress every dynamic runtime-context contribution in the calling
+ * context's scope without changing the services that own or enforce those
+ * facts. Multiple suppressors remain independently disposable.
+ * @returns the exact Cordis effect disposer.
+ */
+suppressRuntimeContext(): () => void
+
 /**
  * Register a tool-schema provider in the calling context's scope. Global and
  * matching scoped providers both contribute; returning the reserved
@@ -148,7 +156,7 @@ variable(name: string, provider: (context: AssembleContext) => string | undefine
 async assemble(context: AssembleContext = {}): Promise<PromptAssembly>
 ```
 
-Source: [`packages/core/system-prompt/src/index.ts:334`](../../packages/core/system-prompt/src/index.ts)
+Source: [`packages/core/system-prompt/src/index.ts:338`](../../packages/core/system-prompt/src/index.ts)
 
 <a id="system-prompt-events"></a>
 

+ 2 - 2
docs/subsystems/typert.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/subsystems/typert.md
-typert.md: 19d517f85ebd9372252608124fef4f513b1462a0
-typert.zh.md: ee69f6fa7d99cb44f8e7f07bd4cd82fc70c1fa18
+typert.md: 863ab9821bbf3681ae43df817cc04018e275390c
+typert.zh.md: 4883b4be51a09d8e63001284e42bd7e60497bf1d

+ 17 - 0
docs/subsystems/typert.md

@@ -233,6 +233,23 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
 
 Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
 
+<a id="ctxapiproxy--apiproxy"></a>
+
+### `ctx.apiProxy` — `ApiProxy`
+
+Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row.
+
+```ts cordis-catalog
+/**
+ * Response entry for server requests; not a domain method.
+ * @param message - Client response carrying the server request's rpcId.
+ * @returns Transport receipt for the response delivery.
+ */
+respond(message: ClientResponse): Promise<RpcReceipt>
+```
+
+Source: [`packages/host/apiproxy/src/api/index.ts:22`](../../packages/host/apiproxy/src/api/index.ts)
+
 <a id="ctxtypert--typertregistry"></a>
 
 ### `ctx.typert` — `TypertRegistry`

+ 17 - 0
docs/subsystems/typert.zh.md

@@ -233,6 +233,23 @@ interface TypertClientRemote extends TypertRemoteNamespaceMap {
 
 Generated from source by `scripts/gen-cordis-catalog.ts` (verified fresh by `pnpm run verify-cordis-catalog` in doc-sync; regenerate with `pnpm run gen-cordis-catalog`) — this section is byte-identical in both language sides of the page. Signature blocks use a `ts cordis-catalog` fence and keep the original source JSDoc; dispatch modes are defined in the [primer](../cordis-primer.md#dispatch-modes), and the framework-inherited `ctx` API lives in [cordis-api/inherited.md](../cordis-api/inherited.md).
 
+<a id="ctxapiproxy--apiproxy"></a>
+
+### `ctx.apiProxy` — `ApiProxy`
+
+Root interface of the unified API. New client-request domain = one new file pair + one field here + one map row.
+
+```ts cordis-catalog
+/**
+ * Response entry for server requests; not a domain method.
+ * @param message - Client response carrying the server request's rpcId.
+ * @returns Transport receipt for the response delivery.
+ */
+respond(message: ClientResponse): Promise<RpcReceipt>
+```
+
+Source: [`packages/host/apiproxy/src/api/index.ts:22`](../../packages/host/apiproxy/src/api/index.ts)
+
 <a id="ctxtypert--typertregistry"></a>
 
 ### `ctx.typert` — `TypertRegistry`

+ 2 - 2
docs/tool-catalog.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write docs/tool-catalog.md
-tool-catalog.md: f4fb7fe2a7ae65f779ae5ded146098deb2be9ad0
-tool-catalog.zh.md: 49ea51446e93c2224bd8f173e6f473e439f6100a
+tool-catalog.md: afe98bf192b160fcb8c660aa8f621ad22c01ce5d
+tool-catalog.zh.md: ec3a1d2532200be8c01ecff76d24d4de17e23034

File diff suppressed because it is too large
+ 140 - 15
docs/tool-catalog.md


File diff suppressed because it is too large
+ 140 - 15
docs/tool-catalog.zh.md


+ 2 - 0
examples/acp-agent/advanced.cordis.snapshot.yml

@@ -25,6 +25,8 @@
       - insert:
           - id: code-runtime
             name: '@deepseek-ai/dsh-code-runtime-worker-thread'
+          - id: cordis-host-runner
+            name: '@deepseek-ai/dsh-cordis-host-runner'
           - id: tool-cordis
             name: '@deepseek-ai/dsh-tool-cordis'
           - id: llm-replay

+ 2 - 0
examples/acp-agent/advanced.cordis.yml

@@ -23,5 +23,7 @@
       - insert:
           - id: code-runtime
             name: '@deepseek-ai/dsh-code-runtime-worker-thread'
+          - id: cordis-host-runner
+            name: '@deepseek-ai/dsh-cordis-host-runner'
           - id: tool-cordis
             name: '@deepseek-ai/dsh-tool-cordis'

+ 2 - 0
examples/acp-agent/cordis-tools.cordis.yml

@@ -6,5 +6,7 @@
     path: ./cordis.yml
     patches:
       - insert:
+          - id: cordis-host-runner
+            name: '@deepseek-ai/dsh-cordis-host-runner'
           - id: tool-cordis
             name: '@deepseek-ai/dsh-tool-cordis'

+ 3 - 2
examples/acp-agent/tests/acp.snapshot.ts

@@ -491,8 +491,9 @@ const SCENARIOS: Scenario[] = [
   // child runs as a spawn subagent under the worker-thread engine (its session is the
   // child fixture), and the tool result carries the script's return value.
   { name: 'workflow-run', hasModelTurn: true, recorded: true },
-  // Authored counterpart to the packaged Python SDK snapshot: mount a live marker, inspect it
-  // through Code Mode, run direct and workflow children, then unmount it. The extra Code Mode and
+  // Authored counterpart to the packaged Python SDK snapshot: define a host-half marker package and
+  // run it, inspect this session's dynamic packages through Code Mode, run direct and workflow
+  // children, then undefine it. The extra Code Mode and
   // Cordis plugins require their own request-header pin; the fixture tests deterministic composition.
   {
     name: 'advanced-toolchain',

+ 10 - 3
examples/acp-agent/tests/snapshots/advanced-toolchain/input.json

@@ -1,7 +1,14 @@
 {
   "steps": [
-    { "op": "initialize" },
-    { "op": "newSession" },
-    { "op": "prompt", "text": "Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_ACP_OK." }
+    {
+      "op": "initialize"
+    },
+    {
+      "op": "newSession"
+    },
+    {
+      "op": "prompt",
+      "text": "Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_ACP_OK."
+    }
   ]
 }

+ 1 - 1
examples/acp-agent/tests/snapshots/advanced-toolchain/session.1.jsonl

@@ -6,7 +6,7 @@
 {"type":"subagent/descriptor","seq":4,"time":1786357538308,"data":{"version":2,"mode":"one-shot","provider":"spawn","label":"Check direct child"}}
 {"type":"step/start","seq":5,"time":1786357538310,"data":{"turn":1,"step":1}}
 {"type":"user/message","seq":6,"time":1785730458555,"data":{"content":[{"type":"text","text":"Reply with exactly DIRECT_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"ebe0cfa0-a909-47e0-8294-28ad84a8fe77"},"surfaceOp":"append"}
-{"type":"user/message","seq":7,"time":1786357538310,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"511768bb-311b-4ea7-ab14-5c0524812613"},"surfaceOp":"append"}
+{"type":"user/message","seq":7,"time":1786357538310,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"21c656d1-bb34-4dcd-8d27-9eac72ffcd72"},"surfaceOp":"append"}
 {"type":"session/title","seq":8,"time":1786357538310,"data":{"title":"Reply with exactly DIRECT_CHILD_OK and","messageSeqs":[6],"source":{"kind":"fallback"}}}
 {"type":"request/header","seq":9,"time":1785730458555,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
 {"type":"request/context","seq":10,"time":1785730458555,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}

+ 1 - 1
examples/acp-agent/tests/snapshots/advanced-toolchain/session.2.jsonl

@@ -6,7 +6,7 @@
 {"type":"subagent/descriptor","seq":4,"time":1786357538469,"data":{"version":2,"mode":"one-shot","provider":"spawn"}}
 {"type":"step/start","seq":5,"time":1786357538470,"data":{"turn":1,"step":1}}
 {"type":"user/message","seq":6,"time":1785730458703,"data":{"content":[{"type":"text","text":"Reply with exactly WORKFLOW_CHILD_OK and nothing else."}],"source":{"kind":"user"},"role":"user","id":"2ac2cc54-9bce-4cfa-a569-a64f51bc30a7"},"surfaceOp":"append"}
-{"type":"user/message","seq":7,"time":1786357538471,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"2b3e4c08-fa23-47d9-873a-599e0345fdc4"},"surfaceOp":"append"}
+{"type":"user/message","seq":7,"time":1786357538471,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`).\n\nYou are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."},{"name":"subagent:delegation","text":"You are a delegated subagent: your permission scope was fixed when you were started and cannot be widened from inside this session — operations that require approval are rejected automatically. When the task needs access beyond that scope, do not retry the denied operation; state the limitation in your reply so the delegating agent can handle it."}]},"role":"user","id":"1843b045-94c6-4f30-b1f0-21a3adc04fe9"},"surfaceOp":"append"}
 {"type":"session/title","seq":8,"time":1786357538471,"data":{"title":"Reply with exactly WORKFLOW_CHILD_OK and","messageSeqs":[6],"source":{"kind":"fallback"}}}
 {"type":"request/header","seq":9,"time":1785730458703,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
 {"type":"request/context","seq":10,"time":1785730458703,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}

+ 60 - 58
examples/acp-agent/tests/snapshots/advanced-toolchain/session.jsonl

@@ -1,74 +1,76 @@
 {"type":"session","version":0,"id":"11111111-1111-4111-8111-111111111111","createdAt":1783950000000,"cwd":"{{cwd}}","delegationDepth":0}
-{"type":"agent/inbox/spliced","seq":0,"time":1785498801734,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_ACP_OK."}],"source":{"kind":"user"},"role":"user","id":"6e45782a-31be-4ba7-8c4a-7411a2027e36"}]}}
+{"type":"agent/inbox/spliced","seq":0,"time":1785498801734,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_ACP_OK."}],"source":{"kind":"user"},"role":"user","id":"6a989c18-ce01-46ce-8105-43789f710fb5"}]}}
 {"type":"turn/start","seq":1,"time":1785821417918,"data":{"turn":1}}
 {"type":"agent/inbox/spliced","seq":2,"time":1785821417919,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
 {"type":"step/start","seq":3,"time":1783957884486,"data":{"turn":1,"step":1}}
-{"type":"user/message","seq":4,"time":1785498801761,"data":{"content":[{"type":"text","text":"Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_ACP_OK."}],"source":{"kind":"user"},"role":"user","id":"6e45782a-31be-4ba7-8c4a-7411a2027e36"},"surfaceOp":"append"}
+{"type":"user/message","seq":4,"time":1785498801761,"data":{"content":[{"type":"text","text":"Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_ACP_OK."}],"source":{"kind":"user"},"role":"user","id":"6a989c18-ce01-46ce-8105-43789f710fb5"},"surfaceOp":"append"}
 {"type":"user/message","seq":5,"time":1785730458430,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations.\n\nApproval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."},{"name":"approval:policy","text":"Approval prompts are disabled in this session: actions that require approval are rejected automatically — do not request sandbox escalation (do not set `sandbox_permissions`)."}]},"role":"user","id":"f66cc92b-b90c-4aeb-9568-7463d5eeede9"},"surfaceOp":"append"}
 {"type":"session/title","seq":6,"time":1785730458430,"data":{"title":"Run this advanced flow exactly","messageSeqs":[4],"source":{"kind":"fallback"}}}
 {"type":"request/header","seq":7,"time":1785498801765,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
 {"type":"request/context","seq":8,"time":1785730458431,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
 {"type":"assistant/chunk","seq":9,"time":1783950000007,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":10,"time":1783950000008,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-mount","name":"cordis_mount","argumentsDelta":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}}
-{"type":"assistant/chunk","seq":11,"time":1783950000009,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}}}
+{"type":"assistant/chunk","seq":10,"time":1783950000008,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-define","name":"cordis_define","argumentsDelta":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}}
+{"type":"assistant/chunk","seq":11,"time":1783950000009,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}}}
 {"type":"assistant/chunk","seq":12,"time":1785498801774,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
 {"type":"assistant/chunk","seq":13,"time":1785730458439,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":14,"time":1785730458440,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0713b7ec-0182-4820-8ec1-39d0371b533b"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
-{"type":"tool/call","seq":15,"time":1785730458440,"data":{"turn":1,"step":1,"callId":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}
-{"type":"tool/result","seq":16,"time":1785730458450,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-mount"},"content":[{"type":"tool-result","toolCallId":"advanced-mount","content":[{"type":"text","text":"Temporary Plugin dyn-1 is running (plugin \"snapshot-marker\"; available until unmounted or DSH restarts)."}],"isError":false}],"role":"user","id":"b10e76f0-e1a5-4c2c-b6a2-6cbdcf259cca"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
+{"type":"assistant/message","seq":14,"time":1785730458440,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0713b7ec-0182-4820-8ec1-39d0371b533b"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
+{"type":"tool/call","seq":15,"time":1785730458440,"data":{"turn":1,"step":1,"callId":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}
+{"type":"tool/result","seq":16,"time":1785730458450,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-define"},"content":[{"type":"tool-result","toolCallId":"advanced-define","content":[{"type":"text","text":"Defined snap-1/pkg-1 (Snapshot Marker); it is not running yet. Use cordis_run to activate this Package."}],"isError":false}],"role":"user","id":"e583400c-a37d-4f0a-ba44-f57a1ab063bd"},"meta":{"pluginId":"snap-1","packageId":"pkg-1"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
 {"type":"step/end","seq":17,"time":1785730458450,"data":{"turn":1,"step":1}}
 {"type":"step/start","seq":18,"time":1785730458460,"data":{"turn":1,"step":2}}
 {"type":"assistant/chunk","seq":19,"time":1783950000017,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":20,"time":1783950000018,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-code","name":"run_code","argumentsDelta":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}}
-{"type":"assistant/chunk","seq":21,"time":1783950000019,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}}}
+{"type":"assistant/chunk","seq":20,"time":1783950000018,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-code","name":"run_code","argumentsDelta":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}}
+{"type":"assistant/chunk","seq":21,"time":1783950000019,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}}}
 {"type":"assistant/chunk","seq":22,"time":1785498801800,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
 {"type":"assistant/chunk","seq":23,"time":1785730458465,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":24,"time":1785730458465,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"e3061430-3f2d-4dd8-a3ee-c0fde800547d"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[19,20,21,22,23],"surfaceOp":"append"}
-{"type":"tool/call","seq":25,"time":1785730458465,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}
-{"type":"tool/code-dispatch-start","seq":26,"time":1785730458517,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"temporary"}}}
-{"type":"tool/code-dispatch","seq":27,"time":1785730458518,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"temporary"},"isError":false,"content":[{"type":"text","text":"## Temporary Plugins\n- Temporary Plugin dyn-1: snapshot-marker [running] — provides: none; waiting for: none; lifetime: until unmounted or DSH restarts"}]}}
-{"type":"tool/result","seq":28,"time":1785730458520,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"## Temporary Plugins\n- Temporary Plugin dyn-1: snapshot-marker [running] — provides: none; waiting for: none; lifetime: until unmounted or DSH restarts"}],"isError":false}],"role":"user","id":"4dce223d-0097-4ac2-a717-d1c430240cef"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
-{"type":"step/end","seq":29,"time":1785730458520,"data":{"turn":1,"step":2}}
-{"type":"step/start","seq":30,"time":1785730458527,"data":{"turn":1,"step":3}}
-{"type":"assistant/chunk","seq":31,"time":1783950000029,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":32,"time":1783950000030,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-direct-child","name":"subagent","argumentsDelta":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}
-{"type":"assistant/chunk","seq":33,"time":1785036891179,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}
-{"type":"assistant/chunk","seq":34,"time":1785498801872,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":35,"time":1785730458531,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":36,"time":1785730458531,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"51fe1d59-eebc-457b-a072-fe217546ff04"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[31,32,33,34,35],"surfaceOp":"append"}
-{"type":"tool/call","seq":37,"time":1785730458531,"data":{"turn":1,"step":3,"callId":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}
-{"type":"tool/result","seq":38,"time":1785730458562,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"09028579-5ae5-4d57-955e-02504f4dfc2a"}},"sourceEventSeqs":[37],"surfaceOp":"append"}
-{"type":"step/end","seq":39,"time":1785730458563,"data":{"turn":1,"step":3}}
-{"type":"step/start","seq":40,"time":1785730458572,"data":{"turn":1,"step":4}}
-{"type":"assistant/chunk","seq":41,"time":1783957884594,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":42,"time":1783957884594,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-workflow","name":"workflow","argumentsDelta":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}}
-{"type":"assistant/chunk","seq":43,"time":1785036891211,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}}}
-{"type":"assistant/chunk","seq":44,"time":1785498801920,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":45,"time":1785730458577,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":46,"time":1785730458577,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ebeca5c6-68ae-43b3-87c3-c48fdfe416c8"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[41,42,43,44,45],"surfaceOp":"append"}
-{"type":"tool/call","seq":47,"time":1785730458577,"data":{"turn":1,"step":4,"callId":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}
-{"type":"tool-workflow/run-start","seq":48,"time":1786359248404,"data":{"runId":"2f6d6a6e-6d76-4a8a-8677-6671366645dc","name":"advanced-acp-snapshot"}}
-{"type":"tool-workflow/agent-start","seq":49,"time":1786359248518,"data":{"runId":"2f6d6a6e-6d76-4a8a-8677-6671366645dc","seq":1,"label":"workflow-child","phase":"Delegate","childId":"33333333-3333-4333-8333-333333333333"}}
-{"type":"tool-workflow/agent-end","seq":50,"time":1786359248542,"data":{"runId":"2f6d6a6e-6d76-4a8a-8677-6671366645dc","seq":1,"outcome":"completed"}}
-{"type":"tool-workflow/run-end","seq":51,"time":1786359248543,"data":{"runId":"2f6d6a6e-6d76-4a8a-8677-6671366645dc","stopReason":"completed"}}
-{"type":"tool/result","seq":52,"time":1786359248543,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-acp-snapshot\" completed (1 agent).\nReturn value:\n{\n  \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"f892f17e-1e93-4f4b-9e9e-15116593b6fc"}},"sourceEventSeqs":[47],"surfaceOp":"append"}
-{"type":"step/end","seq":53,"time":1786359248543,"data":{"turn":1,"step":4}}
-{"type":"step/start","seq":54,"time":1786359248550,"data":{"turn":1,"step":5}}
-{"type":"assistant/chunk","seq":55,"time":1785730458728,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":56,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-unmount","name":"cordis_unmount","argumentsDelta":"{\"id\":\"dyn-1\"}"}}}
-{"type":"assistant/chunk","seq":57,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}}}}
-{"type":"assistant/chunk","seq":58,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":59,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":60,"time":1786359248554,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"1291ce3c-e568-4f0d-a95a-5157b8b2cc75"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[55,56,57,58,59],"surfaceOp":"append"}
-{"type":"tool/call","seq":61,"time":1786359248554,"data":{"turn":1,"step":5,"callId":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}}
-{"type":"tool/result","seq":62,"time":1786359248558,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-unmount"},"content":[{"type":"tool-result","toolCallId":"advanced-unmount","content":[{"type":"text","text":"Temporary Plugin dyn-1 was unmounted and removed."}],"isError":false}],"role":"user","id":"b3634221-2358-4e82-aac5-e37f0a115023"}},"sourceEventSeqs":[61],"surfaceOp":"append"}
-{"type":"step/end","seq":63,"time":1786359248558,"data":{"turn":1,"step":5}}
-{"type":"step/start","seq":64,"time":1786359248564,"data":{"turn":1,"step":6}}
-{"type":"assistant/chunk","seq":65,"time":1785730458751,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
-{"type":"assistant/chunk","seq":66,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"text-delta","index":0,"text":"ADVANCED_ACP_OK"}}}
-{"type":"assistant/chunk","seq":67,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"ADVANCED_ACP_OK"}}}}
-{"type":"assistant/chunk","seq":68,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":69,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
-{"type":"assistant/message","seq":70,"time":1786359248568,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_ACP_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"a32b89ce-13ed-48ba-a7f9-24144b94ec56"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[65,66,67,68,69],"surfaceOp":"append"}
-{"type":"step/end","seq":71,"time":1786359248568,"data":{"turn":1,"step":6}}
-{"type":"turn/end","seq":72,"time":1786359248568,"data":{"turn":1,"reason":{"kind":"completed"}}}
+{"type":"assistant/message","seq":24,"time":1785730458465,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"e3061430-3f2d-4dd8-a3ee-c0fde800547d"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[19,20,21,22,23],"surfaceOp":"append"}
+{"type":"tool/call","seq":25,"time":1785730458465,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}
+{"type":"tool/code-dispatch-start","seq":26,"time":1785730458517,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_run","arguments":{"pluginId":"snap-1","packageId":"pkg-1","mode":"run"}}}
+{"type":"tool/code-dispatch","seq":27,"time":1785730458518,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_run","arguments":{"pluginId":"snap-1","packageId":"pkg-1","mode":"run"},"isError":false,"content":[{"type":"text","text":"snap-1/pkg-1 is running (run-1)."}]}}
+{"type":"tool/code-dispatch-start","seq":28,"time":1786553843104,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:2","name":"cordis_inspect_self","arguments":{"pluginId":"snap-1"}}}
+{"type":"tool/code-dispatch","seq":29,"time":1786553843104,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:2","name":"cordis_inspect_self","arguments":{"pluginId":"snap-1"},"isError":false,"content":[{"type":"text","text":"{\n  \"mode\": \"plugin\",\n  \"pluginId\": \"snap-1\",\n  \"name\": \"Snapshot Marker\",\n  \"packageCount\": 1,\n  \"state\": \"running\",\n  \"currentPackageId\": \"pkg-1\",\n  \"activeRun\": {\n    \"pluginRunId\": \"run-1\",\n    \"packageId\": \"pkg-1\"\n  },\n  \"packages\": [\n    {\n      \"packageId\": \"pkg-1\",\n      \"name\": \"Snapshot Marker\",\n      \"purpose\": \"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\n      \"hasHostHalf\": true,\n      \"hasClientHalf\": false,\n      \"isCurrent\": true,\n      \"isNext\": false\n    }\n  ]\n}"}]}}
+{"type":"tool/result","seq":30,"time":1786553843106,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"{\n  \"run\": {\n    \"status\": \"running\",\n    \"pluginId\": \"snap-1\",\n    \"packageId\": \"pkg-1\",\n    \"pluginRunId\": \"run-1\",\n    \"currentPackageId\": \"pkg-1\",\n    \"host\": {\n      \"status\": \"running\",\n      \"provides\": [],\n      \"waitingFor\": []\n    },\n    \"client\": {\n      \"status\": \"absent\",\n      \"waitingFor\": []\n    }\n  },\n  \"inspected\": {\n    \"mode\": \"plugin\",\n    \"pluginId\": \"snap-1\",\n    \"name\": \"Snapshot Marker\",\n    \"packageCount\": 1,\n    \"state\": \"running\",\n    \"currentPackageId\": \"pkg-1\",\n    \"activeRun\": {\n      \"pluginRunId\": \"run-1\",\n      \"packageId\": \"pkg-1\"\n    },\n    \"packages\": [\n      {\n        \"packageId\": \"pkg-1\",\n        \"name\": \"Snapshot Marker\",\n        \"purpose\": \"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\n        \"hasHostHalf\": true,\n        \"hasClientHalf\": false,\n        \"isCurrent\": true,\n        \"isNext\": false\n      }\n    ]\n  }\n}"}],"isError":false}],"role":"user","id":"fe7613ff-5837-4493-af89-0c06f1ef1010"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
+{"type":"step/end","seq":31,"time":1786553843106,"data":{"turn":1,"step":2}}
+{"type":"step/start","seq":32,"time":1786553843113,"data":{"turn":1,"step":3}}
+{"type":"assistant/chunk","seq":33,"time":1785036891179,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":34,"time":1785498801872,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-direct-child","name":"subagent","argumentsDelta":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}
+{"type":"assistant/chunk","seq":35,"time":1785730458531,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}
+{"type":"assistant/chunk","seq":36,"time":1786553843117,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":37,"time":1786553843117,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":38,"time":1786553843117,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"51fe1d59-eebc-457b-a072-fe217546ff04"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[33,34,35,36,37],"surfaceOp":"append"}
+{"type":"tool/call","seq":39,"time":1786553843118,"data":{"turn":1,"step":3,"callId":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}
+{"type":"tool/result","seq":40,"time":1786553843151,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"09028579-5ae5-4d57-955e-02504f4dfc2a"}},"sourceEventSeqs":[39],"surfaceOp":"append"}
+{"type":"step/end","seq":41,"time":1786553843151,"data":{"turn":1,"step":3}}
+{"type":"step/start","seq":42,"time":1786553843157,"data":{"turn":1,"step":4}}
+{"type":"assistant/chunk","seq":43,"time":1785036891211,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":44,"time":1785498801920,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-workflow","name":"workflow","argumentsDelta":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}}
+{"type":"assistant/chunk","seq":45,"time":1785730458577,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}}}
+{"type":"assistant/chunk","seq":46,"time":1786553843162,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":47,"time":1786553843162,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":48,"time":1786553843162,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ebeca5c6-68ae-43b3-87c3-c48fdfe416c8"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[43,44,45,46,47],"surfaceOp":"append"}
+{"type":"tool/call","seq":49,"time":1786553843163,"data":{"turn":1,"step":4,"callId":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-acp-snapshot\",\"description\":\"exercise one workflow child through ACP\"}}"}}
+{"type":"tool-workflow/run-start","seq":50,"time":1786553843167,"data":{"runId":"8ae2383b-3e28-438d-b9fd-1823db77fdaa","name":"advanced-acp-snapshot"}}
+{"type":"tool-workflow/agent-start","seq":51,"time":1786553843285,"data":{"runId":"8ae2383b-3e28-438d-b9fd-1823db77fdaa","seq":1,"label":"workflow-child","phase":"Delegate","childId":"33333333-3333-4333-8333-333333333333"}}
+{"type":"tool-workflow/agent-end","seq":52,"time":1786553843313,"data":{"runId":"8ae2383b-3e28-438d-b9fd-1823db77fdaa","seq":1,"outcome":"completed"}}
+{"type":"tool-workflow/run-end","seq":53,"time":1786553843314,"data":{"runId":"8ae2383b-3e28-438d-b9fd-1823db77fdaa","stopReason":"completed"}}
+{"type":"tool/result","seq":54,"time":1786553843314,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-acp-snapshot\" completed (1 agent).\nReturn value:\n{\n  \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"f892f17e-1e93-4f4b-9e9e-15116593b6fc"}},"sourceEventSeqs":[49],"surfaceOp":"append"}
+{"type":"step/end","seq":55,"time":1786553843314,"data":{"turn":1,"step":4}}
+{"type":"step/start","seq":56,"time":1786553843321,"data":{"turn":1,"step":5}}
+{"type":"assistant/chunk","seq":57,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":58,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-undefine","name":"cordis_undefine","argumentsDelta":"{\"pluginId\":\"snap-1\"}"}}}
+{"type":"assistant/chunk","seq":59,"time":1786359248554,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}}}}
+{"type":"assistant/chunk","seq":60,"time":1786553843325,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":61,"time":1786553843325,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":62,"time":1786553843325,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"1291ce3c-e568-4f0d-a95a-5157b8b2cc75"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[57,58,59,60,61],"surfaceOp":"append"}
+{"type":"tool/call","seq":63,"time":1786553843325,"data":{"turn":1,"step":5,"callId":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}}
+{"type":"tool/result","seq":64,"time":1786553843329,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-undefine"},"content":[{"type":"tool-result","toolCallId":"advanced-undefine","content":[{"type":"text","text":"Removed dynamic Plugin snap-1 and all of its Packages."}],"isError":false}],"role":"user","id":"dd45db06-baa0-4e48-ad52-681b511c8f80"}},"sourceEventSeqs":[63],"surfaceOp":"append"}
+{"type":"step/end","seq":65,"time":1786553843330,"data":{"turn":1,"step":5}}
+{"type":"step/start","seq":66,"time":1786553843337,"data":{"turn":1,"step":6}}
+{"type":"assistant/chunk","seq":67,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
+{"type":"assistant/chunk","seq":68,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"text-delta","index":0,"text":"ADVANCED_ACP_OK"}}}
+{"type":"assistant/chunk","seq":69,"time":1786359248568,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"ADVANCED_ACP_OK"}}}}
+{"type":"assistant/chunk","seq":70,"time":1786553843341,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":71,"time":1786553843341,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
+{"type":"assistant/message","seq":72,"time":1786553843341,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_ACP_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"a32b89ce-13ed-48ba-a7f9-24144b94ec56"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[67,68,69,70,71],"surfaceOp":"append"}
+{"type":"step/end","seq":73,"time":1786553843342,"data":{"turn":1,"step":6}}
+{"type":"turn/end","seq":74,"time":1786553843342,"data":{"turn":1,"reason":{"kind":"completed"}}}

File diff suppressed because it is too large
+ 128 - 7
examples/acp-agent/tests/snapshots/advanced-toolchain/system-prompt.expected.md


File diff suppressed because it is too large
+ 122 - 13
examples/acp-agent/tests/snapshots/advanced-toolchain/tool-schemas.expected.json


+ 1 - 1
examples/acp-agent/tests/snapshots/both-mode-turn/system-prompt.expected.md

@@ -25,7 +25,7 @@ Use subagent in the background by default. Start independent delegations togethe
 
 ## Writing code for run_code
 
-Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
+`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
 
 - Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
 - A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.

+ 1 - 1
examples/acp-agent/tests/snapshots/both-mode-turn/tool-schemas.expected.json

@@ -246,7 +246,7 @@
     },
     {
       "name": "run_code",
-      "description": "Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
+      "description": "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
       "parameters": {
         "type": "object",
         "properties": {

+ 1 - 1
examples/acp-agent/tests/snapshots/code-mode-turn/system-prompt.expected.md

@@ -27,7 +27,7 @@ Use subagent in the background by default. Start independent delegations togethe
 
 ## Writing code for run_code
 
-Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
+`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
 
 - Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
 - A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.

+ 1 - 1
examples/acp-agent/tests/snapshots/code-mode-turn/tool-schemas.expected.json

@@ -2,7 +2,7 @@
   "initial": [
     {
       "name": "run_code",
-      "description": "Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
+      "description": "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
       "parameters": {
         "type": "object",
         "properties": {

+ 1 - 1
examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/input.json

@@ -2,6 +2,6 @@
   "steps": [
     { "op": "initialize" },
     { "op": "newSession" },
-    { "op": "prompt", "text": "Inspect the exact tools service API and tools/pre-execute event with cordis_inspect, then reply with exactly CORDIS_INSPECT_JSDOC_OK." }
+    { "op": "prompt", "text": "Inspect the exact tools service API and tools/pre-execute event with cordis_inspect_query, then reply with exactly CORDIS_INSPECT_JSDOC_OK." }
   ]
 }

File diff suppressed because it is too large
+ 4 - 6
examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl


+ 2 - 0
examples/headless-agent/advanced.cordis.snapshot.yml

@@ -41,6 +41,8 @@
       - insert:
           - id: code-runtime
             name: '@deepseek-ai/dsh-code-runtime-worker-thread'
+          - id: cordis-host-runner
+            name: '@deepseek-ai/dsh-cordis-host-runner'
           - id: tool-cordis
             name: '@deepseek-ai/dsh-tool-cordis'
           - id: llm-replay

+ 2 - 0
examples/headless-agent/advanced.cordis.yml

@@ -28,5 +28,7 @@
       - insert:
           - id: code-runtime
             name: '@deepseek-ai/dsh-code-runtime-worker-thread'
+          - id: cordis-host-runner
+            name: '@deepseek-ai/dsh-cordis-host-runner'
           - id: tool-cordis
             name: '@deepseek-ai/dsh-tool-cordis'

+ 64 - 26
examples/headless-agent/tests/code-mode.e2e.ts

@@ -23,6 +23,7 @@ import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
 import * as WorkspaceContext from '@deepseek-ai/dsh-agent-instructions'
 import LocalJobRegistry from '@deepseek-ai/dsh-jobs-local'
 import * as ToolTasks from '@deepseek-ai/dsh-tool-jobs'
+import CordisHostRunner from '@deepseek-ai/dsh-cordis-host-runner'
 import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
 
 /**
@@ -85,12 +86,18 @@ let keylessCall = 0
 const testToolSignal = new AbortController().signal
 
 /** Execute one outer Code Mode call through the real registry and worker. */
-function runCode(harness: Context, code: string, signal: AbortSignal = testToolSignal): Promise<ToolExecutionResult> {
+function runCode(
+  harness: Context,
+  code: string,
+  signal: AbortSignal = testToolSignal,
+  agent?: Agent,
+): Promise<ToolExecutionResult> {
   return harness.tools.execute({
     callId: CallId(`keyless-code-${++keylessCall}`),
     name: RUN_CODE_NAME,
     arguments: { code, description: 'Run the e2e program' },
     signal,
+    ...(agent === undefined ? {} : { agent }),
   })
 }
 
@@ -254,46 +261,77 @@ describe('Code Mode typed values: keyless real-worker contracts', () => {
     expect(ctx.jobs.list()).toEqual([])
   }, 15_000)
 
-  it('uses cordis_mount DTO ids directly for running and pending temporary Plugins, then confirms removal', async () => {
+  it('uses versioned Cordis DTO ids directly for running and pending Plugins, then confirms removal', async () => {
     ctx = await typedCodeModeHarness()
+    await ctx.plugin(CordisHostRunner)
     await ctx.plugin(ToolCordis)
+    const agent = {
+      id: SessionId('code-mode-cordis'),
+      session: { append: vi.fn() },
+    } as unknown as Agent
 
     const value = completion(await runCode(ctx, `
-      const active = await tools.cordis_mount({
-        code: "return { name: 'active-code-mode-plugin', apply(ctx) {} }",
+      const activeDefinition = await tools.cordis_define({
+        plugin: { kind: 'new', idPrefix: 'active' },
+        name: 'active-code-mode-plugin',
+        purpose: 'prove an active Host half',
+        code: { host: "return { name: 'active-code-mode-plugin', apply(ctx) {} }" },
       });
-      const pending = await tools.cordis_mount({
-        code: "return { name: 'pending-code-mode-plugin', inject: ['missing-code-mode-service'], apply(ctx) {} }",
+      const active = await tools.cordis_run({
+        pluginId: activeDefinition.pluginId,
+        packageId: activeDefinition.packageId,
+        mode: 'run',
       });
-      const before = await tools.cordis_inspect({ what: 'temporary' });
-      const stopped = await tools.cordis_unmount({ id: active.id });
-      const after = await tools.cordis_inspect({ what: 'temporary' });
-      await tools.cordis_unmount({ id: pending.id });
+      const pendingDefinition = await tools.cordis_define({
+        plugin: { kind: 'new', idPrefix: 'queue' },
+        name: 'pending-code-mode-plugin',
+        purpose: 'prove a Host half waiting for a Service',
+        code: { host: "return { name: 'pending-code-mode-plugin', inject: ['missing-code-mode-service'], apply(ctx) {} }" },
+      });
+      const pending = await tools.cordis_run({
+        pluginId: pendingDefinition.pluginId,
+        packageId: pendingDefinition.packageId,
+        mode: 'run',
+      });
+      const before = await tools.cordis_inspect_self({});
+      const removed = await tools.cordis_undefine({ pluginId: active.pluginId });
+      const after = await tools.cordis_inspect_self({});
+      await tools.cordis_undefine({ pluginId: pending.pluginId });
       return {
-        active,
-        pending,
-        stopped,
-        beforeContainsId: before.includes(active.id),
-        afterContainsId: after.includes(active.id),
+        active: {
+          pluginId: active.pluginId,
+          packageId: active.packageId,
+          pluginRunId: active.pluginRunId,
+          status: active.host.status,
+        },
+        pending: {
+          pluginId: pending.pluginId,
+          packageId: pending.packageId,
+          pluginRunId: pending.pluginRunId,
+          status: pending.host.status,
+          waitingFor: pending.host.waitingFor,
+        },
+        removed,
+        beforeContainsId: before.plugins.some(plugin => plugin.pluginId === active.pluginId),
+        afterContainsId: after.plugins.some(plugin => plugin.pluginId === active.pluginId),
       };
-    `))
+    `, testToolSignal, agent))
 
     expect(value).toEqual({
       active: {
-        id: 'dyn-1',
-        pluginName: 'active-code-mode-plugin',
-        state: 'active',
-        provides: [],
-        waitingFor: [],
+        pluginId: 'active-1',
+        packageId: 'pkg-1',
+        pluginRunId: 'run-1',
+        status: 'running',
       },
       pending: {
-        id: 'dyn-2',
-        pluginName: 'pending-code-mode-plugin',
-        state: 'pending',
-        provides: [],
+        pluginId: 'queue-2',
+        packageId: 'pkg-2',
+        pluginRunId: 'run-2',
+        status: 'waiting',
         waitingFor: ['missing-code-mode-service'],
       },
-      stopped: { id: 'dyn-1', pluginName: 'active-code-mode-plugin' },
+      removed: { pluginId: 'active-1', wasRunning: true },
       beforeContainsId: true,
       afterContainsId: false,
     })

+ 10 - 3
examples/headless-agent/tests/snapshots/advanced-toolchain/input.json

@@ -1,7 +1,14 @@
 {
   "steps": [
-    { "op": "initialize" },
-    { "op": "newSession" },
-    { "op": "prompt", "text": "Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_HEADLESS_OK." }
+    {
+      "op": "initialize"
+    },
+    {
+      "op": "newSession"
+    },
+    {
+      "op": "prompt",
+      "text": "Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_HEADLESS_OK."
+    }
   ]
 }

File diff suppressed because it is too large
+ 3 - 3
examples/headless-agent/tests/snapshots/advanced-toolchain/session.1.jsonl


File diff suppressed because it is too large
+ 3 - 3
examples/headless-agent/tests/snapshots/advanced-toolchain/session.2.jsonl


File diff suppressed because it is too large
+ 2 - 2
examples/headless-agent/tests/snapshots/advanced-toolchain/session.jsonl


+ 60 - 58
examples/headless-agent/tests/snapshots/advanced-toolchain/stream-json.expected.jsonl

@@ -1,73 +1,75 @@
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":0,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_HEADLESS_OK."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":0,"time":0,"data":{"target":"next-turn","start":0,"inserted":[{"content":[{"type":"text","text":"Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_HEADLESS_OK."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"}]}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/start","seq":1,"time":0,"data":{"turn":1}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":2,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":3,"time":0,"data":{"turn":1,"step":1}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":4,"time":0,"data":{"content":[{"type":"text","text":"Run this advanced flow exactly once: try a no-op temporary Cordis Plugin named snapshot-marker; use run_code to inspect the live temporary Plugins through tools.cordis_inspect; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; stop dyn-1; then reply with exactly ADVANCED_HEADLESS_OK."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"user/message","seq":4,"time":0,"data":{"content":[{"type":"text","text":"Run this advanced flow exactly once: define a host-only dynamic Cordis Package named Snapshot Marker; run and inspect snap-1/pkg-1 through run_code; delegate once to a direct spawn child; run one workflow that delegates to another spawn child; remove snap-1; then reply with exactly ADVANCED_HEADLESS_OK."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"session/title","seq":5,"time":0,"data":{"title":"Run this advanced flow exactly","messageSeqs":[4],"source":{"kind":"fallback"}}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/header","seq":6,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"request/context","seq":7,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":9,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-mount","name":"cordis_mount","argumentsDelta":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":10,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":9,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-define","name":"cordis_define","argumentsDelta":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":10,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":11,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":12,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":13,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":14,"time":0,"data":{"turn":1,"step":1,"callId":"advanced-mount","name":"cordis_mount","arguments":"{\"code\":\"return { name: 'snapshot-marker', apply() {} }\"}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":15,"time":0,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-mount"},"content":[{"type":"tool-result","toolCallId":"advanced-mount","content":[{"type":"text","text":"Temporary Plugin dyn-1 is running (plugin \"snapshot-marker\"; available until unmounted or DSH restarts)."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[14],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":13,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":14,"time":0,"data":{"turn":1,"step":1,"callId":"advanced-define","name":"cordis_define","arguments":"{\"plugin\":{\"kind\":\"new\",\"idPrefix\":\"snap\"},\"name\":\"Snapshot Marker\",\"purpose\":\"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\"code\":{\"host\":\"return { apply() {} }\"}}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":15,"time":0,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"advanced-define"},"content":[{"type":"tool-result","toolCallId":"advanced-define","content":[{"type":"text","text":"Defined snap-1/pkg-1 (Snapshot Marker); it is not running yet. Use cordis_run to activate this Package."}],"isError":false}],"role":"user","id":"{{sessionId}}"},"meta":{"pluginId":"snap-1","packageId":"pkg-1"}},"sourceEventSeqs":[14],"surfaceOp":"append"}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":16,"time":0,"data":{"turn":1,"step":1}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":17,"time":0,"data":{"turn":1,"step":2}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":18,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-code","name":"run_code","argumentsDelta":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":20,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-code","name":"run_code","argumentsDelta":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":20,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":21,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
 {"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":22,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":23,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":24,"time":0,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\": \"return await tools.cordis_inspect({ what: 'temporary' })\", \"description\": \"Run the scripted inspection program\"}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch-start","seq":25,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"temporary"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch","seq":26,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_inspect","arguments":{"what":"temporary"},"isError":false,"content":[{"type":"text","text":"## Temporary Plugins\n- Temporary Plugin dyn-1: snapshot-marker [running] — provides: none; waiting for: none; lifetime: until unmounted or DSH restarts"}]}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":27,"time":0,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"## Temporary Plugins\n- Temporary Plugin dyn-1: snapshot-marker [running] — provides: none; waiting for: none; lifetime: until unmounted or DSH restarts"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[24],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":28,"time":0,"data":{"turn":1,"step":2}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":29,"time":0,"data":{"turn":1,"step":3}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":30,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":31,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-direct-child","name":"subagent","argumentsDelta":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":32,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":33,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":34,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":35,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[30,31,32,33,34],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":36,"time":0,"data":{"turn":1,"step":3,"callId":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":37,"time":0,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[36],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":38,"time":0,"data":{"turn":1,"step":3}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":39,"time":0,"data":{"turn":1,"step":4}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":40,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":41,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-workflow","name":"workflow","argumentsDelta":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":42,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":43,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":44,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":45,"time":0,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[40,41,42,43,44],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":46,"time":0,"data":{"turn":1,"step":4,"callId":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/run-start","seq":47,"time":0,"data":{"runId":"{{sessionId}}","name":"advanced-headless-snapshot"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/agent-start","seq":48,"time":0,"data":{"runId":"{{sessionId}}","seq":1,"label":"workflow-child","phase":"Delegate","childId":"{{sessionId}}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/agent-end","seq":49,"time":0,"data":{"runId":"{{sessionId}}","seq":1,"outcome":"completed"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/run-end","seq":50,"time":0,"data":{"runId":"{{sessionId}}","stopReason":"completed"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":51,"time":0,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-headless-snapshot\" completed (1 agent).\nReturn value:\n{\n  \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[46],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":52,"time":0,"data":{"turn":1,"step":4}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":53,"time":0,"data":{"turn":1,"step":5}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":54,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":55,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-unmount","name":"cordis_unmount","argumentsDelta":"{\"id\":\"dyn-1\"}"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":56,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":57,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":58,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":59,"time":0,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[54,55,56,57,58],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":60,"time":0,"data":{"turn":1,"step":5,"callId":"advanced-unmount","name":"cordis_unmount","arguments":"{\"id\":\"dyn-1\"}"}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":61,"time":0,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-unmount"},"content":[{"type":"tool-result","toolCallId":"advanced-unmount","content":[{"type":"text","text":"Temporary Plugin dyn-1 was unmounted and removed."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[60],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":62,"time":0,"data":{"turn":1,"step":5}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":63,"time":0,"data":{"turn":1,"step":6}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":64,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":65,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"text-delta","index":0,"text":"ADVANCED_HEADLESS_OK"}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":66,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"ADVANCED_HEADLESS_OK"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":67,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":68,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":69,"time":0,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_HEADLESS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[64,65,66,67,68],"surfaceOp":"append"}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":70,"time":0,"data":{"turn":1,"step":6}}}
-{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":71,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":23,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":24,"time":0,"data":{"turn":1,"step":2,"callId":"advanced-code","name":"run_code","arguments":"{\"code\":\"const run = await tools.cordis_run({ pluginId: 'snap-1', packageId: 'pkg-1', mode: 'run' });\\nconst inspected = await tools.cordis_inspect_self({ pluginId: 'snap-1' });\\nreturn { run, inspected };\",\"description\":\"Run and inspect the dynamic Cordis Package\"}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch-start","seq":25,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_run","arguments":{"pluginId":"snap-1","packageId":"pkg-1","mode":"run"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch","seq":26,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:1","name":"cordis_run","arguments":{"pluginId":"snap-1","packageId":"pkg-1","mode":"run"},"isError":false,"content":[{"type":"text","text":"snap-1/pkg-1 is running (run-1)."}]}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch-start","seq":27,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:2","name":"cordis_inspect_self","arguments":{"pluginId":"snap-1"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/code-dispatch","seq":28,"time":0,"data":{"rootCallId":"advanced-code","parentCallId":"advanced-code","subCallId":"advanced-code:code:2","name":"cordis_inspect_self","arguments":{"pluginId":"snap-1"},"isError":false,"content":[{"type":"text","text":"{\n  \"mode\": \"plugin\",\n  \"pluginId\": \"snap-1\",\n  \"name\": \"Snapshot Marker\",\n  \"packageCount\": 1,\n  \"state\": \"running\",\n  \"currentPackageId\": \"pkg-1\",\n  \"activeRun\": {\n    \"pluginRunId\": \"run-1\",\n    \"packageId\": \"pkg-1\"\n  },\n  \"packages\": [\n    {\n      \"packageId\": \"pkg-1\",\n      \"name\": \"Snapshot Marker\",\n      \"purpose\": \"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\n      \"hasHostHalf\": true,\n      \"hasClientHalf\": false,\n      \"isCurrent\": true,\n      \"isNext\": false\n    }\n  ]\n}"}]}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":29,"time":0,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"advanced-code"},"content":[{"type":"tool-result","toolCallId":"advanced-code","content":[{"type":"text","text":"{\n  \"run\": {\n    \"status\": \"running\",\n    \"pluginId\": \"snap-1\",\n    \"packageId\": \"pkg-1\",\n    \"pluginRunId\": \"run-1\",\n    \"currentPackageId\": \"pkg-1\",\n    \"host\": {\n      \"status\": \"running\",\n      \"provides\": [],\n      \"waitingFor\": []\n    },\n    \"client\": {\n      \"status\": \"absent\",\n      \"waitingFor\": []\n    }\n  },\n  \"inspected\": {\n    \"mode\": \"plugin\",\n    \"pluginId\": \"snap-1\",\n    \"name\": \"Snapshot Marker\",\n    \"packageCount\": 1,\n    \"state\": \"running\",\n    \"currentPackageId\": \"pkg-1\",\n    \"activeRun\": {\n      \"pluginRunId\": \"run-1\",\n      \"packageId\": \"pkg-1\"\n    },\n    \"packages\": [\n      {\n        \"packageId\": \"pkg-1\",\n        \"name\": \"Snapshot Marker\",\n        \"purpose\": \"Exercise the dynamic Cordis Package lifecycle in the snapshot.\",\n        \"hasHostHalf\": true,\n        \"hasClientHalf\": false,\n        \"isCurrent\": true,\n        \"isNext\": false\n      }\n    ]\n  }\n}"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[24],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":30,"time":0,"data":{"turn":1,"step":2}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":31,"time":0,"data":{"turn":1,"step":3}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":32,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":33,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-direct-child","name":"subagent","argumentsDelta":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":34,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":35,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":36,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":37,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[32,33,34,35,36],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":38,"time":0,"data":{"turn":1,"step":3,"callId":"advanced-direct-child","name":"subagent","arguments":"{\"description\":\"Check direct child\",\"prompt\":\"Reply with exactly DIRECT_CHILD_OK and nothing else.\",\"run_in_background\":false}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":39,"time":0,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"advanced-direct-child"},"content":[{"type":"tool-result","toolCallId":"advanced-direct-child","content":[{"type":"text","text":"DIRECT_CHILD_OK"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[38],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":40,"time":0,"data":{"turn":1,"step":3}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":41,"time":0,"data":{"turn":1,"step":4}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":42,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":43,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-workflow","name":"workflow","argumentsDelta":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":44,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":45,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":46,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":47,"time":0,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[42,43,44,45,46],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":48,"time":0,"data":{"turn":1,"step":4,"callId":"advanced-workflow","name":"workflow","arguments":"{\"script\":\"phase('Delegate')\\nconst reply = await agent('Reply with exactly WORKFLOW_CHILD_OK and nothing else.', { label: 'workflow-child' })\\nreturn { reply }\",\"meta\":{\"name\":\"advanced-headless-snapshot\",\"description\":\"exercise one workflow child through the headless agent\"}}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/run-start","seq":49,"time":0,"data":{"runId":"{{sessionId}}","name":"advanced-headless-snapshot"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/agent-start","seq":50,"time":0,"data":{"runId":"{{sessionId}}","seq":1,"label":"workflow-child","phase":"Delegate","childId":"{{sessionId}}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/agent-end","seq":51,"time":0,"data":{"runId":"{{sessionId}}","seq":1,"outcome":"completed"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool-workflow/run-end","seq":52,"time":0,"data":{"runId":"{{sessionId}}","stopReason":"completed"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":53,"time":0,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"advanced-workflow"},"content":[{"type":"tool-result","toolCallId":"advanced-workflow","content":[{"type":"text","text":"workflow \"advanced-headless-snapshot\" completed (1 agent).\nReturn value:\n{\n  \"reply\": \"WORKFLOW_CHILD_OK\"\n}"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[48],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":54,"time":0,"data":{"turn":1,"step":4}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":55,"time":0,"data":{"turn":1,"step":5}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":56,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":57,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"advanced-undefine","name":"cordis_undefine","argumentsDelta":"{\"pluginId\":\"snap-1\"}"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":58,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":59,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":60,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":61,"time":0,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[56,57,58,59,60],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":62,"time":0,"data":{"turn":1,"step":5,"callId":"advanced-undefine","name":"cordis_undefine","arguments":"{\"pluginId\":\"snap-1\"}"}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":63,"time":0,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"advanced-undefine"},"content":[{"type":"tool-result","toolCallId":"advanced-undefine","content":[{"type":"text","text":"Removed dynamic Plugin snap-1 and all of its Packages."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[62],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":64,"time":0,"data":{"turn":1,"step":5}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/start","seq":65,"time":0,"data":{"turn":1,"step":6}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":66,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":67,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"text-delta","index":0,"text":"ADVANCED_HEADLESS_OK"}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":68,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"ADVANCED_HEADLESS_OK"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":69,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":70,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":71,"time":0,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"text","text":"ADVANCED_HEADLESS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[66,67,68,69,70],"surfaceOp":"append"}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"step/end","seq":72,"time":0,"data":{"turn":1,"step":6}}}
+{"type":"session_event","sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":73,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}
 {"type":"result","sessionId":"{{sessionId}}","output":"ADVANCED_HEADLESS_OK","usage":{"inputTokens":18,"outputTokens":18}}

+ 2 - 2
examples/jsonrpc-agent/README.i18n.yaml

@@ -2,5 +2,5 @@
 # side as of the last confirmed-consistent state. Both languages carry equal authority;
 # after editing either side, bring the other along and re-record with:
 #   pnpm run verify-translation-pairing --write examples/jsonrpc-agent/README.md
-README.md: 5166d94e92e2e4bcdda5026fa65ba6b77b87fe40
-README.zh.md: f84ab95132e820cf0fcf45bff4ae30d9bccb55c1
+README.md: ec94fa7ceec5a51585241851eaee2cfcf938738f
+README.zh.md: 64a5e607bd37e97b60cb0a4f6ee89a7c766d7464

+ 1 - 1
examples/jsonrpc-agent/README.md

@@ -30,7 +30,7 @@ Pass the config path through the Python SDK's `cordis` option or `DSH_CORDIS_CON
 
 ## Minimal variant
 
-[`minimal.cordis.yml`](minimal.cordis.yml) is the complete standalone counterpart of the Web `minimal` preset. `DSH_SYSTEM_PROMPT` selects its system prompt, with `You are a helpful software engineer assistant.` as the fallback, and no context-compaction plugin is mounted. Its model-facing tools are exactly:
+[`minimal.cordis.yml`](minimal.cordis.yml) is the complete standalone counterpart of the Web `minimal` preset. `DSH_SYSTEM_PROMPT` selects its system prompt, with `You are a helpful software engineer assistant.` as the fallback. It suppresses every system-prompt runtime-context contribution for fresh sessions and mounts no context-compaction plugin. Its model-facing tools are exactly:
 
 - owner-scoped persistent `bash`
 - `str_replace_editor` with `view`, `create`, `str_replace`, and `insert`

+ 1 - 1
examples/jsonrpc-agent/README.zh.md

@@ -30,7 +30,7 @@
 
 ## 极简变体
 
-[`minimal.cordis.yml`](minimal.cordis.yml) 是 Web `minimal` preset 的完整独立版本。`DSH_SYSTEM_PROMPT` 选择它的系统提示词,未设置时使用 `You are a helpful software engineer assistant.`,且不挂载上下文压缩插件。面向模型的工具严格只有:
+[`minimal.cordis.yml`](minimal.cordis.yml) 是 Web `minimal` preset 的完整独立版本。`DSH_SYSTEM_PROMPT` 选择它的系统提示词,未设置时使用 `You are a helpful software engineer assistant.`。它为新建会话抑制每个 system-prompt runtime-context 贡献,且不挂载上下文压缩插件。面向模型的工具严格只有:
 
 - 所有者作用域内持久化的 `bash`
 - 提供 `view`、`create`、`str_replace` 与 `insert` 的 `str_replace_editor`

+ 3 - 1
examples/jsonrpc-agent/minimal.cordis.yml

@@ -1,6 +1,7 @@
 # Complete unattended minimal-agent composition for the Python SDK. The model
 # sees one deployment-selected system prompt and only the owner-scoped
-# persistent Bash and string-replace editor tools. Context compaction is absent.
+# persistent Bash and string-replace editor tools. Runtime-context injection and
+# context compaction are absent.
 
 - id: sdk-jsonrpc-server
   name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
@@ -47,6 +48,7 @@
   name: '@deepseek-ai/dsh-agent-spine-demo'
   config:
     includeHarnessIdentity: false
+    includeRuntimeContext: false
     persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'
     workspaceContext: false
     skills:

+ 17 - 16
examples/jsonrpc-agent/tests/sdk.snapshot.ts

@@ -77,8 +77,8 @@ interface SdkScenario {
   expectedSystem?: string
   /** Exact model-facing descriptions for selected tools. */
   expectedToolDescriptions?: Readonly<Record<string, string>>
-  /** Stable policy-context clauses the real assembled request must include or omit. */
-  policyContext?: { includes: readonly string[]; excludes: readonly string[] }
+  /** Expected runtime-context state in the real assembled request. */
+  runtimeContext?: false | { includes: readonly string[]; excludes: readonly string[] }
 }
 
 const SCENARIOS: SdkScenario[] = [
@@ -111,10 +111,7 @@ const SCENARIOS: SdkScenario[] = [
     expectedTools: { bash: ['command'], str_replace_editor: ['command', 'path'] },
     expectedSystem: MINIMAL_SYSTEM_PROMPT,
     expectedToolDescriptions: { bash: MINIMAL_BASH_DESCRIPTION },
-    policyContext: {
-      includes: ['Current DSH file policy: danger-full-access.', 'file modifications by available operations'],
-      excludes: ['write and edit tools', 'terminal sessions', 'one-shot bash commands'],
-    },
+    runtimeContext: false,
   },
 ]
 
@@ -182,8 +179,8 @@ function assembledSystem(log: PersistedLog): string {
   return system
 }
 
-function assembledPolicyContext(log: PersistedLog): string {
-  const contexts = log.content.trimEnd().split('\n').flatMap((line) => {
+function assembledRuntimeContexts(log: PersistedLog): string[] {
+  return log.content.trimEnd().split('\n').flatMap((line) => {
     const event = JSON.parse(line) as {
       type?: string
       data?: { source?: { kind?: string; plugin?: string }; content?: Array<{ type?: string; text?: unknown }> }
@@ -193,8 +190,6 @@ function assembledPolicyContext(log: PersistedLog): string {
       || event.data.source.plugin !== '@deepseek-ai/dsh-system-prompt') return []
     return event.data.content?.flatMap(block => block.type === 'text' && typeof block.text === 'string' ? [block.text] : []) ?? []
   })
-  if (contexts.length !== 1) throw new Error(`session log has ${String(contexts.length)} runtime-context snapshots; expected one`)
-  return contexts[0] as string
 }
 
 function contextOf(logs: readonly { content: string; header: Record<string, unknown> }[], cwd: string): NormalizeContext {
@@ -447,14 +442,20 @@ describe('TypeScript SDK snapshots over the jsonrpc runtime', () => {
         if (parent === undefined) throw new Error(`${scenario.name} has no parent session log`)
         expect(assembledToolDescriptions(parent)).toMatchObject(scenario.expectedToolDescriptions)
       }
-      if (scenario.policyContext !== undefined) {
+      if (scenario.runtimeContext !== undefined) {
         const parent = ordered[0]
         if (parent === undefined) throw new Error(`${scenario.name} has no parent session log`)
-        const context = assembledPolicyContext(parent)
-        for (const clause of scenario.policyContext.includes) expect(context).toContain(clause)
-        for (const clause of scenario.policyContext.excludes) expect(context).not.toContain(clause)
-        const system = assembledSystem(parent)
-        for (const clause of scenario.policyContext.includes) expect(system).not.toContain(clause)
+        const contexts = assembledRuntimeContexts(parent)
+        if (scenario.runtimeContext === false) {
+          expect(contexts).toEqual([])
+        } else {
+          expect(contexts).toHaveLength(1)
+          const context = contexts[0] as string
+          for (const clause of scenario.runtimeContext.includes) expect(context).toContain(clause)
+          for (const clause of scenario.runtimeContext.excludes) expect(context).not.toContain(clause)
+          const system = assembledSystem(parent)
+          for (const clause of scenario.runtimeContext.includes) expect(system).not.toContain(clause)
+        }
       }
       if (scenario.children > 0) {
         expect(notifications.some(n => n.method === 'subagent.started')).toBe(true)

+ 71 - 72
examples/jsonrpc-agent/tests/snapshots/persistent-tools/notifications.expected.jsonl

@@ -4,76 +4,75 @@
 {"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"agent/inbox/spliced","seq":2,"time":0,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}}}
 {"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":3,"time":0,"data":{"turn":1,"step":1}}}}
 {"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":4,"time":0,"data":{"content":[{"type":"text","text":"Prove that bash state persists. Then create {{cwd}}/note.txt with a tab-indented line, view it, replace that literal tab-indented line, and make the persistent shell exit with code 9."}],"source":{"kind":"user"},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"user/message","seq":5,"time":0,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."}]},"role":"user","id":"{{sessionId}}"},"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"session/title","seq":6,"time":0,"data":{"title":"Prove that bash state persists.","messageSeqs":[4],"source":{"kind":"fallback"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/header","seq":7,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/context","seq":8,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":9,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":10,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-1","name":"bash","argumentsDelta":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":11,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":12,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":13,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":14,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":15,"time":0,"data":{"turn":1,"step":1,"callId":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":16,"time":0,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"bash-1"},"content":[{"type":"tool-result","toolCallId":"bash-1","content":[{"type":"text","text":"COUNT=1 CWD=/tmp"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[15],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":17,"time":0,"data":{"turn":1,"step":1}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":18,"time":0,"data":{"turn":1,"step":2}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":20,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-2","name":"bash","argumentsDelta":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":21,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":22,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":23,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":24,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[19,20,21,22,23],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":25,"time":0,"data":{"turn":1,"step":2,"callId":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":26,"time":0,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"bash-2"},"content":[{"type":"tool-result","toolCallId":"bash-2","content":[{"type":"text","text":"COUNT=2 CWD=/tmp"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[25],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":27,"time":0,"data":{"turn":1,"step":2}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":28,"time":0,"data":{"turn":1,"step":3}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":29,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":30,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-create","name":"str_replace_editor","argumentsDelta":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":31,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":32,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":33,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":34,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[29,30,31,32,33],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":35,"time":0,"data":{"turn":1,"step":3,"callId":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":36,"time":0,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"editor-create"},"content":[{"type":"tool-result","toolCallId":"editor-create","content":[{"type":"text","text":"New file created successfully at: {{cwd}}/note.txt"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[35],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":37,"time":0,"data":{"turn":1,"step":3}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":38,"time":0,"data":{"turn":1,"step":4}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":39,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":40,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-view","name":"str_replace_editor","argumentsDelta":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":41,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":42,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":43,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":44,"time":0,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[39,40,41,42,43],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":45,"time":0,"data":{"turn":1,"step":4,"callId":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":46,"time":0,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"editor-view"},"content":[{"type":"tool-result","toolCallId":"editor-view","content":[{"type":"text","text":"Here's the content of {{cwd}}/note.txt with line numbers (which has a total of 3 lines):\n     1  target:\n     2  \told\n     3  \n"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[45],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":47,"time":0,"data":{"turn":1,"step":4}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":48,"time":0,"data":{"turn":1,"step":5}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":49,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":50,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-replace","name":"str_replace_editor","argumentsDelta":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":51,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":52,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":53,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":54,"time":0,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[49,50,51,52,53],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":55,"time":0,"data":{"turn":1,"step":5,"callId":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":56,"time":0,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"editor-replace"},"content":[{"type":"tool-result","toolCallId":"editor-replace","content":[{"type":"text","text":"The file {{cwd}}/note.txt has been edited successfully."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[55],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":57,"time":0,"data":{"turn":1,"step":5}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":58,"time":0,"data":{"turn":1,"step":6}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":59,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":60,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-exit","name":"bash","argumentsDelta":"{\"command\":\"exit 9\"}"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":61,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":62,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":63,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":64,"time":0,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[59,60,61,62,63],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":65,"time":0,"data":{"turn":1,"step":6,"callId":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":66,"time":0,"data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"bash-exit"},"content":[{"type":"tool-result","toolCallId":"bash-exit","content":[{"type":"text","text":"exit\n[shell exited: code 9]\nThe persistent bash shell was reset; the next bash call starts from the workspace with a fresh current directory and environment."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[65],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":67,"time":0,"data":{"turn":1,"step":6}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":68,"time":0,"data":{"turn":1,"step":7}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":69,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":70,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"text-delta","index":0,"text":"PERSISTENT_TOOLS_OK"}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":71,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PERSISTENT_TOOLS_OK"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":72,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":73,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":74,"time":0,"data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"PERSISTENT_TOOLS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[69,70,71,72,73],"surfaceOp":"append"}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":75,"time":0,"data":{"turn":1,"step":7}}}}
-{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":76,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"session/title","seq":5,"time":0,"data":{"title":"Prove that bash state persists.","messageSeqs":[4],"source":{"kind":"fallback"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/header","seq":6,"time":0,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"request/context","seq":7,"time":0,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":8,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":9,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-1","name":"bash","argumentsDelta":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":10,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":11,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":12,"time":0,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":13,"time":0,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":14,"time":0,"data":{"turn":1,"step":1,"callId":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":15,"time":0,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"bash-1"},"content":[{"type":"tool-result","toolCallId":"bash-1","content":[{"type":"text","text":"COUNT=1 CWD=/tmp"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[14],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":16,"time":0,"data":{"turn":1,"step":1}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":17,"time":0,"data":{"turn":1,"step":2}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":18,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":19,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-2","name":"bash","argumentsDelta":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":20,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":21,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":22,"time":0,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":23,"time":0,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":24,"time":0,"data":{"turn":1,"step":2,"callId":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":25,"time":0,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"bash-2"},"content":[{"type":"tool-result","toolCallId":"bash-2","content":[{"type":"text","text":"COUNT=2 CWD=/tmp"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[24],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":26,"time":0,"data":{"turn":1,"step":2}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":27,"time":0,"data":{"turn":1,"step":3}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":28,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":29,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-create","name":"str_replace_editor","argumentsDelta":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":30,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":31,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":32,"time":0,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":33,"time":0,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[28,29,30,31,32],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":34,"time":0,"data":{"turn":1,"step":3,"callId":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":35,"time":0,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"editor-create"},"content":[{"type":"tool-result","toolCallId":"editor-create","content":[{"type":"text","text":"New file created successfully at: {{cwd}}/note.txt"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[34],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":36,"time":0,"data":{"turn":1,"step":3}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":37,"time":0,"data":{"turn":1,"step":4}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":38,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":39,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-view","name":"str_replace_editor","argumentsDelta":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":40,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":41,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":42,"time":0,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":43,"time":0,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[38,39,40,41,42],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":44,"time":0,"data":{"turn":1,"step":4,"callId":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":45,"time":0,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"editor-view"},"content":[{"type":"tool-result","toolCallId":"editor-view","content":[{"type":"text","text":"Here's the content of {{cwd}}/note.txt with line numbers (which has a total of 3 lines):\n     1  target:\n     2  \told\n     3  \n"}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[44],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":46,"time":0,"data":{"turn":1,"step":4}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":47,"time":0,"data":{"turn":1,"step":5}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":48,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":49,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-replace","name":"str_replace_editor","argumentsDelta":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":50,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":51,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":52,"time":0,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":53,"time":0,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[48,49,50,51,52],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":54,"time":0,"data":{"turn":1,"step":5,"callId":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":55,"time":0,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"editor-replace"},"content":[{"type":"tool-result","toolCallId":"editor-replace","content":[{"type":"text","text":"The file {{cwd}}/note.txt has been edited successfully."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[54],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":56,"time":0,"data":{"turn":1,"step":5}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":57,"time":0,"data":{"turn":1,"step":6}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":58,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":59,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-exit","name":"bash","argumentsDelta":"{\"command\":\"exit 9\"}"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":60,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":61,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":62,"time":0,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":63,"time":0,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[58,59,60,61,62],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/call","seq":64,"time":0,"data":{"turn":1,"step":6,"callId":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"tool/result","seq":65,"time":0,"data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"bash-exit"},"content":[{"type":"tool-result","toolCallId":"bash-exit","content":[{"type":"text","text":"exit\n[shell exited: code 9]\nThe persistent bash shell was reset; the next bash call starts from the workspace with a fresh current directory and environment."}],"isError":false}],"role":"user","id":"{{sessionId}}"}},"sourceEventSeqs":[64],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":66,"time":0,"data":{"turn":1,"step":6}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/start","seq":67,"time":0,"data":{"turn":1,"step":7}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":68,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":69,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"text-delta","index":0,"text":"PERSISTENT_TOOLS_OK"}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":70,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PERSISTENT_TOOLS_OK"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":71,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/chunk","seq":72,"time":0,"data":{"turn":1,"step":7,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"assistant/message","seq":73,"time":0,"data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"PERSISTENT_TOOLS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"{{sessionId}}"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[68,69,70,71,72],"surfaceOp":"append"}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"step/end","seq":74,"time":0,"data":{"turn":1,"step":7}}}}
+{"method":"session.event","params":{"sessionId":"{{sessionId}}","event":{"type":"turn/end","seq":75,"time":0,"data":{"turn":1,"reason":{"kind":"completed"}}}}}
 {"method":"session.status","params":{"sessionId":"{{sessionId}}","status":"idle"}}

+ 71 - 72
examples/jsonrpc-agent/tests/snapshots/persistent-tools/session.jsonl

@@ -4,75 +4,74 @@
 {"type":"agent/inbox/spliced","seq":2,"time":1785821461907,"data":{"target":"next-turn","start":0,"removedCount":1,"inserted":[]}}
 {"type":"step/start","seq":3,"time":1785331618312,"data":{"turn":1,"step":1}}
 {"type":"user/message","seq":4,"time":1785498592368,"data":{"content":[{"type":"text","text":"Prove that bash state persists. Then create {{cwd}}/note.txt with a tab-indented line, view it, replace that literal tab-indented line, and make the persistent shell exit with code 9."}],"source":{"kind":"user"},"role":"user","id":"9a08e199-69d7-4b85-bfa4-27b41a92672a"},"surfaceOp":"append"}
-{"type":"user/message","seq":5,"time":1785730508088,"data":{"content":[{"type":"text","text":"Current runtime context. This snapshot supersedes earlier runtime-context snapshots.\n\nCurrent DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."}],"source":{"kind":"plugin","plugin":"@deepseek-ai/dsh-system-prompt","form":"snapshot","sections":[{"name":"sandbox:policy","text":"Current DSH file policy: danger-full-access. The DSH file sandbox does not restrict file modifications by available operations."}]},"role":"user","id":"bb38bdc2-276e-46ec-87a1-089732acbc8d"},"surfaceOp":"append"}
-{"type":"session/title","seq":6,"time":1785730508088,"data":{"title":"Prove that bash state persists.","messageSeqs":[4],"source":{"kind":"fallback"}}}
-{"type":"request/header","seq":7,"time":1785498592370,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
-{"type":"request/context","seq":8,"time":1785730508089,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
-{"type":"assistant/chunk","seq":9,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":10,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-1","name":"bash","argumentsDelta":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}
-{"type":"assistant/chunk","seq":11,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
-{"type":"assistant/chunk","seq":12,"time":1785498592372,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":13,"time":1785730508090,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":14,"time":1785730508090,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0d064526-8eff-482d-8525-ac478e1d1791"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[9,10,11,12,13],"surfaceOp":"append"}
-{"type":"tool/call","seq":15,"time":1785730508090,"data":{"turn":1,"step":1,"callId":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}
-{"type":"tool/result","seq":16,"time":1785730508425,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"bash-1"},"content":[{"type":"tool-result","toolCallId":"bash-1","content":[{"type":"text","text":"COUNT=1 CWD=/tmp"}],"isError":false}],"role":"user","id":"2c01f81a-01ea-47e2-bf92-f7825b7cc69f"}},"sourceEventSeqs":[15],"surfaceOp":"append"}
-{"type":"step/end","seq":17,"time":1785730508425,"data":{"turn":1,"step":1}}
-{"type":"step/start","seq":18,"time":1785730508425,"data":{"turn":1,"step":2}}
-{"type":"assistant/chunk","seq":19,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":20,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-2","name":"bash","argumentsDelta":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}
-{"type":"assistant/chunk","seq":21,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
-{"type":"assistant/chunk","seq":22,"time":1785498592702,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":23,"time":1785730508426,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":24,"time":1785730508426,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ba4078ce-0e18-419a-b720-339918aecf26"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[19,20,21,22,23],"surfaceOp":"append"}
-{"type":"tool/call","seq":25,"time":1785730508426,"data":{"turn":1,"step":2,"callId":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}
-{"type":"tool/result","seq":26,"time":1785730508537,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"bash-2"},"content":[{"type":"tool-result","toolCallId":"bash-2","content":[{"type":"text","text":"COUNT=2 CWD=/tmp"}],"isError":false}],"role":"user","id":"6e3ad5e1-1149-44d5-bd20-d9cc0139c747"}},"sourceEventSeqs":[25],"surfaceOp":"append"}
-{"type":"step/end","seq":27,"time":1785730508537,"data":{"turn":1,"step":2}}
-{"type":"step/start","seq":28,"time":1785730508537,"data":{"turn":1,"step":3}}
-{"type":"assistant/chunk","seq":29,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":30,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-create","name":"str_replace_editor","argumentsDelta":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}
-{"type":"assistant/chunk","seq":31,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}
-{"type":"assistant/chunk","seq":32,"time":1785498592812,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":33,"time":1785730508538,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":34,"time":1785730508538,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"e5769b2d-ea91-42fe-a78f-2f7f408f545e"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[29,30,31,32,33],"surfaceOp":"append"}
-{"type":"tool/call","seq":35,"time":1785730508538,"data":{"turn":1,"step":3,"callId":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}
-{"type":"tool/result","seq":36,"time":1785730508551,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"editor-create"},"content":[{"type":"tool-result","toolCallId":"editor-create","content":[{"type":"text","text":"New file created successfully at: {{cwd}}/note.txt"}],"isError":false}],"role":"user","id":"af41060c-7007-4ada-89d6-8b15a0e8be7c"}},"sourceEventSeqs":[35],"surfaceOp":"append"}
-{"type":"step/end","seq":37,"time":1785730508551,"data":{"turn":1,"step":3}}
-{"type":"step/start","seq":38,"time":1785730508552,"data":{"turn":1,"step":4}}
-{"type":"assistant/chunk","seq":39,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":40,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-view","name":"str_replace_editor","argumentsDelta":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}
-{"type":"assistant/chunk","seq":41,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}
-{"type":"assistant/chunk","seq":42,"time":1785498592825,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":43,"time":1785730508552,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":44,"time":1785730508552,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0e9afabb-10a6-444c-ae22-fcdbb5e14695"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[39,40,41,42,43],"surfaceOp":"append"}
-{"type":"tool/call","seq":45,"time":1785730508553,"data":{"turn":1,"step":4,"callId":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}
-{"type":"tool/result","seq":46,"time":1785730508554,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"editor-view"},"content":[{"type":"tool-result","toolCallId":"editor-view","content":[{"type":"text","text":"Here's the content of {{cwd}}/note.txt with line numbers (which has a total of 3 lines):\n     1  target:\n     2  \told\n     3  \n"}],"isError":false}],"role":"user","id":"a4472b37-6311-4880-bce2-cc369f9bc34b"}},"sourceEventSeqs":[45],"surfaceOp":"append"}
-{"type":"step/end","seq":47,"time":1785730508554,"data":{"turn":1,"step":4}}
-{"type":"step/start","seq":48,"time":1785730508554,"data":{"turn":1,"step":5}}
-{"type":"assistant/chunk","seq":49,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":50,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-replace","name":"str_replace_editor","argumentsDelta":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}
-{"type":"assistant/chunk","seq":51,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}
-{"type":"assistant/chunk","seq":52,"time":1785498592826,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":53,"time":1785730508555,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":54,"time":1785730508555,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ba189070-d46e-461e-969b-9bca032bb154"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[49,50,51,52,53],"surfaceOp":"append"}
-{"type":"tool/call","seq":55,"time":1785730508555,"data":{"turn":1,"step":5,"callId":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}
-{"type":"tool/result","seq":56,"time":1785730508564,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"editor-replace"},"content":[{"type":"tool-result","toolCallId":"editor-replace","content":[{"type":"text","text":"The file {{cwd}}/note.txt has been edited successfully."}],"isError":false}],"role":"user","id":"17331db9-174b-4699-9c9e-3140921956c4"}},"sourceEventSeqs":[55],"surfaceOp":"append"}
-{"type":"step/end","seq":57,"time":1785730508564,"data":{"turn":1,"step":5}}
-{"type":"step/start","seq":58,"time":1785730508565,"data":{"turn":1,"step":6}}
-{"type":"assistant/chunk","seq":59,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
-{"type":"assistant/chunk","seq":60,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-exit","name":"bash","argumentsDelta":"{\"command\":\"exit 9\"}"}}}
-{"type":"assistant/chunk","seq":61,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}
-{"type":"assistant/chunk","seq":62,"time":1785498592838,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":63,"time":1785730508565,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
-{"type":"assistant/message","seq":64,"time":1785730508565,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"7fa07d0f-e70a-460d-b685-bf8a63b6a8a0"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[59,60,61,62,63],"surfaceOp":"append"}
-{"type":"tool/call","seq":65,"time":1785730508565,"data":{"turn":1,"step":6,"callId":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}
-{"type":"tool/result","seq":66,"time":1785730508641,"data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"bash-exit"},"content":[{"type":"tool-result","toolCallId":"bash-exit","content":[{"type":"text","text":"exit\n[shell exited: code 9]\nThe persistent bash shell was reset; the next bash call starts from the workspace with a fresh current directory and environment."}],"isError":false}],"role":"user","id":"ccb91a28-4034-49bf-967d-450f68f7f9b8"}},"sourceEventSeqs":[65],"surfaceOp":"append"}
-{"type":"step/end","seq":67,"time":1785730508641,"data":{"turn":1,"step":6}}
-{"type":"step/start","seq":68,"time":1785730508642,"data":{"turn":1,"step":7}}
-{"type":"assistant/chunk","seq":69,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
-{"type":"assistant/chunk","seq":70,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"text-delta","index":0,"text":"PERSISTENT_TOOLS_OK"}}}
-{"type":"assistant/chunk","seq":71,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PERSISTENT_TOOLS_OK"}}}}
-{"type":"assistant/chunk","seq":72,"time":1785498592934,"data":{"turn":1,"step":7,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
-{"type":"assistant/chunk","seq":73,"time":1785730508642,"data":{"turn":1,"step":7,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
-{"type":"assistant/message","seq":74,"time":1785730508642,"data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"PERSISTENT_TOOLS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"43efc58a-46a1-4813-995f-1dc489438942"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[69,70,71,72,73],"surfaceOp":"append"}
-{"type":"step/end","seq":75,"time":1785730508642,"data":{"turn":1,"step":7}}
-{"type":"turn/end","seq":76,"time":1785730508642,"data":{"turn":1,"reason":{"kind":"completed"}}}
+{"type":"session/title","seq":5,"time":1785498592368,"data":{"title":"Prove that bash state persists.","messageSeqs":[4],"source":{"kind":"fallback"}}}
+{"type":"request/header","seq":6,"time":1786547087174,"data":{"header":{"config":{"provider":"deepseek-official","model":"deepseek-v4-flash"},"system":"{{system}}","tools":"{{tools}}"},"reason":"initial"}}
+{"type":"request/context","seq":7,"time":1786547087175,"data":{"provider":"deepseek-official","model":"deepseek-v4-flash"}}
+{"type":"assistant/chunk","seq":8,"time":1786547087175,"data":{"turn":1,"step":1,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":9,"time":1786547087175,"data":{"turn":1,"step":1,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-1","name":"bash","argumentsDelta":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}
+{"type":"assistant/chunk","seq":10,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
+{"type":"assistant/chunk","seq":11,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":12,"time":1785331618326,"data":{"turn":1,"step":1,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":13,"time":1786547087175,"data":{"turn":1,"step":1,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0d064526-8eff-482d-8525-ac478e1d1791"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[8,9,10,11,12],"surfaceOp":"append"}
+{"type":"tool/call","seq":14,"time":1786547087176,"data":{"turn":1,"step":1,"callId":"bash-1","name":"bash","arguments":"{\"command\":\"cd /tmp && export DSH_EXAMPLE_COUNT=1 && printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}
+{"type":"tool/result","seq":15,"time":1786547094340,"data":{"turn":1,"step":1,"message":{"source":{"kind":"tool","callId":"bash-1"},"content":[{"type":"tool-result","toolCallId":"bash-1","content":[{"type":"text","text":"COUNT=1 CWD=/tmp"}],"isError":false}],"role":"user","id":"2c01f81a-01ea-47e2-bf92-f7825b7cc69f"}},"sourceEventSeqs":[14],"surfaceOp":"append"}
+{"type":"step/end","seq":16,"time":1786547094340,"data":{"turn":1,"step":1}}
+{"type":"step/start","seq":17,"time":1786547094341,"data":{"turn":1,"step":2}}
+{"type":"assistant/chunk","seq":18,"time":1786547094341,"data":{"turn":1,"step":2,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":19,"time":1786547094341,"data":{"turn":1,"step":2,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-2","name":"bash","argumentsDelta":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}
+{"type":"assistant/chunk","seq":20,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}}}
+{"type":"assistant/chunk","seq":21,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":22,"time":1785331618652,"data":{"turn":1,"step":2,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":23,"time":1786547094341,"data":{"turn":1,"step":2,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ba4078ce-0e18-419a-b720-339918aecf26"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[18,19,20,21,22],"surfaceOp":"append"}
+{"type":"tool/call","seq":24,"time":1786547094341,"data":{"turn":1,"step":2,"callId":"bash-2","name":"bash","arguments":"{\"command\":\"DSH_EXAMPLE_COUNT=$((DSH_EXAMPLE_COUNT + 1)); printf \\\"COUNT=%s CWD=%s\\\\n\\\" \\\"$DSH_EXAMPLE_COUNT\\\" \\\"$PWD\\\"\"}"}}
+{"type":"tool/result","seq":25,"time":1786547097878,"data":{"turn":1,"step":2,"message":{"source":{"kind":"tool","callId":"bash-2"},"content":[{"type":"tool-result","toolCallId":"bash-2","content":[{"type":"text","text":"COUNT=2 CWD=/tmp"}],"isError":false}],"role":"user","id":"6e3ad5e1-1149-44d5-bd20-d9cc0139c747"}},"sourceEventSeqs":[24],"surfaceOp":"append"}
+{"type":"step/end","seq":26,"time":1786547097878,"data":{"turn":1,"step":2}}
+{"type":"step/start","seq":27,"time":1786547097878,"data":{"turn":1,"step":3}}
+{"type":"assistant/chunk","seq":28,"time":1786547097878,"data":{"turn":1,"step":3,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":29,"time":1786547097878,"data":{"turn":1,"step":3,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-create","name":"str_replace_editor","argumentsDelta":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}
+{"type":"assistant/chunk","seq":30,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}}}
+{"type":"assistant/chunk","seq":31,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":32,"time":1785331618762,"data":{"turn":1,"step":3,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":33,"time":1786547097878,"data":{"turn":1,"step":3,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"e5769b2d-ea91-42fe-a78f-2f7f408f545e"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[28,29,30,31,32],"surfaceOp":"append"}
+{"type":"tool/call","seq":34,"time":1786547097879,"data":{"turn":1,"step":3,"callId":"editor-create","name":"str_replace_editor","arguments":"{\"command\":\"create\",\"path\":\"{{cwd}}/note.txt\",\"file_text\":\"target:\\n\\told\\n\"}"}}
+{"type":"tool/result","seq":35,"time":1786547097885,"data":{"turn":1,"step":3,"message":{"source":{"kind":"tool","callId":"editor-create"},"content":[{"type":"tool-result","toolCallId":"editor-create","content":[{"type":"text","text":"New file created successfully at: {{cwd}}/note.txt"}],"isError":false}],"role":"user","id":"af41060c-7007-4ada-89d6-8b15a0e8be7c"}},"sourceEventSeqs":[34],"surfaceOp":"append"}
+{"type":"step/end","seq":36,"time":1786547097885,"data":{"turn":1,"step":3}}
+{"type":"step/start","seq":37,"time":1786547097885,"data":{"turn":1,"step":4}}
+{"type":"assistant/chunk","seq":38,"time":1786547097886,"data":{"turn":1,"step":4,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":39,"time":1786547097886,"data":{"turn":1,"step":4,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-view","name":"str_replace_editor","argumentsDelta":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}
+{"type":"assistant/chunk","seq":40,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}}}
+{"type":"assistant/chunk","seq":41,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":42,"time":1785331618784,"data":{"turn":1,"step":4,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":43,"time":1786547097886,"data":{"turn":1,"step":4,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"0e9afabb-10a6-444c-ae22-fcdbb5e14695"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[38,39,40,41,42],"surfaceOp":"append"}
+{"type":"tool/call","seq":44,"time":1786547097886,"data":{"turn":1,"step":4,"callId":"editor-view","name":"str_replace_editor","arguments":"{\"command\":\"view\",\"path\":\"{{cwd}}/note.txt\"}"}}
+{"type":"tool/result","seq":45,"time":1786547097887,"data":{"turn":1,"step":4,"message":{"source":{"kind":"tool","callId":"editor-view"},"content":[{"type":"tool-result","toolCallId":"editor-view","content":[{"type":"text","text":"Here's the content of {{cwd}}/note.txt with line numbers (which has a total of 3 lines):\n     1  target:\n     2  \told\n     3  \n"}],"isError":false}],"role":"user","id":"a4472b37-6311-4880-bce2-cc369f9bc34b"}},"sourceEventSeqs":[44],"surfaceOp":"append"}
+{"type":"step/end","seq":46,"time":1786547097887,"data":{"turn":1,"step":4}}
+{"type":"step/start","seq":47,"time":1786547097887,"data":{"turn":1,"step":5}}
+{"type":"assistant/chunk","seq":48,"time":1786547097887,"data":{"turn":1,"step":5,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":49,"time":1786547097887,"data":{"turn":1,"step":5,"chunk":{"type":"tool-call-delta","index":0,"id":"editor-replace","name":"str_replace_editor","argumentsDelta":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}
+{"type":"assistant/chunk","seq":50,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}}}
+{"type":"assistant/chunk","seq":51,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":52,"time":1785331618801,"data":{"turn":1,"step":5,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":53,"time":1786547097887,"data":{"turn":1,"step":5,"message":{"role":"assistant","content":[{"type":"tool-call","id":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"ba189070-d46e-461e-969b-9bca032bb154"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[48,49,50,51,52],"surfaceOp":"append"}
+{"type":"tool/call","seq":54,"time":1786547097887,"data":{"turn":1,"step":5,"callId":"editor-replace","name":"str_replace_editor","arguments":"{\"command\":\"str_replace\",\"path\":\"{{cwd}}/note.txt\",\"old_str\":\"\\told\",\"new_str\":\"\\tnew\"}"}}
+{"type":"tool/result","seq":55,"time":1786547097892,"data":{"turn":1,"step":5,"message":{"source":{"kind":"tool","callId":"editor-replace"},"content":[{"type":"tool-result","toolCallId":"editor-replace","content":[{"type":"text","text":"The file {{cwd}}/note.txt has been edited successfully."}],"isError":false}],"role":"user","id":"17331db9-174b-4699-9c9e-3140921956c4"}},"sourceEventSeqs":[54],"surfaceOp":"append"}
+{"type":"step/end","seq":56,"time":1786547097892,"data":{"turn":1,"step":5}}
+{"type":"step/start","seq":57,"time":1786547097892,"data":{"turn":1,"step":6}}
+{"type":"assistant/chunk","seq":58,"time":1786547097893,"data":{"turn":1,"step":6,"chunk":{"type":"block-start","index":0,"blockType":"tool-call"}}}
+{"type":"assistant/chunk","seq":59,"time":1786547097893,"data":{"turn":1,"step":6,"chunk":{"type":"tool-call-delta","index":0,"id":"bash-exit","name":"bash","argumentsDelta":"{\"command\":\"exit 9\"}"}}}
+{"type":"assistant/chunk","seq":60,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"block-end","index":0,"block":{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}}}
+{"type":"assistant/chunk","seq":61,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":62,"time":1785331618804,"data":{"turn":1,"step":6,"chunk":{"type":"finish","reason":{"kind":"tool-calls"}}}}
+{"type":"assistant/message","seq":63,"time":1786547097893,"data":{"turn":1,"step":6,"message":{"role":"assistant","content":[{"type":"tool-call","id":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"7fa07d0f-e70a-460d-b685-bf8a63b6a8a0"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[58,59,60,61,62],"surfaceOp":"append"}
+{"type":"tool/call","seq":64,"time":1786547097893,"data":{"turn":1,"step":6,"callId":"bash-exit","name":"bash","arguments":"{\"command\":\"exit 9\"}"}}
+{"type":"tool/result","seq":65,"time":1786547098003,"data":{"turn":1,"step":6,"message":{"source":{"kind":"tool","callId":"bash-exit"},"content":[{"type":"tool-result","toolCallId":"bash-exit","content":[{"type":"text","text":"exit\n[shell exited: code 9]\nThe persistent bash shell was reset; the next bash call starts from the workspace with a fresh current directory and environment."}],"isError":false}],"role":"user","id":"ccb91a28-4034-49bf-967d-450f68f7f9b8"}},"sourceEventSeqs":[64],"surfaceOp":"append"}
+{"type":"step/end","seq":66,"time":1786547098003,"data":{"turn":1,"step":6}}
+{"type":"step/start","seq":67,"time":1786547098003,"data":{"turn":1,"step":7}}
+{"type":"assistant/chunk","seq":68,"time":1786547098003,"data":{"turn":1,"step":7,"chunk":{"type":"block-start","index":0,"blockType":"text"}}}
+{"type":"assistant/chunk","seq":69,"time":1786547098003,"data":{"turn":1,"step":7,"chunk":{"type":"text-delta","index":0,"text":"PERSISTENT_TOOLS_OK"}}}
+{"type":"assistant/chunk","seq":70,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"block-end","index":0,"block":{"type":"text","text":"PERSISTENT_TOOLS_OK"}}}}
+{"type":"assistant/chunk","seq":71,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"usage","usage":{"inputTokens":3,"outputTokens":3}}}}
+{"type":"assistant/chunk","seq":72,"time":1785331618807,"data":{"turn":1,"step":7,"chunk":{"type":"finish","reason":{"kind":"stop"}}}}
+{"type":"assistant/message","seq":73,"time":1786547098003,"data":{"turn":1,"step":7,"message":{"role":"assistant","content":[{"type":"text","text":"PERSISTENT_TOOLS_OK"}],"source":{"kind":"model","provider":"deepseek-official","model":"deepseek-v4-flash"},"id":"43efc58a-46a1-4813-995f-1dc489438942"},"usage":{"inputTokens":3,"outputTokens":3}},"sourceEventSeqs":[68,69,70,71,72],"surfaceOp":"append"}
+{"type":"step/end","seq":74,"time":1786547098003,"data":{"turn":1,"step":7}}
+{"type":"turn/end","seq":75,"time":1786547098004,"data":{"turn":1,"reason":{"kind":"completed"}}}

+ 1 - 0
examples/package.json

@@ -36,6 +36,7 @@
     "@deepseek-ai/dsh-goal-round-driver": "workspace:*",
     "@deepseek-ai/dsh-hooks-claude-code": "workspace:*",
     "@deepseek-ai/dsh-hooks-codex": "workspace:*",
+    "@deepseek-ai/dsh-cordis-host-runner": "workspace:*",
     "@deepseek-ai/dsh-invariants": "workspace:*",
     "@deepseek-ai/dsh-sdk-jsonrpc-server": "workspace:*",
     "@deepseek-ai/dsh-llm": "workspace:*",

+ 2 - 0
examples/web-cordis/cordis.yml

@@ -13,5 +13,7 @@
     port: 3081
 
 - insert:
+    - id: cordis-host-runner
+      name: '@deepseek-ai/dsh-cordis-host-runner'
     - id: tool-cordis
       name: '@deepseek-ai/dsh-tool-cordis'

+ 12 - 0
knip.json

@@ -97,6 +97,18 @@
         "@deepseek-ai/dsh-client-ui-directory-picker-native"
       ]
     },
+    "packages/extensions/cordis-host-runner": {
+      "entry": [
+        "tests/**/*.spec.ts"
+      ],
+      "project": [
+        "src/**/*.ts",
+        "tests/**/*.ts"
+      ],
+      "ignoreDependencies": [
+        "zod"
+      ]
+    },
     "packages/host/directory-picker-native": {
       "entry": [
         "tests/**/*.spec.{ts,tsx}",

+ 4 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "@deepseek-ai/dsh-root",
-  "version": "0.0.1-rc.2",
+  "version": "0.0.1-rc.5",
   "private": true,
   "type": "module",
   "packageManager": "pnpm@11.7.0",
@@ -102,6 +102,9 @@
     "verify-cordis-catalog": "tsx scripts/gen-cordis-catalog.ts --check",
     "gen-cordis-api": "tsx scripts/gen-cordis-api.ts",
     "verify-cordis-api": "tsx scripts/gen-cordis-api.ts --check",
+    "gen-client-catalog": "tsx scripts/gen-client-catalog.ts",
+    "gen-cordis-inspect-catalog": "tsx scripts/gen-cordis-inspect-catalog.ts",
+    "verify-client-catalog": "tsx scripts/gen-client-catalog.ts --check",
     "verify-export-jsdoc": "tsx scripts/verify-export-jsdoc.ts",
     "gen-tool-catalog": "tsx scripts/gen-tool-catalog.ts",
     "verify-tool-catalog": "tsx scripts/gen-tool-catalog.ts --check",

Some files were not shown because too many files changed in this diff