Tianyi Cui 2 місяців тому
батько
коміт
44ad2ef073
64 змінених файлів з 228 додано та 481 видалено
  1. 3 4
      .agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md
  2. 1 1
      .agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md
  3. 2 2
      .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.i18n.yaml
  4. 1 1
      .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md
  5. 1 1
      .agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md
  6. 1 1
      .agents/notes/implemented/process/2026-06-11-quality-gates.md
  7. 1 1
      .agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md
  8. 1 2
      .agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md
  9. 1 1
      .agents/notes/implemented/process/2026-07-06-node-engine-floor.md
  10. 1 1
      .agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md
  11. 1 1
      .agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md
  12. 0 44
      .agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.md
  13. 0 44
      .agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.zh.md
  14. 2 2
      .agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.i18n.yaml
  15. 45 0
      .agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.md
  16. 45 0
      .agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.zh.md
  17. 2 2
      .agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.i18n.yaml
  18. 1 1
      .agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md
  19. 1 1
      .agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md
  20. 2 2
      .agents/skills/dsh-pre-push-checks/SKILL.md
  21. 1 7
      AGENTS.md
  22. 2 2
      README.i18n.yaml
  23. 5 5
      README.md
  24. 5 5
      README.zh.md
  25. 2 2
      docs/cookbook/adding-a-tool.i18n.yaml
  26. 1 1
      docs/cookbook/adding-a-tool.md
  27. 1 1
      docs/cookbook/adding-a-tool.zh.md
  28. 2 2
      docs/cookbook/extension-cookbook.i18n.yaml
  29. 1 1
      docs/cookbook/extension-cookbook.md
  30. 1 1
      docs/cookbook/extension-cookbook.zh.md
  31. 2 2
      docs/development.i18n.yaml
  32. 3 3
      docs/development.md
  33. 3 3
      docs/development.zh.md
  34. 0 1
      docs/graph-atlas.md
  35. 1 1
      docs/testing.md
  36. 2 2
      docs/user/develop/basic/index.i18n.yaml
  37. 6 6
      docs/user/develop/basic/index.md
  38. 6 6
      docs/user/develop/basic/index.zh.md
  39. 2 2
      docs/user/develop/practice/llm-adapter.i18n.yaml
  40. 1 2
      docs/user/develop/practice/llm-adapter.md
  41. 1 2
      docs/user/develop/practice/llm-adapter.zh.md
  42. 2 2
      docs/user/guide/config.i18n.yaml
  43. 0 1
      docs/user/guide/config.md
  44. 0 1
      docs/user/guide/config.zh.md
  45. 2 2
      docs/user/guide/quickstart.i18n.yaml
  46. 15 7
      docs/user/guide/quickstart.md
  47. 15 7
      docs/user/guide/quickstart.zh.md
  48. 0 2
      examples/AGENTS.md
  49. 1 12
      examples/README.md
  50. 0 25
      examples/echo-agent/README.md
  51. 0 40
      examples/echo-agent/composition.md
  52. 0 26
      examples/echo-agent/cordis.yml
  53. 0 7
      examples/echo-agent/package.json
  54. 0 19
      examples/echo-agent/src/echo-tool.ts
  55. 0 59
      examples/echo-agent/src/mock-llm.ts
  56. 0 37
      examples/echo-agent/tests/echo.e2e.ts
  57. 1 1
      examples/headless-agent/tests/fixtures/time-context-driver.ts
  58. 22 0
      examples/headless-agent/tests/fixtures/time-context-mock-llm.ts
  59. 4 4
      examples/headless-agent/tests/fixtures/time-context.cordis.yml
  60. 2 1
      knip.json
  61. 0 1
      package.json
  62. 2 2
      packages/context/time-context/tests/time-context.e2e.ts
  63. 0 10
      scripts/gen-doc-graphs.ts
  64. 2 46
      scripts/run-gates.ts

+ 3 - 4
.agents/notes/implemented/architecture/2026-06-20-extract-example-app-packages.md

@@ -16,7 +16,6 @@ Each example is now **mostly an invocation of an app package**, splitting the wi
 - **`@deepseek-ai/dsh-tui-demo`**, **`@deepseek-ai/dsh-cli-demo`**, and **`@deepseek-ai/dsh-acp-demo`** bake in their process roles. TUI includes the full-screen UI and a pre-created `main`; Headless includes the one-shot driver and a pre-created `main`; ACP includes the bridge and no pre-created agent. All three include JSONL persistence and omit stdout loggers.
 - **`start.ts` is gone.** Each app package exposes a bin; the `demo:*` scripts invoke it. Loader boot, `.env` loading, and fail-loud guards live in the shared [`@deepseek-ai/dsh-app-boot`](../../../../packages/ui/app-boot) package (unit-tested under the per-file coverage gate — see [share the app bins' boot glue](../simplification/2026-07-04-share-app-bin-boot-glue.md)); the thin self-executing entries are driven by keyless Loader-path tests.
 - **Each leaf `cordis.yml` collapses** to backends, optional product tools, and one app entry carrying the app config. TUI and Headless route model/session choices onto a pre-created agent; ACP routes the initial provider/model onto its bridge.
-- **echo-agent loads `dsh-cli-demo`**, swapping the LLM backend to the local `mock-llm` and adding the local `echo-tool` at the leaf. `mock-llm.ts` and `echo-tool.ts` stay as example-local teaching plugins.
 - **`base.yml`, `base-core.yml`, and `acp-agent/acp-tail.yml` are retired** — the spine they shared now lives in `dsh-agent-spine-demo`.
 
 `bash-local` and the LLM adapter stay **leaf choices**: the bundle ships `tool-bash` (the consumer schema), the leaf picks the executor implementation, so a sandboxed executor or replay adapter swaps in without touching the app.
@@ -39,13 +38,13 @@ The old `base*.yml`/`acp-tail.yml` includes already deduped the *config*, but a
 ## Verification
 
 - Example directories contain only their config, README, and tests: `start.ts`, the infrastructure preamble, and the shared YAML includes are gone.
-- `demo:echo`, `demo:tui`, `demo:headless`, and `demo:acp` invoke the app-package bins.
+- `demo:tui`, `demo:headless`, and `demo:acp` invoke the app-package bins.
 - Each new package has a README and per-file 100% coverage; each app package also has a keyless real-Loader-path bin smoke that catches export-shape failures described in [postmortem 0001](../../../../docs/postmortem/0001-acp-default-export-drops-inject.md).
 - The ACP replay transcript remains unchanged because the plugin set and load order did not change.
 
 ## Consequences
 
-- **The bare-plugin-tree pedagogy.** echo-agent's inlined `cordis.yml` showed every plugin at once; the spine now lives behind a bundle, so seeing the whole tree means opening `dsh-agent-spine-demo`. The app package's README carries that teaching weight.
+- **The bare-plugin-tree pedagogy.** The spine lives behind a bundle, so seeing the whole tree means opening `dsh-agent-spine-demo`. The app package's README carries that teaching weight.
 - **A layer of indirection.** "What does this demo load?" becomes a package read, not a single YAML scan.
 
 ## Related
@@ -53,4 +52,4 @@ The old `base*.yml`/`acp-tail.yml` includes already deduped the *config*, but a
 - Supersedes [Make the shared example base providerless](../../rejected/architecture/2026-06-20-providerless-example-base.md): renaming `base.yml` to the providerless core is moot once the spine moves into `dsh-agent-spine-demo` and the `base*.yml` files are deleted.
 - Builds on the [capability-seams](2026-06-13-capability-seams.md) interface/implementation/consumer split — backends and presentation stay leaf choices; the spine is the shared bundle.
 - Complements [Reorganize packages into a modular hierarchy](2026-06-20-package-hierarchy.md): the new app/core packages slot into existing groups under that hierarchy (`core` for the reusable spine bundle, `ui` for the app-specific front doors).
-- The later [remove-stdio-agent decision](../simplification/2026-07-20-remove-stdio-agent.md) owns the final TUI/Headless split and removal of the line-oriented app.
+- The later [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) owns the final TUI/Headless split and removes the line-oriented and mock-only leaves.

+ 1 - 1
.agents/notes/implemented/architecture/2026-06-20-package-hierarchy.md

@@ -2,7 +2,7 @@
 
 Status: implemented
 
-The later [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) decision superseded the original `support/ui-stdio` placement, and the [remove-stdio-agent](../simplification/2026-07-20-remove-stdio-agent.md) decision subsequently removed that surface entirely. The uniform depth-two hierarchy remains the decision owned here.
+The later [fold-stdio-helper](../simplification/2026-07-04-fold-stdio-ui-helper.md) decision superseded the original `support/ui-stdio` placement, and the [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) subsequently removed that surface entirely. The uniform depth-two hierarchy remains the decision owned here.
 
 ## Problem
 

+ 2 - 2
.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.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
-2026-07-17-dedicated-full-screen-tui-front-door.md: c7bd01011121f04683afde1d05b046970e497a71
-2026-07-17-dedicated-full-screen-tui-front-door.zh.md: 5de443f367725a116e70d368657562b6732904e7
+2026-07-17-dedicated-full-screen-tui-front-door.md: 8fbc5dddc029190b346075a65c9e7857187f3d2b
+2026-07-17-dedicated-full-screen-tui-front-door.zh.md: 6ddc3523b7a7173013efe2ef15c5ca0e940929fb

+ 1 - 1
.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.md

@@ -6,7 +6,7 @@ English | [中文](2026-07-17-dedicated-full-screen-tui-front-door.zh.md)
 
 ## Problem
 
-At the time this front door was introduced, the line-oriented agent handled pipes and ordinary terminals, but a full-screen coding interface had to own raw input, differential screen drawing, cursor state, overlays, and terminal restoration. Combining those contracts in one UI plugin would have coupled a stream-oriented path to a TTY-only lifecycle. The later [remove-stdio-agent decision](../simplification/2026-07-20-remove-stdio-agent.md) removes that redundant line agent; this Note continues to own the TUI design.
+At the time this front door was introduced, the line-oriented agent handled pipes and ordinary terminals, but a full-screen coding interface had to own raw input, differential screen drawing, cursor state, overlays, and terminal restoration. Combining those contracts in one UI plugin would have coupled a stream-oriented path to a TTY-only lifecycle. The later [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) removes that line agent; this Note continues to own the TUI design.
 
 The interactive channel must remain a Cordis plugin over the same agent, session, tool, and user-interaction services as every other front door. It needs to resume durable history, follow compaction replacements, display tool-owned presentation, and restore the terminal on startup failure and disposal. A standalone chat application or a second agent composition would duplicate behavior outside the plugin graph.
 

+ 1 - 1
.agents/notes/implemented/feature/2026-07-17-dedicated-full-screen-tui-front-door.zh.md

@@ -6,7 +6,7 @@ Status: implemented
 
 ## 问题
 
-在本入口引入时,面向行的 agent 负责 pipe 与普通终端,但全屏 coding 界面必须负责原始输入、差分绘制、光标状态、浮层和终端恢复。把这两类契约合并到一个 UI 插件中,会迫使面向 stream 的路径依赖仅适用于 TTY 的生命周期。后续的[移除 stdio agent 决策](../simplification/2026-07-20-remove-stdio-agent.md)移除了这一重复的面向行 agent;本 Note 继续负责 TUI 设计。
+在本入口引入时,面向行的 agent 负责 pipe 与普通终端,但全屏 coding 界面必须负责原始输入、差分绘制、光标状态、浮层和终端恢复。把这两类契约合并到一个 UI 插件中,会迫使面向 stream 的路径依赖仅适用于 TTY 的生命周期。后续的[移除重复 agent 决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)移除了这个面向行 agent;本 Note 继续负责 TUI 设计。
 
 交互通道必须继续作为 Cordis 插件,使用与其他入口相同的 agent(智能体)、会话、工具和用户交互服务。它需要恢复持久历史、跟随压缩替换、显示工具自有的呈现内容,并在启动失败和资源释放时恢复终端。独立聊天应用或第二套 agent 组合会在插件图之外重复实现这些行为。
 

+ 1 - 1
.agents/notes/implemented/process/2026-06-11-quality-gates.md

@@ -15,7 +15,7 @@ Every AGENTS.md promise gets a command that exits non-zero, wired into git hooks
 - jscpd detects cross-file clones in package production TypeScript and repository scripts; narrow source-range exceptions document deliberately parallel implementations.
 - Per-file 100% coverage on `packages/*/*/src` (v8); unreachable defensive guards carry `/* v8 ignore */ ` with stated reasons instead of deletion.
 - knip (dead code/deps), publint (package correctness), workspace constraints (workspace rules: private, cordis peer+dev, uniform version, ESM), and a NodeNext consumer typecheck for built package declarations.
-- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus a demo smoke test driving the echo-agent end to end.
+- lefthook pre-commit (lint staged, typecheck, vendor-manifest guard) and pre-push (tests, hygiene); CI runs the full matrix on node 22.19/24/26 plus built application smokes for the Headless, TUI, ACP, JSON-RPC, workflow, and code-runtime entry paths.
 
 ## Consequences
 

+ 1 - 1
.agents/notes/implemented/process/2026-06-16-pnpm-over-yarn.md

@@ -38,4 +38,4 @@ Performance (measured at migration time on the dev NFS filesystem; single-digit-
 
 On a fast local disk pnpm's content-addressed store typically wins on cold/warm installs and, especially, on **disk footprint** across multiple checkouts (one global store hardlinked into every `node_modules` vs Yarn copying ~279 MB per worktree — some devs regularly keep ~10 or more worktrees for this repo). That dedup advantage did **not** show in the migration-time numbers above because the test store and `node_modules` sat on different filesystems, defeating hardlinks; on a single-filesystem dev box or CI cache it applies. The honest summary: install speed on our NFS dev filesystem is a wash within noise; the move is justified by ecosystem alignment, phantom-dependency safety, and cross-checkout disk dedup — not by a raw install-time win.
 
-All quality gates (constraints, typecheck, lint, doc-sync, test:coverage at 100%, build, knip, publint, echo-agent demo smoke) pass unchanged on pnpm, which is the correctness proof that the linker swap introduced no phantom-dependency breakage.
+All quality gates (constraints, typecheck, lint, doc-sync, test:coverage at 100%, build, knip, publint, and built application smokes) pass on pnpm, which is the correctness proof that the linker swap introduces no phantom-dependency breakage.

+ 1 - 2
.agents/notes/implemented/process/2026-07-03-documentation-graph-atlas.md

@@ -26,14 +26,13 @@ Every graph page declares one maintenance mode:
 
 ### First shipped index
 
-The index links twelve relationship surfaces. Package topology and tool-package affordances live in the existing generated catalogs that already own those facts; the remaining focused diagrams are generated by `scripts/gen-doc-graphs.ts`.
+The index links eleven relationship surfaces. Package topology and tool-package affordances live in the existing generated catalogs that already own those facts; the remaining focused diagrams are generated by `scripts/gen-doc-graphs.ts`.
 
 | Graph | Maintenance mode | Source of truth |
 |---|---|---|
 | [module dependency graph](../../../../docs/module-graph.md) | generated | `packages/*/*/package.json` peer dependencies plus package group paths |
 | [tool schema catalog and package map](../../../../docs/tool-catalog.md) | generated | boot-harvested tool schemas plus tool-package service/effect metadata |
 | [capability seams and core services](../../../../docs/capability-seams.md) | hybrid generated | Cordis service declarations plus a role manifest in `gen-doc-graphs.ts` |
-| [echo-agent app composition](../../../../examples/echo-agent/composition.md) | hybrid generated | `examples/echo-agent/cordis.yml` plugin list plus curated app/bundle expansion |
 | [tui-agent app composition](../../../../examples/tui-agent/composition.md) | hybrid generated | `examples/tui-agent/cordis.yml` plugin list plus curated app/bundle expansion |
 | [headless-agent app composition](../../../../examples/headless-agent/composition.md) | hybrid generated | `examples/headless-agent/cordis.yml` plugin list plus curated app/bundle expansion |
 | [cordis-agent app composition](../../../../examples/cordis-agent/composition.md) | hybrid generated | `examples/cordis-agent/cordis.yml` plugin list plus curated app/bundle expansion |

+ 1 - 1
.agents/notes/implemented/process/2026-07-06-node-engine-floor.md

@@ -13,7 +13,7 @@ Set `engines.node` to `^22.19.0 || >=24.0.0` and test the keyless CI compatibili
 Two Node features gate the source runtime:
 
 - **`node:sqlite`** — `packages/session-persistence/session-persistence-sqlite` does a top-level `import { DatabaseSync } from 'node:sqlite'`. The module dropped its `--experimental-sqlite` flag requirement at **22.13** (LTS) and **23.4** (Current); before those, importing it throws at load.
-- **Native TypeScript type-stripping** — the built-mode `examples/echo-agent/tests/echo.e2e.ts` smoke boots `dsh-cli-demo`'s published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` plugins (`mock-llm.ts`, `echo-tool.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
+- **Native TypeScript type-stripping** — the built-mode `examples/headless-agent/tests/keyless-smoke.e2e.ts` smoke boots `dsh-cli-demo`'s published `lib/bin.js` under plain `node` (no tsx) and loads the example's `.ts` test adapter (`cli-mock-llm.ts`). Type-stripping is the default from **22.18** (LTS) and **23.6** (Current); before those it needs `--experimental-strip-types`.
 
 Those source features clear on the 22.x line at **22.18**, but the installed Pi adapter dependency raises the advertised LTS floor. `@deepseek-ai/dsh-llm-pi-ai` depends on `@earendil-works/pi-ai@0.79.3`, whose package declares `engines.node >=22.19.0`, so the LTS floor is **22.19**. The 24.x branch remains `>=24.0.0`. The disjoint range excludes Node 23 entirely: Node 23.0–23.5 still has at least one flagged source feature, and the 23 line is non-LTS/EOL, so advertising `>=23.6` would add a dead release line and a CI leg no deployment should use.
 

+ 1 - 1
.agents/notes/implemented/simplification/2026-06-20-drop-unconsumed-llm-adapter-change-event.md

@@ -24,7 +24,7 @@ If an LLM adapter browser or dynamic model-picker needs this signal later, reint
 
 ## Verification
 
-`llm/adapter-change` and its emits are gone and the regenerated cordis catalog is fresh; HMR-safety holds (disposing a contributing fiber removes the adapter); `tools/change` and `system-prompt/change` remain documented and tested; and no production path changed observable behavior — the ACP snapshot expected outputs and the echo-agent smoke are byte-unchanged.
+`llm/adapter-change` and its emits are gone and the regenerated cordis catalog is fresh; HMR-safety holds (disposing a contributing fiber removes the adapter); `tools/change` and `system-prompt/change` remain documented and tested; and the ACP snapshots plus the keyless Headless Loader smoke pin the unchanged production paths.
 
 ## Consequences
 

+ 1 - 1
.agents/notes/implemented/simplification/2026-07-04-fold-stdio-ui-helper.md

@@ -2,7 +2,7 @@
 
 Status: implemented
 
-The later [remove-stdio-agent decision](2026-07-20-remove-stdio-agent.md) supersedes this package-placement decision and removes the folded package, app, and line-oriented surface entirely.
+The later [redundant-agent removal](2026-07-20-remove-stdio-and-echo-agents.md) supersedes this package-placement decision and removes the folded package, app, and line-oriented surface entirely.
 
 ## Problem
 

+ 0 - 44
.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.md

@@ -1,44 +0,0 @@
-# Agent Note: Remove the line-oriented stdio agent
-
-Status: implemented
-
-English | [中文](2026-07-20-remove-stdio-agent.zh.md)
-
-## Problem
-
-DeepSeek Harness had two terminal agents after the full-screen TUI shipped. `@deepseek-ai/dsh-tui` owned the interactive coding experience, while `@deepseek-ai/dsh-stdio` retained a line-oriented multi-turn chat protocol for ordinary streams. The latter was no longer a distinct product need: interactive users use the TUI, and scripts need a bounded Headless task with explicit output and exit semantics rather than prompts mixed with model and tool output.
-
-The redundant surface extended beyond one UI plugin. `@deepseek-ai/dsh-stdio-demo` selected between two terminal modes, `examples/repl-agent` owned a second copy of the coding composition, `demo:repl` exposed it, Loader and built-bin tests drove its prompt protocol, and the SDK generator offered a `stdio` interface that could create new users of the obsolete package. Keeping any of those paths would preserve the line agent indirectly.
-
-Standard input and output are also used as transport by ACP, the SDK JSON-RPC bridge, subprocesses, and test fixtures. Those byte channels are protocol boundaries, not the line-oriented agent, so removing every generic use of process streams would conflate unrelated designs.
-
-## Decision
-
-The line-oriented agent is removed without a compatibility package or mode alias. The `packages/ui/stdio` plugin, `@deepseek-ai/dsh-stdio-demo` package identity, `examples/repl-agent` leaf, `demo:repl` command, prompt/render tests, and supporting manifest, catalog, graph, and documentation entries are deleted.
-
-The two remaining application roles are explicit:
-
-- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) is the only terminal-interactive app. `examples/tui-agent` owns the complete coding composition and its Code Mode overlay directly; it no longer includes or patches another terminal leaf.
-- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) owns non-interactive execution. `examples/headless-agent` owns the real-model one-shot composition and generic real-agent e2e suites, while `examples/echo-agent` supplies the keyless mock task and CI smoke.
-
-The SDK project model and create/config workflows replace the `stdio` run-interface option with `tui`; generated TUI projects compose `@deepseek-ai/dsh-tui` and continue to create or resume one exact session. No old option is accepted because the repository is pre-release and has no compatibility promise.
-
-ACP and JSON-RPC retain their stdio transports. Child-process `stdio` settings and stream-reading APIs also remain where they describe operating-system I/O rather than the removed agent.
-
-## Verification
-
-TUI Loader coverage runs the real app under a pseudo-terminal in both source and built modes. Headless Loader coverage proves the mock tool round trip, multi-turn test drivers exercise a single app-owned agent without a UI protocol, and the CLI built-bin suite pins text, JSON, stream-JSON, persistence, failure, and signal behavior. Generated package/config/module graphs reject stale package references.
-
-## Alternatives considered
-
-- **Keep the line agent only for pipes** — rejected because Headless already has a clearer bounded-task contract, format-pure stdout, durable completion, and process exit status.
-- **Keep the package as a compatibility wrapper over Headless** — rejected because a multi-turn prompt protocol cannot honestly preserve its behavior by delegating to a one-shot CLI, and the pre-release policy favors the correct public surface.
-- **Let the TUI fall back when streams are not TTYs** — rejected because silent interface changes hide deployment mistakes; the TUI fails loud and callers select Headless explicitly.
-- **Remove every use of the term or mechanism stdio** — rejected because ACP and JSON-RPC intentionally use standard I/O as a framed transport and do not expose the removed line agent.
-
-## Consequences
-
-- Terminal interaction has one owner, one app package, one coding leaf, and one test strategy.
-- Automation has an explicit task/result contract rather than prompt parsing or EOF-driven conversation control.
-- Existing line-agent configurations and SDK `--interface=stdio` invocations fail instead of being translated.
-- The TUI requires a TTY pair; non-interactive environments use Headless, ACP, or JSON-RPC according to their protocol needs.

+ 0 - 44
.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.zh.md

@@ -1,44 +0,0 @@
-# Agent Note: 移除面向行的 stdio agent
-
-Status: implemented
-
-[English](2026-07-20-remove-stdio-agent.md) | 中文
-
-## 问题
-
-全屏 TUI 交付后,DeepSeek Harness 同时存在两个终端 agent。`@deepseek-ai/dsh-tui` 负责交互式 coding 体验,而 `@deepseek-ai/dsh-stdio` 仍为普通 stream 保留面向行的多轮聊天协议。后者已不再对应独立的产品需求:交互用户使用 TUI;脚本需要的是具有明确输出和退出语义的有界 Headless 任务,而不是与模型和工具输出混在一起的提示符。
-
-重复 surface 不只涉及一个 UI 插件。`@deepseek-ai/dsh-stdio-demo` 在两种终端模式间选择,`examples/repl-agent` 维护第二份 coding 组装,`demo:repl` 对外暴露它,Loader 与 built-bin 测试驱动其提示符协议,SDK 生成器还提供可以创建旧包新用户的 `stdio` interface。保留其中任何路径,都会间接保留面向行的 agent。
-
-ACP、SDK JSON-RPC bridge、子进程和测试 fixture 同样使用标准输入输出作为 transport。这些字节通道是协议边界,并不是面向行的 agent;因此,删除所有通用进程 stream 用法会混淆彼此无关的设计。
-
-## 决策
-
-移除面向行的 agent,不提供兼容 package 或 mode alias。删除 `packages/ui/stdio` 插件、`@deepseek-ai/dsh-stdio-demo` package identity、`examples/repl-agent` 叶节点、`demo:repl` 命令、提示符/渲染测试,以及相关 manifest、catalog、graph 和文档条目。
-
-保留的两个应用角色均改为显式选择:
-
-- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) 是唯一的终端交互式 app。`examples/tui-agent` 直接拥有完整 coding 组装及其 Code Mode overlay,不再 include 或 patch 另一个终端叶节点。
-- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) 负责非交互式执行。`examples/headless-agent` 拥有真实模型的单次组装和通用真实 agent e2e suite,`examples/echo-agent` 则提供 keyless mock 任务与 CI smoke。
-
-SDK project model 与 create/config workflow 将 `stdio` run-interface 选项替换为 `tui`;生成的 TUI 工程组合 `@deepseek-ai/dsh-tui`,并继续创建或恢复一个确切 session。仓库处于 pre-release 阶段且没有兼容性承诺,因此不会接受旧选项。
-
-ACP 和 JSON-RPC 保留各自的 stdio transport。描述操作系统 I/O 而非已移除 agent 的子进程 `stdio` 设置与 stream 读取 API 也继续保留。
-
-## 验证
-
-TUI Loader 覆盖在 source 与 built 两种模式下通过伪终端运行真实 app。Headless Loader 覆盖验证 mock 工具往返;多轮测试 driver 在没有 UI 协议的情况下驱动同一个 app-owned agent;CLI built-bin suite 固定 text、JSON、stream-JSON、持久化、失败和 signal 行为。生成的 package/config/module graph 会拒绝陈旧的 package 引用。
-
-## 曾考虑的替代方案
-
-- **仅为 pipe 保留面向行的 agent**:不予采纳,因为 Headless 已提供更清晰的有界任务契约、格式纯净的 stdout、持久完成边界和进程退出状态。
-- **保留 package,并将其作为 Headless 的兼容 wrapper**:不予采纳,因为多轮提示符协议无法通过委托给单次 CLI 来诚实地保持行为,而且 pre-release 策略优先选择正确的公开 surface。
-- **让 TUI 在 stream 不是 TTY 时回退**:不予采纳,因为静默切换 interface 会掩盖部署错误;TUI 会快速失败,由调用方显式选择 Headless。
-- **移除 stdio 这个术语或机制的所有用法**:不予采纳,因为 ACP 与 JSON-RPC 有意使用标准 I/O 作为分帧 transport,并不暴露已移除的面向行 agent。
-
-## 后果
-
-- 终端交互只有一个 owner、一个 app package、一个 coding 叶节点和一套测试策略。
-- 自动化使用显式 task/result 契约,不再解析提示符或通过 EOF 控制对话。
-- 现有面向行的 agent 配置和 SDK `--interface=stdio` 调用会直接失败,不会被转换。
-- TUI 要求成对的 TTY;非交互环境根据协议需要使用 Headless、ACP 或 JSON-RPC。

+ 2 - 2
.agents/notes/implemented/simplification/2026-07-20-remove-stdio-agent.i18n.yaml → .agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.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
-2026-07-20-remove-stdio-agent.md: e4dcd371490e0810900134ab9a05f6f894ca06d0
-2026-07-20-remove-stdio-agent.zh.md: 9f0c2348de27b9c724e6f656881ec316bf48005f
+2026-07-20-remove-stdio-and-echo-agents.md: 2aba8193710c96d3726b91062bfa43d039b4cabf
+2026-07-20-remove-stdio-and-echo-agents.zh.md: 2c3916683f4743384a2ce4104319da26145837fe

+ 45 - 0
.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.md

@@ -0,0 +1,45 @@
+# Agent Note: Remove the stdio and Echo agents
+
+Status: implemented
+
+English | [中文](2026-07-20-remove-stdio-and-echo-agents.zh.md)
+
+## Problem
+
+DeepSeek Harness exposed two redundant product agents beside the TUI and Headless coding agents. The line-oriented stdio agent duplicated terminal interaction and non-interactive execution with a mixed prompt/output protocol. Echo duplicated Headless as a network-free mock model plus one teaching tool, making a test fixture into a user-facing agent and the default quick-start path.
+
+Both agents carried support surfaces beyond their leaf configurations. Stdio owned a UI plugin, app package, SDK interface, REPL leaf, prompt protocol, and Loader tests. Echo owned a runnable command, mock adapter, tool, CI demo gate, graph entry, teaching references, and a shared test fixture. Keeping any of those product paths would preserve the redundant agent indirectly.
+
+Standard input and output remain protocol boundaries for ACP, JSON-RPC, MCP, and child processes. Deterministic model adapters also remain valid inside tests. Those mechanisms do not justify a line-oriented or mock-only product agent.
+
+## Decision
+
+The stdio and Echo agents are removed without compatibility packages, modes, commands, or aliases. The stdio UI and app packages, `examples/repl-agent`, `examples/echo-agent`, `demo:repl`, `demo:echo`, their dedicated tests, and supporting manifests, gates, graphs, and documentation entries are deleted.
+
+The remaining application roles are explicit:
+
+- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) owns terminal-interactive execution. `examples/tui-agent` owns the complete coding composition, Code Mode overlay, PTY coverage, and terminal snapshots.
+- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) owns non-interactive execution. `examples/headless-agent` owns the real-model one-shot composition, replay snapshots, generic real-agent suites, and test-only keyless Loader fixtures.
+- [`@deepseek-ai/dsh-acp-demo`](../../../../packages/examples/acp-demo/README.md) and `@deepseek-ai/dsh-jsonrpc` own their framed protocol integrations.
+
+The SDK project model and create/config workflows replace the `stdio` run-interface option with `tui`; generated TUI projects compose `@deepseek-ai/dsh-tui` and create or resume one exact session. Repository-facing demo documentation requires a DeepSeek API key and leads with the real Headless or TUI agents.
+
+Keyless validation is test-owned. The Headless Loader smoke uses a fixture adapter to exercise a real tool round trip, the CLI built-bin suite pins output, persistence, failure, and signal semantics, and package-specific Loader tests keep deterministic adapters beside their scenarios. None is exposed as a runnable mock agent.
+
+## Verification
+
+TUI and Headless Loader coverage run the real app packages in source and built modes. TUI uses a pseudo-terminal; Headless proves its task/result and tool-call contracts. Generated graphs and repository searches reject stale package, command, leaf, and SDK-interface references.
+
+## Alternatives considered
+
+- **Keep the line agent only for pipes** — rejected because Headless has a bounded task contract, format-pure stdout, durable completion, and process exit status.
+- **Keep Echo as the keyless quick start** — rejected because the first product experience should exercise the real model and supported coding agent, not a scripted adapter with a bespoke tool.
+- **Keep Echo only as a CI demo command** — rejected because test-owned Headless fixtures cover the same Loader and built-artifact boundaries without preserving a mock product leaf.
+- **Remove every stdio or mock mechanism** — rejected because framed protocols, process I/O, and deterministic test adapters are independent infrastructure, not the removed agents.
+
+## Consequences
+
+- Interactive and non-interactive product execution each have one owner and one runnable coding leaf.
+- The repository has no keyless user-facing agent demo; local agent demos require `DEEPSEEK_API_KEY`.
+- CI retains keyless real-entry coverage through test fixtures rather than a product command.
+- Existing stdio-agent configurations, Echo commands, and SDK `--interface=stdio` invocations fail instead of being translated.

+ 45 - 0
.agents/notes/implemented/simplification/2026-07-20-remove-stdio-and-echo-agents.zh.md

@@ -0,0 +1,45 @@
+# Agent Note: 移除 stdio 和 Echo agent
+
+Status: implemented
+
+[English](2026-07-20-remove-stdio-and-echo-agents.md) | 中文
+
+## 问题
+
+DeepSeek Harness 在 TUI 和 Headless coding agent 之外,还提供了两个重复的产品 agent(智能体)。面向行的 stdio agent 使用混合的提示符/输出协议,同时重复实现终端交互与非交互执行。Echo 则以无需联网的 mock 模型加一个教学工具重复实现 Headless,把测试 fixture(测试前置数据)变成面向用户的 agent 和默认快速上手路径。
+
+两个 agent 的配套实现都不止叶节点配置。stdio 拥有 UI 插件、app 包(package)、SDK 接口、REPL 叶节点、提示符协议和 Loader 测试。Echo 拥有可运行命令、mock 适配器、工具、CI 演示门禁、图谱条目、教学引用和共享测试 fixture。保留其中任何产品路径,都会间接保留这个重复的 agent。
+
+标准输入输出仍是 ACP、JSON-RPC、MCP 和子进程的协议边界。确定性模型适配器也仍可用于测试。这些机制不足以成为保留面向行或仅使用 mock 的产品 agent 的理由。
+
+## 决策
+
+彻底移除 stdio 和 Echo agent,不提供兼容包、模式、命令或别名。删除 stdio UI 包与 app 包、`examples/repl-agent`、`examples/echo-agent`、`demo:repl`、`demo:echo`、各自的专属测试,以及相关的 manifest(元数据清单)、门禁、图谱和文档条目。
+
+保留的应用角色均有明确归属:
+
+- [`@deepseek-ai/dsh-tui-demo`](../../../../packages/examples/tui-demo/README.md) 负责终端交互式执行。`examples/tui-agent` 拥有完整 coding 组装、Code Mode 覆盖层、PTY 覆盖和终端快照。
+- [`@deepseek-ai/dsh-cli-demo`](../../../../packages/examples/cli-demo/README.md) 负责非交互式执行。`examples/headless-agent` 拥有真实模型的单次任务组装、回放快照、通用真实 agent 测试套件,以及仅供测试使用的无密钥 Loader fixture。
+- [`@deepseek-ai/dsh-acp-demo`](../../../../packages/examples/acp-demo/README.md) 和 `@deepseek-ai/dsh-jsonrpc` 负责各自的分帧协议集成。
+
+SDK 工程模型与 create/config 工作流将 `stdio` 运行接口选项替换为 `tui`;生成的 TUI 工程组合 `@deepseek-ai/dsh-tui`,并创建或恢复一个确切会话。仓库中的演示文档要求 DeepSeek API key,并优先引导到真实的 Headless 或 TUI agent。
+
+无密钥验证由测试负责。Headless Loader 冒烟测试使用 fixture 适配器验证真实工具往返;CLI built-bin 测试套件固定输出、持久化、失败和信号语义;各包专属的 Loader 测试则将确定性适配器放在对应场景旁。其中任何一项都不会作为可运行的 mock agent 对外暴露。
+
+## 验证
+
+TUI 与 Headless 的 Loader 覆盖以源码和构建产物两种模式运行真实 app 包。TUI 使用伪终端;Headless 验证任务/结果契约和工具调用契约。生成图谱与仓库搜索会拒绝陈旧的包、命令、叶节点和 SDK 接口引用。
+
+## 曾考虑的替代方案
+
+- **仅为 pipe 保留面向行 agent**:不予采纳,因为 Headless 已提供有界任务契约、格式纯净的 stdout、持久完成边界和进程退出状态。
+- **保留 Echo 作为无密钥快速上手路径**:不予采纳,因为首次产品体验应使用真实模型和受支持的 coding agent,而不是带专用工具的脚本化适配器。
+- **只为 CI 演示命令保留 Echo**:不予采纳,因为由测试持有的 Headless fixture 可以覆盖相同的 Loader 和构建产物边界,无需保留 mock 产品叶节点。
+- **移除所有 stdio 或 mock 机制**:不予采纳,因为分帧协议、进程 I/O 和确定性测试适配器是独立基础设施,并不是被移除的 agent。
+
+## 后果
+
+- 交互式与非交互式产品执行分别只有一个归属方和一个可运行的 coding 叶节点。
+- 仓库没有面向用户的无密钥 agent 演示;本地 agent 演示需要 `DEEPSEEK_API_KEY`。
+- CI 通过测试 fixture 保留针对真实入口的无密钥覆盖,而不是依赖产品命令。
+- 既有 stdio agent 配置、Echo 命令和 SDK `--interface=stdio` 调用会直接失败,不会被转换。

+ 2 - 2
.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.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
-2026-07-18-tui-terminal-state-snapshots.md: 7277e6be6d88a73ea3abbd277e314715c8abc050
-2026-07-18-tui-terminal-state-snapshots.zh.md: 068a8b8a7f469f40492924bf94757bc0e25c3404
+2026-07-18-tui-terminal-state-snapshots.md: 8e86588f69fdb9d615232252ecf57309d440f1cd
+2026-07-18-tui-terminal-state-snapshots.zh.md: b70a46830f44e9da663e30745fcdb7ad281592da

+ 1 - 1
.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.md

@@ -21,7 +21,7 @@ TUI coverage has four complementary layers:
 3. `examples/tui-agent/tests/tui.snapshot.ts` replays committed JSONL session logs through the production agent loop and real tools, then compares the resulting semantic terminal state.
 4. `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` boots the real Loader composition in a PTY, drives a scripted conversation through streaming and `ask_user_question`, and verifies startup, input, exit, failure reporting, and terminal restoration.
 
-The runnable TUI has its own `examples/tui-agent` leaf beside the Headless and ACP leaves. It owns the interactive coding backends and tools directly and loads `@deepseek-ai/dsh-tui-demo`; TUI snapshots and PTY tests live with that leaf. The [line-agent removal](../simplification/2026-07-20-remove-stdio-agent.md) owns this consolidation.
+The runnable TUI has its own `examples/tui-agent` leaf beside the Headless and ACP leaves. It owns the interactive coding backends and tools directly and loads `@deepseek-ai/dsh-tui-demo`; TUI snapshots and PTY tests live with that leaf. The [redundant-agent removal](../simplification/2026-07-20-remove-stdio-and-echo-agents.md) owns this consolidation.
 
 ### Recorded-session replay
 

+ 1 - 1
.agents/notes/implemented/testing/2026-07-18-tui-terminal-state-snapshots.zh.md

@@ -21,7 +21,7 @@ TUI 覆盖分为四个互补层次:
 3. `examples/tui-agent/tests/tui.snapshot.ts` 通过生产 agent loop 和真实工具回放已提交的 JSONL 会话日志,再比较生成的语义终端状态。
 4. `examples/tui-agent/tests/tui-keyless-smoke.e2e.ts` 在 PTY 中启动真实 Loader 组合,驱动一段经过流式输出和 `ask_user_question` 的脚本化会话,并验证启动、输入、退出、失败报告和终端恢复。
 
-可运行 TUI 在 `examples/tui-agent` 中拥有独立叶节点,与 Headless 和 ACP 叶节点并列。它直接拥有交互式 coding 后端与工具,并加载 `@deepseek-ai/dsh-tui-demo`;TUI 快照和 PTY 测试也归属这个叶节点。[面向行 agent 的移除决策](../simplification/2026-07-20-remove-stdio-agent.md)负责此次整合。
+可运行 TUI 在 `examples/tui-agent` 中拥有独立叶节点,与 Headless 和 ACP 叶节点并列。它直接拥有交互式 coding 后端与工具,并加载 `@deepseek-ai/dsh-tui-demo`;TUI 快照和 PTY 测试也归属这个叶节点。[移除重复 agent 的决策](../simplification/2026-07-20-remove-stdio-and-echo-agents.md)负责此次整合。
 
 ### 已录制会话回放
 

+ 2 - 2
.agents/skills/dsh-pre-push-checks/SKILL.md

@@ -5,7 +5,7 @@ description: Use before pushing, force-pushing, marking ready for review, claimi
 
 # DSH Pre-Push Checks
 
-Use this skill to choose and run the smallest sufficient verification set before a `deepseek-harness` push. Do not treat the local pre-push hook as the full CI contract: CI also runs coverage, build, demo smoke, and built-bin smoke.
+Use this skill to choose and run the smallest sufficient verification set before a `deepseek-harness` push. Do not treat the local pre-push hook as the full CI contract: CI also runs coverage, build, and built-bin smoke.
 
 ## First Steps
 
@@ -54,7 +54,7 @@ pnpm run test:snapshot
 Run built-bin smoke tests after `pnpm run build` when app packages, app boot, package runtime imports, bin entries, loader behavior, or published artifact paths change.
 
 ```sh
-DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/echo-agent/tests/echo.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts
+DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/headless-agent/tests/keyless-smoke.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts
 ```
 
 Run real e2e when behavior depends on a real model/API, tool-use loop, ACP integration, prompt injection, or end-to-end agent UX. If `.env` is available, use it; do not print secrets.

+ 1 - 7
AGENTS.md

@@ -58,7 +58,6 @@ pnpm run build          # tsc emits lib/types, tsdown bundles runtime
 pnpm run hygiene        # knip + publint + workspace constraints + NodeNext consumer check
 pnpm run doc-sync       # all documentation gates; see the doc-sync script in package.json
 pnpm run website:build  # VitePress build (doubles as the site's dead-link check)
-pnpm run demo:echo "task"    # mock-model headless agent, no key needed
 pnpm run demo:headless "task" # one-shot agent (needs DEEPSEEK_API_KEY)
 pnpm run demo:tui       # full-screen TUI coding agent (needs DEEPSEEK_API_KEY)
 pnpm run demo:cordis    # self-referential demo: the agent modifies its own runtime (needs key)
@@ -85,12 +84,7 @@ pnpm run website:build
 pnpm run verify-module-graph
 pnpm run build
 pnpm run hygiene
-out=$(pnpm run demo:echo --output-format stream-json -- "echo ci smoke" 2>&1)
-printf '%s\n' "$out" | grep -q '"type":"tool/call"'
-printf '%s\n' "$out" | grep -q 'ECHO: CI SMOKE'
-test -n "$(find .sessions -path '.sessions/cwd-*/main-session-*.jsonl' -type f -print -quit)"
-rm -rf .sessions
-DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/echo-agent/tests/echo.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts
+DSH_EXAMPLE_MODE=lib pnpm exec vitest run --config vitest.e2e.config.ts examples/headless-agent/tests/keyless-smoke.e2e.ts examples/tui-agent/tests/tui-keyless-smoke.e2e.ts packages/examples/cli-demo/tests/built-bin.e2e.ts packages/examples/acp-demo/tests/built-bin.e2e.ts packages/ui/jsonrpc/tests/built-scope-carrier.e2e.ts packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts
 ```
 
 `test:coverage`, not `test`, is the gate ([why](docs/testing.md)); report only commands actually run.

+ 2 - 2
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
-README.md: 4ce9391e9286391a601d59d8401870c9ca8c79f3
-README.zh.md: c4f996762b36d2ebe00cd256e2f18b0a62550ba8
+README.md: 32958db0e74bd14d6d41e8d7886b8d3257fe0f59
+README.zh.md: b28b175a8296347a7bed05b4e53c0d75dc51efed

+ 5 - 5
README.md

@@ -11,11 +11,11 @@ This monorepo is built on the [Cordis](https://github.com/cordiverse/cordis) fra
 ```sh
 pnpm install
 pnpm run test          # vitest
-pnpm run demo:echo "task"    # keyless mock-model headless agent
-pnpm run demo:tui      # full-screen TUI coding agent (needs DEEPSEEK_API_KEY)
-pnpm run demo:headless "task" # one-shot coding agent (needs DEEPSEEK_API_KEY)
-pnpm run demo:cordis   # self-referential agent demo (needs DEEPSEEK_API_KEY)
-pnpm run demo:acp      # ACP server agent demo (needs DEEPSEEK_API_KEY)
+# Agent demos require DEEPSEEK_API_KEY.
+pnpm run demo:tui      # full-screen TUI coding agent
+pnpm run demo:headless "task" # one-shot coding agent
+pnpm run demo:cordis   # self-referential agent demo
+pnpm run demo:acp      # ACP server agent demo
 ```
 
 For humans, start with the [development guide](docs/development.md) for local setup, hooks, environment variables, and quality gates, then read the [architecture design](docs/architecture.md) and [documentation graph index](docs/graph-atlas.md) before package work. Local context lives in [packages/](packages/) and [vendor/](vendor/).

+ 5 - 5
README.zh.md

@@ -11,11 +11,11 @@
 ```sh
 pnpm install
 pnpm run test          # vitest
-pnpm run demo:echo "task"    # keyless mock-model headless agent
-pnpm run demo:tui      # full-screen TUI coding agent (needs DEEPSEEK_API_KEY)
-pnpm run demo:headless "task" # one-shot coding agent (needs DEEPSEEK_API_KEY)
-pnpm run demo:cordis   # self-referential agent demo (needs DEEPSEEK_API_KEY)
-pnpm run demo:acp      # ACP server agent demo (needs DEEPSEEK_API_KEY)
+# Agent demos require DEEPSEEK_API_KEY.
+pnpm run demo:tui      # full-screen TUI coding agent
+pnpm run demo:headless "task" # one-shot coding agent
+pnpm run demo:cordis   # self-referential agent demo
+pnpm run demo:acp      # ACP server agent demo
 ```
 
 面向开发者:先读[开发指南](docs/development.md),了解本地环境搭建、钩子、环境变量与质量门禁,动手改 package 之前再读[架构设计](docs/architecture.md)和[文档关系图索引](docs/graph-atlas.md)。局部上下文见 [packages/](packages/) 与 [vendor/](vendor/)。

+ 2 - 2
docs/cookbook/adding-a-tool.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
-adding-a-tool.md: 68a8449bc189497b917efe678837d757f85aaf75
-adding-a-tool.zh.md: 003534e04550bfbee6740aa3b6bee02ac2cdc237
+adding-a-tool.md: a45315dc0ec92ab28963c2aca32dffcf5f778dcd
+adding-a-tool.zh.md: f574957ddd0e42cedc93ddc0f3270110a8f110c5

+ 1 - 1
docs/cookbook/adding-a-tool.md

@@ -2,7 +2,7 @@
 
 English | [中文](adding-a-tool.zh.md)
 
-How to give the model a new capability. Reference implementations: `examples/echo-agent/src/echo-tool.ts` (minimal) and `packages/bash/tool-bash` (production-grade, three-package seam).
+How to give the model a new capability. The minimal shape below shows the contract; `packages/bash/tool-bash` is the production-grade three-package seam.
 
 ## The minimal shape
 

+ 1 - 1
docs/cookbook/adding-a-tool.zh.md

@@ -2,7 +2,7 @@
 
 [English](adding-a-tool.md) | 中文
 
-如何为模型赋予一项新能力。参考实现:`examples/echo-agent/src/echo-tool.ts`(最小化)和 `packages/bash/tool-bash`(生产级,由三个包(package)构成的 seam)。
+如何为模型赋予一项新能力。下文的最小形态展示这项契约;`packages/bash/tool-bash` 是生产级、由三个包(package)构成的 seam。
 
 ## 最小形态
 

+ 2 - 2
docs/cookbook/extension-cookbook.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
-extension-cookbook.md: 811eeb04d1730a8062454f932477d1e05275f3cf
-extension-cookbook.zh.md: a1c22aeffcd337401bed9444ebd52ebd5b524595
+extension-cookbook.md: 32877b6170fd75ec901dda7cc0aec6b5a92e6cc6
+extension-cookbook.zh.md: d6bb6075b47867dcb5a848c835062ef4d9af5d45

+ 1 - 1
docs/cookbook/extension-cookbook.md

@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
 
 ## Runnable wirings
 
-Five runnable leaves load their plugin trees from `cordis.yml`: [`examples/echo-agent`](../../examples/echo-agent) (keyless mock model + echo tool through Headless, `pnpm run demo:echo "task"`), [`examples/tui-agent`](../../examples/tui-agent) (DeepSeek coding tools through the full-screen TUI, `pnpm run demo:tui`), [`examples/headless-agent`](../../examples/headless-agent) (the coding capabilities behind a one-shot task and DSH-native output, `pnpm run demo:headless "task"`), [`examples/cordis-agent`](../../examples/cordis-agent) (self-inspection and dynamic plugin mounting through the TUI, `pnpm run demo:cordis`), and [`examples/acp-agent`](../../examples/acp-agent) (an ACP server over JSON-RPC stdio, `pnpm run demo:acp`). Interactive leaves load [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves load [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), the ACP leaf loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and all three app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo).
+Four runnable leaves load their plugin trees from `cordis.yml`: [`examples/tui-agent`](../../examples/tui-agent) (DeepSeek coding tools through the full-screen TUI, `pnpm run demo:tui`), [`examples/headless-agent`](../../examples/headless-agent) (the coding capabilities behind a one-shot task and DSH-native output, `pnpm run demo:headless "task"`), [`examples/cordis-agent`](../../examples/cordis-agent) (self-inspection and dynamic plugin mounting through the TUI, `pnpm run demo:cordis`), and [`examples/acp-agent`](../../examples/acp-agent) (an ACP server over JSON-RPC stdio, `pnpm run demo:acp`). Interactive leaves load [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo), non-interactive leaves load [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), the ACP leaf loads [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo), and all three app packages share [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo).
 
 ## The feature → mechanism map
 

+ 1 - 1
docs/cookbook/extension-cookbook.zh.md

@@ -87,7 +87,7 @@ export function apply(ctx: Context) {
 
 ## 可运行的组装示例
 
-五个可运行叶子从 `cordis.yml` 加载各自的插件树:[`examples/echo-agent`](../../examples/echo-agent)(通过 Headless 运行的 keyless mock 模型 + echo 工具,`pnpm run demo:echo "task"`)、[`examples/tui-agent`](../../examples/tui-agent)(通过全屏 TUI 运行的 DeepSeek coding 工具,`pnpm run demo:tui`)、[`examples/headless-agent`](../../examples/headless-agent)(通过单次任务和 DSH 原生输出运行的 coding 能力,`pnpm run demo:headless "task"`)、[`examples/cordis-agent`](../../examples/cordis-agent)(通过 TUI 进行自我检查和动态插件挂载,`pnpm run demo:cordis`)与 [`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露的 ACP 服务器,`pnpm run demo:acp`)。交互式叶子加载 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子加载 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo),ACP 叶子加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo),三个 app 包都通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) 共享主干。
+四个可运行叶子从 `cordis.yml` 加载各自的插件树:[`examples/tui-agent`](../../examples/tui-agent)(通过全屏 TUI 运行的 DeepSeek coding 工具,`pnpm run demo:tui`)、[`examples/headless-agent`](../../examples/headless-agent)(通过单次任务和 DSH 原生输出运行的 coding 能力,`pnpm run demo:headless "task"`)、[`examples/cordis-agent`](../../examples/cordis-agent)(通过 TUI 进行自我检查和动态插件挂载,`pnpm run demo:cordis`)与 [`examples/acp-agent`](../../examples/acp-agent)(通过 JSON-RPC stdio 暴露的 ACP 服务器,`pnpm run demo:acp`)。交互式叶子加载 [`@deepseek-ai/dsh-tui-demo`](../../packages/examples/tui-demo),非交互式叶子加载 [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo),ACP 叶子加载 [`@deepseek-ai/dsh-acp-demo`](../../packages/examples/acp-demo),三个 app 包都通过 [`@deepseek-ai/dsh-agent-spine-demo`](../../packages/examples/agent-spine-demo) 共享主干。
 
 ## 功能→机制映射
 

+ 2 - 2
docs/development.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
-development.md: 6517a14f094a5098c26815e04f81e3f8ea1ceff9
-development.zh.md: bb70970679aaa8ffaed927b746002277cb422f6b
+development.md: 3327d094a31ad9af62a23c9562cdfa03218961a5
+development.zh.md: cb1cb86f9f3a34c455844467a20dfdfd08e15098

+ 3 - 3
docs/development.md

@@ -63,7 +63,7 @@ lefthook is configured in `lefthook.yml` as an early local checkpoint before rev
 
 The vendor manifest guard checks that changes under `vendor/*/src` are staged with the matching `vendor/README.md` manifest update. See `vendor/README.md` before editing vendored code.
 
-These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs echo-agent and built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26.
+These hooks do not exactly mirror CI. Notably, `pre-push` runs unit tests without coverage, while CI runs `pnpm run test:coverage`; CI also runs built-bin smoke tests and exercises the compatibility matrix on Node 22.19, 24, and 26.
 
 ## CI gates
 
@@ -102,10 +102,10 @@ When changing package public behavior, update the relevant README or JSDoc in th
 
 ## Demos
 
-The Headless echo demo does not need API credentials:
+The one-shot Headless coding agent needs `DEEPSEEK_API_KEY` in the environment or repo-root `.env`:
 
 ```sh
-pnpm run demo:echo "echo hello"
+pnpm run demo:headless "summarize this workspace"
 ```
 
 The full-screen interactive coding agent needs `DEEPSEEK_API_KEY` in the environment or repo-root `.env`:

+ 3 - 3
docs/development.zh.md

@@ -63,7 +63,7 @@ lefthook 在 `lefthook.yml` 中配置,作为评审前的本地早期检查点
 
 vendor manifest 守卫检查 `vendor/*/src` 下的改动是否连同对应的 `vendor/README.md` manifest 更新一起暂存。请在编辑 vendor 代码前先阅读 `vendor/README.md`。
 
-这些钩子并不与 CI 完全一致。特别是:`pre-push` 运行不带覆盖率的单元测试,而 CI 运行 `pnpm run test:coverage`;CI 还会运行 echo-agent 和 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上执行兼容性矩阵。
+这些钩子并不与 CI 完全一致。特别是:`pre-push` 运行不带覆盖率的单元测试,而 CI 运行 `pnpm run test:coverage`;CI 还会运行 built-bin 冒烟测试,并在 Node 22.19、24 和 26 上执行兼容性矩阵。
 
 ## CI 门禁
 
@@ -102,10 +102,10 @@ pnpm run hygiene        # knip, publint, workspace constraints, and NodeNext dec
 
 ## 演示
 
-Headless echo 演示不需要 API 凭证:
+单次运行的 Headless coding agent 需要环境变量或仓库根目录 `.env` 中的 `DEEPSEEK_API_KEY`:
 
 ```sh
-pnpm run demo:echo "echo hello"
+pnpm run demo:headless "summarize this workspace"
 ```
 
 全屏交互式 coding agent 需要环境变量或仓库根目录 `.env` 中的 `DEEPSEEK_API_KEY`:

+ 0 - 1
docs/graph-atlas.md

@@ -12,7 +12,6 @@ The process decision behind this index is recorded in [the documentation graph A
 | [module dependency graph](module-graph.md) | `generated` |
 | [tool schema catalog and package map](tool-catalog.md) | `generated` |
 | [capability seams and core services](capability-seams.md) | `hybrid generated` |
-| [echo-agent app composition](../examples/echo-agent/composition.md) | `hybrid generated` |
 | [tui-agent app composition](../examples/tui-agent/composition.md) | `hybrid generated` |
 | [headless-agent app composition](../examples/headless-agent/composition.md) | `hybrid generated` |
 | [cordis-agent app composition](../examples/cordis-agent/composition.md) | `hybrid generated` |

+ 1 - 1
docs/testing.md

@@ -11,7 +11,7 @@ How this repo tests, tier by tier, and the rules that keep a green suite meaning
 
 ## The with-key policy: inference is cheap here
 
-We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Write many: file-writing prompts, multi-turn conversations, tool use, cancellation mid-stream. Highest-value are **smoke tests** that boot the real example, send one real prompt, and check the world — they catch the "green unit tests, broken product" class that mocks structurally cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). The self-skip exists only so secretless CI and keyless contributors aren't blocked; it is not a cost signal. Every example ships a keyless smoke and — unless keyless-by-nature — a with-key smoke ([examples/AGENTS.md](../examples/AGENTS.md)).
+We are DeepSeek — do not ration real-API tests. A no-key test proves plumbing; only a with-key run proves the agent works against a real model. Write many: file-writing prompts, multi-turn conversations, tool use, cancellation mid-stream. Highest-value are **smoke tests** that boot the real example, send one real prompt, and check the world — they catch the "green unit tests, broken product" class that mocks structurally cannot ([postmortem 0001](postmortem/0001-acp-default-export-drops-inject.md)). The self-skip exists only so secretless CI and keyless contributors aren't blocked; it is not a cost signal. Every example ships both a keyless smoke and a with-key smoke ([examples/AGENTS.md](../examples/AGENTS.md)).
 
 ## Prefer the real implementation over a mock
 

+ 2 - 2
docs/user/develop/basic/index.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
-index.md: 5fa46806bc195ad2566fc0a29b45eb1dd7a68179
-index.zh.md: a6d238c12841c8c25b00376ee032e5db50fc6b4e
+index.md: d7d657ff7b8cb9001dd5e9c3af658a7a3c45b5b7
+index.zh.md: 7a134f7aaed470b87ee8ca8978dd39593de2651b

+ 6 - 6
docs/user/develop/basic/index.md

@@ -122,24 +122,24 @@ Function form is sufficient in most cases. Use class form when the plugin provid
 
 ## Complete example
 
-`examples/echo-agent/src/echo-tool.ts` is a plugin that registers a tool:
+A minimal tool plugin registers its definition on `ctx.tools`:
 
 ```ts
 import type { Context } from 'cordis'
 import { defineTool } from '@deepseek-ai/dsh-tools'
 
-export const name = 'echo-tool'
+export const name = 'greet-tool'
 export const inject = ['tools']
 
 export function apply(ctx: Context) {
   ctx.tools.register(defineTool({
-    name: 'echo',
-    description: 'Echo the given text back, uppercased.',
+    name: 'greet',
+    description: 'Greet the named person.',
     parameters: {
-      text: { type: 'string', required: true },
+      name: { type: 'string', required: true },
     },
     async execute(args) {
-      return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }]
+      return [{ type: 'text', text: `Hello, ${args.name}!` }]
     },
   }))
 }

+ 6 - 6
docs/user/develop/basic/index.zh.md

@@ -122,24 +122,24 @@ export default class MyService extends Service {
 
 ## 完整示例
 
-参考仓库中的 `examples/echo-agent/src/echo-tool.ts`,这是一个注册 tool 的插件:
+最小化的工具插件会在 `ctx.tools` 上注册其定义:
 
 ```ts
 import type { Context } from 'cordis'
 import { defineTool } from '@deepseek-ai/dsh-tools'
 
-export const name = 'echo-tool'
+export const name = 'greet-tool'
 export const inject = ['tools']
 
 export function apply(ctx: Context) {
   ctx.tools.register(defineTool({
-    name: 'echo',
-    description: 'Echo the given text back, uppercased.',
+    name: 'greet',
+    description: 'Greet the named person.',
     parameters: {
-      text: { type: 'string', required: true },
+      name: { type: 'string', required: true },
     },
     async execute(args) {
-      return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }]
+      return [{ type: 'text', text: `Hello, ${args.name}!` }]
     },
   }))
 }

+ 2 - 2
docs/user/develop/practice/llm-adapter.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
-llm-adapter.md: 83296e54220c668410fe69d689199171251a7787
-llm-adapter.zh.md: 89b7185690dbdfe33cbafe7b0ee4c3e83cfe0df8
+llm-adapter.md: 3e83289b8072ef231f83c0fa3cfe3260547b42fa
+llm-adapter.zh.md: 92fcf9b22f4bb356ada4c46f9a03ef0cc2d159da

+ 1 - 2
docs/user/develop/practice/llm-adapter.md

@@ -145,9 +145,8 @@ The repository contains complete implementations:
 
 - `packages/llm/llm-deepseek/` — DeepSeek API adapter using the OpenAI-compatible format
 - `packages/llm/llm-pi-ai/` — Pi AI adapter using a different API format
-- `examples/echo-agent/src/mock-llm.ts` — minimal local teaching adapter
 
-Start with the mock adapter to study a complete chunk sequence without network behavior.
+Compare the two shipped adapters to see the same harness contract implemented over different provider SDKs.
 
 ## Error handling
 

+ 1 - 2
docs/user/develop/practice/llm-adapter.zh.md

@@ -145,9 +145,8 @@ ctx.llm.registerAdapter(['model-name-1', 'model-name-2'], adapter)
 
 - `packages/llm/llm-deepseek/` — DeepSeek API 适配器(OpenAI 兼容格式)
 - `packages/llm/llm-pi-ai/` — Pi AI 适配器(不同的 API 格式)
-- `examples/echo-agent/src/mock-llm.ts` — 最简 mock 适配器(教学用)
 
-mock 适配器是学习 StreamChunk 协议的最佳起点——它用纯本地逻辑演示了完整的 chunk 序列。
+对比这两个已交付的适配器,可以看到同一套 harness 契约如何在不同提供方 SDK 之上实现。
 
 ## 错误处理
 

+ 2 - 2
docs/user/guide/config.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
-config.md: 0616f163f995b152d7a28841506027558de2c32c
-config.zh.md: fa91445ae88456a61a4736ce8b71aed482227ce8
+config.md: 8958729d04224215ca420c3103d253a8a5783405
+config.zh.md: 530f2b335453d5064acdac28a60d7df51cd915f0

+ 0 - 1
docs/user/guide/config.md

@@ -8,7 +8,6 @@ Harness uses `cordis.yml` to describe which plugins an agent loads and the confi
 
 The repository examples are runnable configurations and the most reliable starting points for a new project:
 
-- [echo-agent](../../../examples/echo-agent/cordis.yml) uses a local mock model and needs no API key.
 - [tui-agent](../../../examples/tui-agent/cordis.yml) combines the DeepSeek model, Bash, filesystem, compaction, subagents, workflows, and the interactive TUI.
 - [headless-agent](../../../examples/headless-agent/cordis.yml) exposes the coding composition as a one-shot task.
 - [acp-agent](../../../examples/acp-agent/cordis.yml) connects to editor clients over ACP.

+ 0 - 1
docs/user/guide/config.zh.md

@@ -8,7 +8,6 @@ Harness 使用 `cordis.yml` 描述 Agent 加载哪些插件以及每个插件的
 
 仓库中的示例就是可以运行的配置,也是新项目最可靠的起点:
 
-- [echo-agent](../../../examples/echo-agent/cordis.yml) 使用本地 mock 模型,不需要 API key。
 - [tui-agent](../../../examples/tui-agent/cordis.yml) 组合 DeepSeek 模型、Bash、文件系统、压缩、子代理、工作流和交互式 TUI。
 - [headless-agent](../../../examples/headless-agent/cordis.yml) 以单次任务形式暴露 coding 组装。
 - [acp-agent](../../../examples/acp-agent/cordis.yml) 通过 ACP 接入编辑器客户端。

+ 2 - 2
docs/user/guide/quickstart.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
-quickstart.md: 62e899adfa33e566083b8224b9bdf77c1038557a
-quickstart.zh.md: 382c9685ebe0c919c2fd039484898b44e9264aa7
+quickstart.md: 25ce51ee3d010d2eb800071b9697fc62857dace1
+quickstart.zh.md: e2e023670a999566e273d8893c42103dc273e7b1

+ 15 - 7
docs/user/guide/quickstart.md

@@ -8,6 +8,7 @@ This guide gets an agent running in five minutes.
 
 - [Node.js](https://nodejs.org/) ^22.19 or >= 24
 - [pnpm](https://pnpm.io/) 11 through Corepack
+- A [DeepSeek Platform](https://platform.deepseek.com/) API key
 
 ```sh
 node -v
@@ -15,25 +16,32 @@ corepack enable
 pnpm -v
 ```
 
-## Step 1: run the keyless Headless demo
+## Step 1: install and configure the API key
 
 ```sh
 git clone https://github.com/deepseek-harness/deepseek-harness.git
 cd deepseek-harness
 pnpm install
-pnpm run demo:echo "echo hello world"
 ```
 
-The local mock model calls the `echo` tool, which returns the text in uppercase, and the final response is printed without opening an interactive UI. Use `--output-format stream-json` when you need the canonical event stream.
+Create the gitignored repository-root `.env`:
 
-## Step 2: use a real model in the TUI
+```sh
+DEEPSEEK_API_KEY=sk-your-key-here
+```
+
+## Step 2: run one Headless task
 
-Get an API key from [DeepSeek Platform](https://platform.deepseek.com/) and create the gitignored repository-root `.env`:
+Run a non-interactive task and print its final answer:
 
 ```sh
-DEEPSEEK_API_KEY=sk-your-key-here
+pnpm run demo:headless "summarize the architecture of this workspace"
 ```
 
+Headless runs one complete model/tool turn, persists the session, prints the result, and exits. Use `--output-format stream-json` when you need the canonical event stream.
+
+## Step 3: use the TUI
+
 Start the interactive coding agent:
 
 ```sh
@@ -44,7 +52,7 @@ The full-screen agent can read and write files, run commands, delegate subtasks,
 
 ## What happened
 
-echo-agent uses the Headless `@deepseek-ai/dsh-cli-demo` app; tui-agent uses the interactive `@deepseek-ai/dsh-tui-demo` app. Both load the same providerless agent spine, while their `cordis.yml` files select the model and capability plugins appropriate to each surface.
+headless-agent uses the `@deepseek-ai/dsh-cli-demo` app; tui-agent uses the interactive `@deepseek-ai/dsh-tui-demo` app. Both load the same providerless agent spine, while their `cordis.yml` files select the DeepSeek model and capability plugins appropriate to each surface.
 
 ## Next steps
 

+ 15 - 7
docs/user/guide/quickstart.zh.md

@@ -8,6 +8,7 @@
 
 - [Node.js](https://nodejs.org/) ^22.19 或 >= 24
 - 通过 Corepack 使用 [pnpm](https://pnpm.io/) 11
+- [DeepSeek Platform](https://platform.deepseek.com/) API key
 
 ```sh
 node -v
@@ -15,25 +16,32 @@ corepack enable
 pnpm -v
 ```
 
-## 第一步:运行 keyless Headless 演示
+## 第一步:安装并配置 API key
 
 ```sh
 git clone https://github.com/deepseek-harness/deepseek-harness.git
 cd deepseek-harness
 pnpm install
-pnpm run demo:echo "echo hello world"
 ```
 
-本地 mock 模型会调用 `echo` 工具,由工具返回大写文本,最终回复在不打开交互式 UI 的情况下直接输出。需要规范事件流时可使用 `--output-format stream-json`。
+在仓库根目录创建已被 Git 忽略的 `.env`:
 
-## 第二步:在 TUI 中使用真实模型
+```sh
+DEEPSEEK_API_KEY=sk-your-key-here
+```
+
+## 第二步:运行一个 Headless 任务
 
-前往 [DeepSeek Platform](https://platform.deepseek.com/) 获取 API key,并创建已被 Git 忽略的仓库根目录 `.env`:
+运行一个非交互式任务并打印最终回答:
 
 ```sh
-DEEPSEEK_API_KEY=sk-your-key-here
+pnpm run demo:headless "summarize the architecture of this workspace"
 ```
 
+Headless 运行一个完整的模型/工具轮次,持久化会话,打印结果后退出。需要规范事件流时可使用 `--output-format stream-json`。
+
+## 第三步:使用 TUI
+
 启动交互式 coding agent:
 
 ```sh
@@ -44,7 +52,7 @@ pnpm run demo:tui
 
 ## 回头看
 
-echo-agent 使用 Headless `@deepseek-ai/dsh-cli-demo` app,tui-agent 使用交互式 `@deepseek-ai/dsh-tui-demo` app。二者加载同一个 providerless agent spine,并通过各自的 `cordis.yml` 为对应 surface 选择模型和能力插件。
+headless-agent 使用 `@deepseek-ai/dsh-cli-demo` app,tui-agent 使用交互式 `@deepseek-ai/dsh-tui-demo` app。二者加载同一个 providerless agent spine,并通过各自的 `cordis.yml` 为对应 surface 选择 DeepSeek 模型和能力插件。
 
 ## 下一步
 

+ 0 - 2
examples/AGENTS.md

@@ -11,8 +11,6 @@ Each example has both:
 - **Keyless:** boot the real `cordis.yml` through the Loader, drive it, and assert output and clean exit. Catches Loader/export-shape failures hand-mounted tests miss ([postmortem](../docs/postmortem/0001-acp-default-export-drops-inject.md)).
 - **With-key:** send a live-model prompt and verify external state, not the model's claim. Self-skip without `DEEPSEEK_API_KEY`; see [testing.md](../docs/testing.md).
 
-Mock-only examples require only the keyless tier; state that exception in the test.
-
 Keyless process smokes use `@deepseek-ai/dsh-loader-smoke` for Loader launch resolution; terminal tests wrap that launch in a pseudo-terminal. Tests supply paths, environment, input, and assertions. Every checked-in test Cordis config lives under its corresponding `examples/<agent>/` leaf. Map a package-owned config to `examples/<agent>/tests/fixtures/<group>/<package>/cordis.yml`, keep its driver and assertions package-local, and declare every package it names in both root `tsconfig.json` references and `examples/package.json`.
 
 Do not inventory example tests here; the `tests/` trees and root scripts are authoritative.

+ 1 - 12
examples/README.md

@@ -1,17 +1,6 @@
 # Examples
 
-Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks swappable backends, loads one app package, and may add optional product tools or demo-only mocks. The composition and boot glue live in [`@deepseek-ai/dsh-tui-demo`](../packages/examples/tui-demo), [`@deepseek-ai/dsh-cli-demo`](../packages/examples/cli-demo), [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo), and their shared [`@deepseek-ai/dsh-agent-spine-demo`](../packages/examples/agent-spine-demo) bundle. There is no `start.ts`; the `demo:*` scripts invoke each app package's bin.
-
-## echo-agent
-
-A mock model + echo tool on the headless one-shot app — the all-mock skeleton. It demonstrates:
-
-- A thin leaf `cordis.yml` loading the `@deepseek-ai/dsh-cli-demo` app
-- Registering a mock `LlmAdapter` (streaming scripted responses)
-- Registering a tool via `ctx.tools.register()`
-- A network-free Headless task with text or DSH-native JSON output
-
-Run with: `pnpm run demo:echo "echo hello"`. The task prefix `echo ` triggers a tool-call round trip.
+Runnable demos (not workspaces) that showcase how the harness is wired. Each example is a **thin leaf**: a `cordis.yml` that picks swappable backends, loads one app package, and may add optional product tools. The composition and boot glue live in [`@deepseek-ai/dsh-tui-demo`](../packages/examples/tui-demo), [`@deepseek-ai/dsh-cli-demo`](../packages/examples/cli-demo), [`@deepseek-ai/dsh-acp-demo`](../packages/examples/acp-demo), and their shared [`@deepseek-ai/dsh-agent-spine-demo`](../packages/examples/agent-spine-demo) bundle. There is no `start.ts`; the `demo:*` scripts invoke each app package's bin.
 
 ## headless-agent
 

+ 0 - 25
examples/echo-agent/README.md

@@ -1,25 +0,0 @@
-# echo-agent
-
-Network-free Headless demo with a scripted mock model and an echo tool.
-
-## What it shows
-
-The leaf loads [`@deepseek-ai/dsh-cli-demo`](../../packages/examples/cli-demo), which supplies the shared spine, JSONL persistence, one fresh `main` agent, and the one-shot CLI driver. Two local plugins provide the demo behavior:
-
-- `mock-llm.ts` registers a scripted `LlmAdapter`; a task beginning with `echo ` requests the tool.
-- `echo-tool.ts` registers a typed tool that returns the input uppercased.
-
-| File | Role |
-|---|---|
-| `src/mock-llm.ts` | Streaming mock adapter |
-| `src/echo-tool.ts` | Model-facing echo tool |
-| `cordis.yml` | Mock plugins, local providers, and one `@deepseek-ai/dsh-cli-demo` entry |
-
-## Run
-
-```sh
-pnpm run demo:echo "echo hello world"
-pnpm run demo:echo --output-format stream-json -- "echo hello world"
-```
-
-The first command prints the final canned response. `stream-json` also exposes the canonical `tool/call` and `tool/result` events. Sessions persist under `.sessions/` relative to the launch directory; remove that generated directory when finished.

+ 0 - 40
examples/echo-agent/composition.md

@@ -1,40 +0,0 @@
-<!-- Generated by scripts/gen-doc-graphs.ts - do not edit by hand.
-     Run `pnpm run gen-doc-graphs` to regenerate. -->
-
-# Echo Agent App Composition
-
-The echo demo swaps in a local mock LLM and teaching echo tool, then loads the headless one-shot app package.
-
-```mermaid
-flowchart LR
-  cfg["examples/echo-agent<br/>cordis.yml"]
-  plugin_echo_mock_llm["mock-llm<br/>./src/mock-llm.ts"]
-  cfg --> plugin_echo_mock_llm
-  plugin_echo_echo_tool["echo-tool<br/>./src/echo-tool.ts"]
-  cfg --> plugin_echo_echo_tool
-  plugin_echo_bash["bash<br/>@deepseek-ai/dsh-bash-local"]
-  cfg --> plugin_echo_bash
-  plugin_echo_fs_local["fs-local<br/>@deepseek-ai/dsh-fs-local"]
-  cfg --> plugin_echo_fs_local
-  plugin_echo_cli_agent["cli-agent<br/>@deepseek-ai/dsh-cli-demo"]
-  cfg --> plugin_echo_cli_agent
-  plugin_echo_cli_agent --> bundle_agent_core["@deepseek-ai/dsh-agent-spine-demo"]
-  plugin_echo_cli_agent --> bundle_jsonl["@deepseek-ai/dsh-session-persistence-jsonl"]
-  plugin_echo_cli_agent --> frontdoor_cli["one-shot driver<br/>format-pure stdout<br/>fresh top-level agent"]
-  bundle_agent_core --> spine_llm["ctx.llm"]
-  bundle_agent_core --> spine_sessions["ctx.sessions"]
-  bundle_agent_core --> spine_tools["ctx.tools + tool-bash"]
-  bundle_agent_core --> spine_loop["ctx.agents + ctx.agentLoop"]
-```
-
-| Plugin id | Package / module |
-| --- | --- |
-| `mock-llm` | `./src/mock-llm.ts` |
-| `echo-tool` | `./src/echo-tool.ts` |
-| `bash` | `@deepseek-ai/dsh-bash-local` |
-| `fs-local` | `@deepseek-ai/dsh-fs-local` |
-| `cli-agent` | `@deepseek-ai/dsh-cli-demo` |
-
-Source config: [`examples/echo-agent/cordis.yml`](cordis.yml).
-
-Maintenance mode: hybrid: the leaf plugin list is parsed from its `cordis.yml`; app package expansion is curated from package source.

+ 0 - 26
examples/echo-agent/cordis.yml

@@ -1,26 +0,0 @@
-# Headless agent with the network-free `mock-echo` adapter and example-local
-# `echo` tool. No API key is needed because the adapter never touches the network.
-
-- id: mock-llm
-  name: './src/mock-llm.ts'
-
-- id: echo-tool
-  name: './src/echo-tool.ts'
-
-- id: bash
-  name: '@deepseek-ai/dsh-bash-local'
-
-- id: fs-local
-  name: '@deepseek-ai/dsh-fs-local'
-  config:
-    cwd: !!js process.cwd()
-
-- id: cli-agent
-  name: '@deepseek-ai/dsh-cli-demo'
-  config:
-    provider: mock
-    model: mock-echo
-    persona: 'You are echo-agent, a demo agent.'
-    persistenceRoot: './.sessions'
-    workspaceContext:
-      maxBytes: 65536

+ 0 - 7
examples/echo-agent/package.json

@@ -1,7 +0,0 @@
-{
-  "name": "echo-agent-example",
-  "private": true,
-  "version": "0.0.1",
-  "type": "module",
-  "description": "Runnable headless demo: scripted mock model + echo tool"
-}

+ 0 - 19
examples/echo-agent/src/echo-tool.ts

@@ -1,19 +0,0 @@
-import type { Context } from 'cordis'
-import { defineTool } from '@deepseek-ai/dsh-tools'
-
-export const name = 'echo-tool'
-export const inject = ['tools']
-
-export function apply(ctx: Context) {
-  ctx.tools.register(defineTool({
-    name: 'echo',
-    description: 'Echo the given text back, uppercased.',
-    parameters: {
-      text: { type: 'string', required: true },
-    },
-    async execute(args) {
-      // args is typed: { text: string }
-      return [{ type: 'text', text: `ECHO: ${args.text.toUpperCase()}` }]
-    },
-  }))
-}

+ 0 - 59
examples/echo-agent/src/mock-llm.ts

@@ -1,59 +0,0 @@
-import type { Context } from 'cordis'
-import type { GenerateOptions, StreamChunk } from '@deepseek-ai/dsh-llm'
-import { CallId, LlmAdapter } from '@deepseek-ai/dsh-llm'
-
-/**
- * Demo adapter for the `mock-echo` model.
- *
- * Behavior: if the last user text starts with "echo ", it calls the `echo`
- * tool with the rest of the line (exercising the tool round-trip), otherwise
- * it streams a canned reply quoting the input.
- */
-class MockEchoAdapter extends LlmAdapter {
-  async * stream(options: GenerateOptions): AsyncIterable<StreamChunk> {
-    const lastUserText = [...options.messages].reverse()
-      .filter(message => message.role === 'user')
-      .flatMap(message => message.content)
-      .filter(block => block.type === 'text')
-      .map(block => block.text)
-      .find(text => !text.startsWith('<')) ?? ''
-
-    const hasToolResult = options.messages.at(-1)?.content.some(block => block.type === 'tool-result')
-
-    if (lastUserText.startsWith('echo ') && !hasToolResult) {
-      const payload = lastUserText.slice(5)
-      const args = JSON.stringify({ text: payload })
-      yield { type: 'block-start', index: 0, blockType: 'text' }
-      for (const char of 'Let me echo that for you.') {
-        yield { type: 'text-delta', index: 0, text: char }
-        await new Promise(resolve => setTimeout(resolve, 2))
-      }
-      yield { type: 'block-end', index: 0, block: { type: 'text', text: 'Let me echo that for you.' } }
-      yield { type: 'block-start', index: 1, blockType: 'tool-call' }
-      yield { type: 'tool-call-delta', index: 1, id: CallId('call-echo'), name: 'echo', argumentsDelta: args }
-      yield { type: 'block-end', index: 1, block: { type: 'tool-call', id: CallId('call-echo'), name: 'echo', arguments: args } }
-      yield { type: 'usage', usage: { inputTokens: 20, outputTokens: 10 } }
-      yield { type: 'finish', reason: { kind: 'tool-calls' } }
-      return
-    }
-
-    const reply = hasToolResult
-      ? 'The echo tool has spoken.'
-      : `You said: "${lastUserText}". Try "echo <something>" to see a tool call.`
-    yield { type: 'block-start', index: 0, blockType: 'text' }
-    for (const char of reply) {
-      yield { type: 'text-delta', index: 0, text: char }
-      await new Promise(resolve => setTimeout(resolve, 2))
-    }
-    yield { type: 'block-end', index: 0, block: { type: 'text', text: reply } }
-    yield { type: 'usage', usage: { inputTokens: 20, outputTokens: reply.length } }
-    yield { type: 'finish', reason: { kind: 'stop' } }
-  }
-}
-
-export const name = 'mock-llm'
-export const inject = ['llm']
-
-export function apply(ctx: Context) {
-  ctx.llm.registerAdapter(['mock'], new MockEchoAdapter())
-}

+ 0 - 37
examples/echo-agent/tests/echo.e2e.ts

@@ -1,37 +0,0 @@
-import { fileURLToPath } from 'node:url'
-import { describe, expect, it } from 'vitest'
-import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-loader-smoke'
-import type { SessionEvent } from '@deepseek-ai/dsh-session'
-
-const binScript = fileURLToPath(new URL('../../../packages/examples/cli-demo/src/bin.ts', import.meta.url))
-const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
-const tsconfigPath = fileURLToPath(new URL('../../../tsconfig.json', import.meta.url))
-
-async function runEcho(task: string, outputFormat: 'text' | 'stream-json' = 'text'): Promise<string> {
-  const { stdout } = await runLoaderSmoke({
-    label: 'echo-agent',
-    tempDirPrefix: 'echo-smoke-',
-    binScript,
-    configPath,
-    binArgs: ['--config', configPath, '--output-format', outputFormat, task],
-    tsconfigPath,
-  })
-  return stdout
-}
-
-describe('echo-agent keyless smoke (Headless through the real Loader tree)', () => {
-  it('runs the echo tool round-trip and exposes both events in stream-json', async () => {
-    const lines = (await runEcho('echo hello world', 'stream-json'))
-      .trimEnd().split('\n').map(line => JSON.parse(line) as Record<string, unknown>)
-    const events = lines.slice(0, -1).map(line => line['event'] as SessionEvent)
-    expect(events.some(event => event.type === 'tool/call' && event.data.name === 'echo')).toBe(true)
-    expect(JSON.stringify(events.find(event => event.type === 'tool/result'))).toContain('ECHO: HELLO WORLD')
-    expect(lines.at(-1)).toMatchObject({ type: 'result', success: true })
-  }, LOADER_SMOKE_TEST_TIMEOUT_MS)
-
-  it('prints the final canned reply for a direct one-shot task', async () => {
-    const stdout = await runEcho('just chatting')
-    expect(stdout).toContain('You said: "just chatting"')
-    expect(stdout).not.toContain('tool/call')
-  }, LOADER_SMOKE_TEST_TIMEOUT_MS)
-})

+ 1 - 1
examples/echo-agent/tests/fixtures/context/time-context/driver.ts → examples/headless-agent/tests/fixtures/time-context-driver.ts

@@ -1,5 +1,5 @@
 #!/usr/bin/env node
-/** Test driver that sends two turns through one headless Loader composition. */
+/** Test driver that sends two turns through one Headless Loader composition. */
 
 import { boot, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
 import { runOneShot } from '@deepseek-ai/dsh-cli-demo/src/cli.ts'

+ 22 - 0
examples/headless-agent/tests/fixtures/time-context-mock-llm.ts

@@ -0,0 +1,22 @@
+import type { Context } from 'cordis'
+import { LlmAdapter, type StreamChunk } from '@deepseek-ai/dsh-llm'
+
+/** Deterministic one-step adapter for the time-context Loader fixture. */
+class TimeContextMockAdapter extends LlmAdapter {
+  async * stream(): AsyncIterable<StreamChunk> {
+    const text = 'time context sampled'
+    yield { type: 'block-start', index: 0, blockType: 'text' }
+    yield { type: 'text-delta', index: 0, text }
+    yield { type: 'block-end', index: 0, block: { type: 'text', text } }
+    yield { type: 'usage', usage: { inputTokens: 1, outputTokens: 1 } }
+    yield { type: 'finish', reason: { kind: 'stop' } }
+  }
+}
+
+export const name = 'time-context-mock-llm'
+export const inject = ['llm']
+
+/** Register the test-only `time-context-mock` adapter. */
+export function apply(ctx: Context): void {
+  ctx.llm.registerAdapter(['time-context-mock'], new TimeContextMockAdapter())
+}

+ 4 - 4
examples/echo-agent/tests/fixtures/context/time-context/cordis.yml → examples/headless-agent/tests/fixtures/time-context.cordis.yml

@@ -1,6 +1,6 @@
 # Test-only composition: keep time-context opt-in while exercising its real Loader/app path.
-- id: mock-llm
-  name: '../../../../src/mock-llm.ts'
+- id: time-context-mock-llm
+  name: './time-context-mock-llm.ts'
 
 - id: bash
   name: '@deepseek-ai/dsh-bash-local'
@@ -11,8 +11,8 @@
 - id: cli-agent
   name: '@deepseek-ai/dsh-cli-demo'
   config:
-    provider: mock
-    model: mock-echo
+    provider: time-context-mock
+    model: time-context-mock
     persona: 'Test the time-context plugin.'
     persistenceRoot: './.sessions'
     workspaceContext: false

+ 2 - 1
knip.json

@@ -9,8 +9,9 @@
     },
     "examples": {
       "entry": [
-        "echo-agent/src/*.ts",
         "headless-agent/tests/fixtures/cli-mock-llm.ts",
+        "headless-agent/tests/fixtures/time-context-driver.ts",
+        "headless-agent/tests/fixtures/time-context-mock-llm.ts",
         "tui-agent/tests/fixtures/tui-scripted-llm.ts",
         "*/tests/**/*.e2e.ts",
         "*/tests/**/*.snapshot.ts"

+ 0 - 1
package.json

@@ -78,7 +78,6 @@
     "constraints": "tsx scripts/check-workspace-constraints.ts",
     "doc-sync": "pnpm run doc-typecheck && pnpm run verify-cordis-catalog && pnpm run verify-cordis-api && pnpm run verify-export-jsdoc && pnpm run verify-tool-catalog && pnpm run verify-config-catalog && pnpm run verify-persistence-catalog && pnpm run verify-doc-graphs && pnpm run verify-scoped-events && pnpm run verify-md-wrap && pnpm run verify-md-links && pnpm run verify-doc-refs && pnpm run verify-package-paths && pnpm run verify-package-readme-model-experience && pnpm run verify-mermaid && pnpm run verify-agent-note-classification && pnpm run verify-agent-note-format && pnpm run verify-type-equiv && pnpm run verify-translation-prompt && pnpm run verify-translation-pairing && pnpm run verify-doc-budgets && pnpm run verify-package-readme-limitations && pnpm run docs:check",
     "hygiene": "pnpm run knip && pnpm run publint && pnpm run constraints && pnpm run verify-cordis-config && pnpm run verify-node-next-types && pnpm run verify-runtime-closure",
-    "demo:echo": "node --expose-internals --import tsx packages/examples/cli-demo/src/bin.ts --config examples/echo-agent/cordis.yml",
     "demo:headless": "node --expose-internals --import tsx packages/examples/cli-demo/src/bin.ts --config examples/headless-agent/cordis.yml",
     "demo:tui": "node --expose-internals --import tsx packages/examples/tui-demo/src/bin.ts examples/tui-agent/cordis.yml",
     "demo:code-mode": "node scripts/demo-code-mode.mjs",

+ 2 - 2
packages/context/time-context/tests/time-context.e2e.ts

@@ -8,11 +8,11 @@ import { LOADER_SMOKE_TEST_TIMEOUT_MS, runLoaderSmoke } from '@deepseek-ai/dsh-l
 // Keep the Loader config under examples so both modes exercise the same deployable
 // topology: local fixture source plus bare plugins owned by the examples workspace.
 const driver = fileURLToPath(new URL(
-  '../../../../examples/echo-agent/tests/fixtures/context/time-context/driver.ts',
+  '../../../../examples/headless-agent/tests/fixtures/time-context-driver.ts',
   import.meta.url,
 ))
 const configPath = fileURLToPath(new URL(
-  '../../../../examples/echo-agent/tests/fixtures/context/time-context/cordis.yml',
+  '../../../../examples/headless-agent/tests/fixtures/time-context.cordis.yml',
   import.meta.url,
 ))
 const repoTsconfig = fileURLToPath(new URL('../../../../tsconfig.json', import.meta.url))

+ 0 - 10
scripts/gen-doc-graphs.ts

@@ -435,14 +435,6 @@ function stripYamlScalar(value: string): string {
 }
 
 const APP_EXAMPLES = [
-  {
-    id: 'echo',
-    rel: 'examples/echo-agent/composition.md',
-    title: 'Echo Agent App Composition',
-    label: 'examples/echo-agent',
-    config: 'examples/echo-agent/cordis.yml',
-    summary: 'The echo demo swaps in a local mock LLM and teaching echo tool, then loads the headless one-shot app package.',
-  },
   {
     id: 'tui',
     rel: 'examples/tui-agent/composition.md',
@@ -1013,7 +1005,6 @@ function renderDocs(): GraphDoc[] {
 function renderIndex(docs: GraphDoc[]): string {
   const labels: Record<string, string> = {
     'docs/capability-seams.md': 'capability seams and core services',
-    'examples/echo-agent/composition.md': 'echo-agent app composition',
     'examples/headless-agent/composition.md': 'headless-agent app composition',
     'examples/tui-agent/composition.md': 'tui-agent app composition',
     'examples/cordis-agent/composition.md': 'cordis-agent app composition',
@@ -1025,7 +1016,6 @@ function renderIndex(docs: GraphDoc[]): string {
   }
   const modes: Record<string, string> = {
     'docs/capability-seams.md': 'hybrid generated',
-    'examples/echo-agent/composition.md': 'hybrid generated',
     'examples/headless-agent/composition.md': 'hybrid generated',
     'examples/tui-agent/composition.md': 'hybrid generated',
     'examples/cordis-agent/composition.md': 'hybrid generated',

+ 2 - 46
scripts/run-gates.ts

@@ -5,9 +5,8 @@
  * independent commands can overlap and which commands wait for built artifacts.
  */
 import { spawn } from 'node:child_process'
-import { readdir, rm } from 'node:fs/promises'
 import { availableParallelism } from 'node:os'
-import { join, resolve } from 'node:path'
+import { resolve } from 'node:path'
 import { performance } from 'node:perf_hooks'
 
 type Mode =
@@ -210,7 +209,6 @@ function ciPrimaryGates(): Gate[] {
     pnpmScript('duplication', 'duplication'),
     coverageGate(),
     snapshotGate(),
-    demoSmokeGate({ needs: ['lint'] }),
     ...docSyncLeafGates(),
     pnpmScript('module-graph', 'verify-module-graph', { label: 'module graph' }),
     pnpmScript('knip', 'knip'),
@@ -229,18 +227,12 @@ function ciStaticGates(): Gate[] {
     pnpmScript('runtime-closure', 'verify-runtime-closure', { label: 'runtime closure' }),
     pnpmScript('constraints', 'constraints'),
     pnpmScript('cordis-config', 'verify-cordis-config', { label: 'Cordis config' }),
-    ...staticDemoSmokeGates(),
     ...docSyncLeafGates(),
     pnpmScript('module-graph', 'verify-module-graph', { label: 'module graph' }),
     pnpmScript('knip', 'knip'),
   ]
 }
 
-function staticDemoSmokeGates(): Gate[] {
-  // Native Windows session persistence is outside the gates-only support scope.
-  return process.platform === 'win32' ? [] : [demoSmokeGate()]
-}
-
 function ciArtifactGates(): Gate[] {
   return [
     pnpmScript('build', 'build'),
@@ -353,49 +345,13 @@ function docSyncLeafGates(options: {
   ]
 }
 
-function demoSmokeGate(options: { needs?: string[] } = {}): Gate {
-  const dependencyOptions = options.needs === undefined ? {} : { needs: options.needs }
-  return {
-    id: 'demo-smoke',
-    label: 'demo smoke',
-    displayCommand: 'pnpm run demo:echo --output-format stream-json -- "echo ci smoke"',
-    ...pnpmInvocation(['run', 'demo:echo', '--output-format', 'stream-json', '--', 'echo ci smoke']),
-    ...dependencyOptions,
-    verify: async (result) => {
-      const output = result.stdout + result.stderr
-      const sessionsRoot = join(root, '.sessions')
-      try {
-        if (!output.includes('"type":"tool/call"') || !output.includes('"name":"echo"')) {
-          throw new Error('demo smoke did not show the echo tool call.')
-        }
-        if (!output.includes('ECHO: CI SMOKE')) {
-          throw new Error('demo smoke did not show the echo tool result.')
-        }
-        const buckets = await readdir(sessionsRoot, { withFileTypes: true })
-        let found = false
-        for (const bucket of buckets) {
-          if (!bucket.isDirectory() || !bucket.name.startsWith('cwd-')) continue
-          const entries = await readdir(join(sessionsRoot, bucket.name))
-          if (entries.some(entry => /^main-session-.+\.jsonl$/.test(entry))) {
-            found = true
-            break
-          }
-        }
-        if (!found) throw new Error('demo smoke did not create a main-session JSONL log in a cwd bucket.')
-      } finally {
-        await rm(sessionsRoot, { recursive: true, force: true })
-      }
-    },
-  }
-}
-
 function builtBinSmokeGate(): Gate {
   return pnpmExec('built-bin-smoke', [
     'vitest',
     'run',
     '--config',
     'vitest.e2e.config.ts',
-    'examples/echo-agent/tests/echo.e2e.ts',
+    'examples/headless-agent/tests/keyless-smoke.e2e.ts',
     'examples/tui-agent/tests/tui-keyless-smoke.e2e.ts',
     'packages/examples/cli-demo/tests/built-bin.e2e.ts',
     'packages/examples/acp-demo/tests/built-bin.e2e.ts',