Parcourir la source

docs: refresh top-level README + add dsh-arch-diagram skill

Replaces the 20-line stub with a bilingual README pair covering:
- getting started (`pnpm run demo:repl` + Node ^22.19 || ≥24 + pnpm 11.7)
- editor integration (Zed / VS Code / Cursor over ACP)
- programmatic embedding via `@deepseek-ai/dsh-app-boot` (with the
  two failure paths of `boot()` vs `installFailLoud` spelled out)
- writing a plugin (`echo-tool` grounded in `examples/echo-agent`, with
  the runnable command `pnpm run demo:echo`)
- Packages table grouped by family, including `session-query`,
  `context`, and Support (with `invariants` called out as a runtime
  diagnostic mounted by `dsh-agent-core`, not test-only)
- deep-dive links, community, license

Bilingual pairing: English and Chinese sides share byte-identical code
blocks and mirroring link ordinals; language-asymmetric community
channels (Discord/X in EN, WeCom in ZH) sit inside HTML `<a href>`
tags that the pairing gate's structural signature excludes by design.
ZH side follows `docs/i18n/terminology.md` — first `agent` occurrence
annotated as `agent(智能体)`, plain `agent` thereafter.

Ships an in-repo skill at `.agents/skills/dsh-arch-diagram/` that owns
the two architecture PNGs (`assets/arch-{en,zh}.png`). HTML templates
+ shared CSS + a `render.sh` that renders via Chrome headless. The
renderer is portable (auto-detects Chrome/Chromium on macOS + Linux,
uses `--no-sandbox` under root for container envs, discovers the local
http.server port from Python's own startup line so `lsof` isn't
required). The 12-card capability row uses `flex: 0 0 auto` so
adjacent card backgrounds cannot clip descriptions; layout tuned to
1560px page / 96% row-width / 1820×580 render viewport.

Consolidates the four review-response commits from the initial round
of ds-review-bot feedback; each review round is documented in a
top-level PR comment for traceability.
NI0317 il y a 3 mois
Parent
commit
069e0ecdc9

+ 158 - 0
.agents/skills/dsh-arch-diagram/SKILL.md

@@ -0,0 +1,158 @@
+---
+name: dsh-arch-diagram
+description: Regenerate the DeepSeek Harness "System overview" architecture PNGs (English + Chinese) that the top-level README embeds. Reflects the current state of packages/* and docs/architecture.md. Use when the codebase adds/removes/renames services and the README diagram must be refreshed.
+---
+
+# dsh-arch-diagram
+
+Produces `assets/arch-en.png` and `assets/arch-zh.png` in this repo — the two hero images embedded at the top of `README.md` and `README.zh.md`.
+
+The pipeline is HTML + Chrome headless, so text quality, layout, and connector geometry are **deterministic** — every rerun produces the same output regardless of model.
+
+Aesthetic is locked to the DeepSeek brand: light blue gradient background, brand-blue Cordis bar, sans-serif everywhere, no serif / no italic / no hand-drawn feel.
+
+---
+
+## When to use
+
+- User asks to "regenerate" or "refresh" the Harness architecture diagram
+- User points out `packages/` has changed (new services, renames) and the README diagram is stale
+- User just added a new `packages/<family>/` or a new `ctx.*` service and wants the diagram to reflect it
+
+## When NOT to use
+
+- User wants a different diagram (Code Mode, Workflow fanout, agent lifecycle) — those belong in `docs/` and need their own skill
+- User wants a different visual aesthetic (dark mode, hand-drawn, editorial-serif) — this skill is locked to DeepSeek brand
+
+---
+
+## Workflow
+
+### 1. Enumerate current services from the repo
+
+The diagram is grounded in two lists that live in the docs:
+
+- **Default Services** — from `packages/core/*` and `docs/architecture.md`'s "Default Services" table. As of last refresh: `ctx.sessions`, `ctx.systemPrompt`, `ctx.tools`, `ctx.agents`, `ctx.agentLoop`.
+- **Capability Services** — from the non-core capability packages and `docs/architecture.md`'s "Capability Services" table. As of last refresh: `ctx.llm`, `ctx.bash`, `ctx.sandbox`, `ctx.codeRuntime`, `ctx.fs`, `ctx.skills`, `ctx.web`, `ctx.compact`, `ctx.subagents`, `ctx.workflows`, `ctx.sessionPersistence`, `ctx.sessionQuery`.
+
+**Do this**:
+
+1. Read `docs/architecture.md`
+2. Extract the two `ctx.*` tables verbatim
+3. Cross-check against `packages/`: services live under `packages/core/*` (defaults) or under `packages/<family>/<package>/` (capabilities). The inner package dir mirrors the npm name without the `@deepseek-ai/dsh-` prefix — e.g. `packages/session-query/session-query/` publishes `@deepseek-ai/dsh-session-query`. Never assume the inner dir carries a `dsh-` prefix.
+
+### 2. Diff against the current HTML templates
+
+Read `harness-arch-en.html` and `harness-arch-zh.html` in this skill directory. Pull out the currently-rendered `ctx.*` names. Report the diff:
+
+```
+Default services: no change
+Capability services: + ctx.<new>, − ctx.<removed>, ↻ ctx.<renamed>
+```
+
+### 3. Update the templates
+
+If there are changes, edit both HTML files in place. Each card is one line:
+
+```html
+<div class="card"><span class="name">ctx.something</span><span class="desc">short description</span></div>
+```
+
+For a **new** service:
+- Description is **short** — 2–4 words (EN), 3–6 chars (ZH)
+- Ground the description in what the package's README or its `ctx.<name>.register()` **actually** does. Do NOT paraphrase from an abstract or invent capabilities the code doesn't have.
+- Add the card in **both** languages, in docs order.
+
+For a **removed** service: delete the card in both files.
+
+For a **renamed** service: update the `.name` span in both files.
+
+**Do not touch the layout**. Rows are:
+- Top row (`row top`): exactly 5 default-service cards
+- Bottom row (`row bottom`): 12 capability-service cards
+
+If the capability count grows past ~13, the row gets visually tight. Stop and ask the user before shrinking fonts or wrapping to two rows.
+
+### 4. Render to PNG
+
+```bash
+bash .agents/skills/dsh-arch-diagram/render.sh
+```
+
+Default output: `<repo>/assets/arch-en.png` and `<repo>/assets/arch-zh.png` — the paths that `README.md` and `README.zh.md` already reference.
+
+Pass an alternate directory as `$1` to write elsewhere. `CHROME` and `PORT` env vars override the browser path and http.server port.
+
+The script:
+- Spins up a temporary `python3 -m http.server` on `127.0.0.1` (needed so Google Fonts CDN loads reliably in Chrome headless)
+- Runs Chrome headless twice at `--force-device-scale-factor=2 --window-size=1536,580`
+- Writes two 3072×1160 PNGs (~600 KB each)
+- Tears down the server
+
+### 5. Verify by eye — mandatory, do not skip
+
+After rendering, **open each PNG and visually check every item** in this list. Do not report the diagram as done without going through it.
+
+- [ ] Top-row card count matches the Default Services list you extracted in §1, every name rendered in full (no truncation on the longest, e.g. `ctx.systemPrompt` / `ctx.agentLoop`)
+- [ ] Bottom-row card count matches the Capability Services list you extracted in §1, every name in full (especially the longest, e.g. `ctx.sessionPersistence`)
+- [ ] Every card has a description underneath, and the description matches what the code does (not made up)
+- [ ] Bar reads `Cordis · microkernel (vendored)` (EN) / `Cordis · 微内核 (vendored)` (ZH)
+- [ ] Number of vertical connector lines equals (top-row cards + bottom-row cards) from §1. All straight vertical, all parallel, each reaching the horizontal center of its card
+- [ ] `cordis.yml` sidebar visible on the right; dashed arrow points left into the bar
+- [ ] `deployment leaf` / `部署清单` and `picks which plugins load` / `决定哪些插件加载` are readable and NOT crossed through by any connector line
+- [ ] Chinese descriptions render as CJK glyphs, not `□` tofu boxes (means fonts loaded)
+- [ ] No large empty gradient area at the bottom of the image — if there is, tune `--window-size` in `render.sh`
+
+If any check fails: fix the CSS or template, re-run `render.sh`, re-check. Do not report "done" on first render without visually confirming.
+
+---
+
+## Design system (locked — do not modify without explicit user request)
+
+Colors:
+- Background: `linear-gradient(135deg, #ffffff 0%, #e8effc 100%)`
+- Brand blue (Cordis bar + connectors): `#4a6ef5`
+- Ink text: `#1a1a1a`
+- Muted text: `#8a8f9c`
+- Card border: `#dde3ef`
+- Card fill: `#ffffff`
+
+Typography (**sans-serif only** — never serif, never italic):
+- English title & body: **Inter** (Google Fonts)
+- Chinese title & body: **Noto Sans SC** (Google Fonts) with `PingFang SC` local fallback
+- Code labels (`ctx.*`, `cordis.yml`, `vendored`): **JetBrains Mono** (Google Fonts)
+
+Layout:
+- `.page` max-width 1560 px, centered
+- `.bus-row`, `.row.top`, `.row.bottom` all 96% width, centered
+- Top row: `flex: 1` on each card (equal widths)
+- Bottom row: `justify-content: space-between` + `flex: 0 0 auto` on each card — cards keep their intrinsic (nowrap) width and adjacent card backgrounds cannot clip a description
+- Bus: `#4a6ef5` filled, 60 px tall, 8 px radius
+- `cordis.yml` sidebar `position: absolute` at `left: calc(100% + 20px)` of `.bus-row`, width 130 px
+- All connectors: CSS `::before` / `::after` pseudo-elements, 2 px wide, 40 px tall, `#4a6ef5`, centered via `left: 50%; transform: translateX(-50%)` — this is what guarantees pixel-perfect vertical parallel lines regardless of card content
+
+Rendering:
+- Chrome headless `--force-device-scale-factor=2`
+- `--window-size=1820,580` → output is 3640×1160 (aspect ~3.14:1, wider than square-ish so a 12-card capability row fits without truncation)
+- Local http.server on `127.0.0.1` so CDN fonts load cleanly
+
+---
+
+## Files in this skill
+
+- `SKILL.md` — this file
+- `harness-arch.css` — shared design system (colors, fonts, layout, connectors)
+- `harness-arch-en.html` — English template
+- `harness-arch-zh.html` — Chinese template
+- `render.sh` — Chrome headless renderer
+
+Templates are self-contained. Fonts load from Google Fonts CDN; no local font files.
+
+---
+
+## Rules I keep breaking (and shouldn't)
+
+1. **Verify the output by looking at it.** Don't report "done" and move on — actually inspect each PNG and check every item in §5.
+2. **Ground service descriptions in the code, not the docs' abstract, not the marketing copy.** If unsure what a package does, read its `src/` or the `ctx.<name>.register()` block.
+3. **Don't touch layout unless asked.** 96% row/bar width, 40 px connector height, and 60 px bar height are all tuned. Card counts grow one at a time; once the bottom row starts to visibly overflow again (adjacent card backgrounds clipping a description, or the `cordis.yml` sidebar falling outside the render viewport), stop and ask before shrinking fonts, widening the viewport further, or wrapping to two rows.
+4. **Never introduce a serif font or italic.** Not for titles, not for annotations, not "to make it feel editorial." This diagram is DeepSeek brand: sans-serif, upright, only.

+ 66 - 0
.agents/skills/dsh-arch-diagram/harness-arch-en.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=1536, initial-scale=1.0">
+  <title>DeepSeek Harness · Architecture</title>
+  <link rel="stylesheet" href="harness-arch.css">
+</head>
+<body>
+  <div class="page">
+    <p class="eyebrow">ARCHITECTURE</p>
+    <h1>System overview</h1>
+
+    <div class="diagram">
+      <p class="section-label top">DEFAULT SERVICES</p>
+
+      <div class="row top">
+        <div class="card"><span class="name">ctx.sessions</span><span class="desc">event-sourced log</span></div>
+        <div class="card"><span class="name">ctx.systemPrompt</span><span class="desc">prompt assembly</span></div>
+        <div class="card"><span class="name">ctx.tools</span><span class="desc">tool registry &amp; pipeline</span></div>
+        <div class="card"><span class="name">ctx.agents</span><span class="desc">agent handles &amp; events</span></div>
+        <div class="card"><span class="name">ctx.agentLoop</span><span class="desc">ReAct control loop</span></div>
+      </div>
+
+      <div class="bus-row">
+        <div class="bus">
+          <span class="core">Cordis</span>
+          <span class="dot">·</span>
+          <span class="core">microkernel</span>
+          <span class="vendored">(vendored)</span>
+        </div>
+        <div class="yml-side">
+          <div class="yml-arrow">
+            <svg viewBox="0 0 30 12" width="30" height="12" xmlns="http://www.w3.org/2000/svg">
+              <line x1="30" y1="6" x2="8" y2="6" stroke="#8a8f9c" stroke-width="1.2" stroke-dasharray="3 3"/>
+              <polyline points="8,3 2,6 8,9" fill="none" stroke="#8a8f9c" stroke-width="1.2" stroke-linejoin="round" stroke-linecap="round"/>
+            </svg>
+          </div>
+          <div class="yml-box">
+            <div class="file">cordis.yml</div>
+            <div class="sub">deployment leaf</div>
+          </div>
+          <div class="yml-note">picks which plugins load</div>
+        </div>
+      </div>
+
+      <div class="row bottom">
+        <div class="card"><span class="name">ctx.llm</span><span class="desc">LLM provider adapter</span></div>
+        <div class="card"><span class="name">ctx.bash</span><span class="desc">shell execution</span></div>
+        <div class="card"><span class="name">ctx.sandbox</span><span class="desc">process confinement</span></div>
+        <div class="card"><span class="name">ctx.codeRuntime</span><span class="desc">JS worker runtime</span></div>
+        <div class="card"><span class="name">ctx.fs</span><span class="desc">filesystem + policy</span></div>
+        <div class="card"><span class="name">ctx.skills</span><span class="desc">reusable skills</span></div>
+        <div class="card"><span class="name">ctx.web</span><span class="desc">search &amp; fetch</span></div>
+        <div class="card"><span class="name">ctx.compact</span><span class="desc">context compression</span></div>
+        <div class="card"><span class="name">ctx.subagents</span><span class="desc">spawn / fork / ACP</span></div>
+        <div class="card"><span class="name">ctx.workflows</span><span class="desc">dynamic orchestration</span></div>
+        <div class="card"><span class="name">ctx.sessionPersistence</span><span class="desc">JSONL / SQLite</span></div>
+        <div class="card"><span class="name">ctx.sessionQuery</span><span class="desc">unified log reads</span></div>
+      </div>
+
+      <p class="section-label bottom">CAPABILITY SERVICES</p>
+    </div>
+  </div>
+</body>
+</html>

+ 66 - 0
.agents/skills/dsh-arch-diagram/harness-arch-zh.html

@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+  <meta charset="UTF-8">
+  <meta name="viewport" content="width=1536, initial-scale=1.0">
+  <title>DeepSeek Harness · 架构</title>
+  <link rel="stylesheet" href="harness-arch.css">
+</head>
+<body>
+  <div class="page">
+    <p class="eyebrow cn">架 构</p>
+    <h1 class="cn">系统一览</h1>
+
+    <div class="diagram">
+      <p class="section-label top cn">默 认 服 务</p>
+
+      <div class="row top">
+        <div class="card"><span class="name">ctx.sessions</span><span class="desc cn">事件溯源日志</span></div>
+        <div class="card"><span class="name">ctx.systemPrompt</span><span class="desc cn">系统提示词组装</span></div>
+        <div class="card"><span class="name">ctx.tools</span><span class="desc cn">工具注册与执行</span></div>
+        <div class="card"><span class="name">ctx.agents</span><span class="desc cn">Agent 实例与事件</span></div>
+        <div class="card"><span class="name">ctx.agentLoop</span><span class="desc cn">ReAct 控制循环</span></div>
+      </div>
+
+      <div class="bus-row">
+        <div class="bus cn">
+          <span class="core">Cordis</span>
+          <span class="dot">·</span>
+          <span class="core">微内核</span>
+          <span class="vendored">(vendored)</span>
+        </div>
+        <div class="yml-side">
+          <div class="yml-arrow">
+            <svg viewBox="0 0 30 12" width="30" height="12" xmlns="http://www.w3.org/2000/svg">
+              <line x1="30" y1="6" x2="8" y2="6" stroke="#8a8f9c" stroke-width="1.2" stroke-dasharray="3 3"/>
+              <polyline points="8,3 2,6 8,9" fill="none" stroke="#8a8f9c" stroke-width="1.2" stroke-linejoin="round" stroke-linecap="round"/>
+            </svg>
+          </div>
+          <div class="yml-box">
+            <div class="file">cordis.yml</div>
+            <div class="sub cn">部署清单</div>
+          </div>
+          <div class="yml-note cn">决定哪些插件加载</div>
+        </div>
+      </div>
+
+      <div class="row bottom">
+        <div class="card"><span class="name">ctx.llm</span><span class="desc cn">模型适配层</span></div>
+        <div class="card"><span class="name">ctx.bash</span><span class="desc cn">命令行执行</span></div>
+        <div class="card"><span class="name">ctx.sandbox</span><span class="desc cn">进程隔离</span></div>
+        <div class="card"><span class="name">ctx.codeRuntime</span><span class="desc cn">JS 运行时</span></div>
+        <div class="card"><span class="name">ctx.fs</span><span class="desc cn">文件读写</span></div>
+        <div class="card"><span class="name">ctx.skills</span><span class="desc cn">可复用技能</span></div>
+        <div class="card"><span class="name">ctx.web</span><span class="desc cn">网页搜索抓取</span></div>
+        <div class="card"><span class="name">ctx.compact</span><span class="desc cn">上下文压缩</span></div>
+        <div class="card"><span class="name">ctx.subagents</span><span class="desc cn">子智能体</span></div>
+        <div class="card"><span class="name">ctx.workflows</span><span class="desc cn">动态编排</span></div>
+        <div class="card"><span class="name">ctx.sessionPersistence</span><span class="desc cn">会话持久化</span></div>
+        <div class="card"><span class="name">ctx.sessionQuery</span><span class="desc cn">会话日志查询</span></div>
+      </div>
+
+      <p class="section-label bottom cn">能 力 服 务</p>
+    </div>
+  </div>
+</body>
+</html>

+ 220 - 0
.agents/skills/dsh-arch-diagram/harness-arch.css

@@ -0,0 +1,220 @@
+/* DeepSeek brand — bone-white + brand-blue, all sans-serif, no italic, no serif. */
+
+@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Noto+Sans+SC:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap');
+
+:root {
+  --bg-top:      #ffffff;
+  --bg-bot:      #e8effc;
+  --ink:         #1a1a1a;
+  --muted:       #8a8f9c;
+  --card-bd:     #dde3ef;
+  --card-bg:     #ffffff;
+  --brand:       #4a6ef5;
+  --brand-soft:  #dbe4fe;
+
+  --sans:  'Inter', 'Noto Sans SC', 'PingFang SC', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
+  --cn:    'Noto Sans SC', 'PingFang SC', 'Inter', -apple-system, sans-serif;
+  --mono:  'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
+}
+
+*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
+
+body {
+  font-family: var(--sans);
+  color: var(--ink);
+  background: linear-gradient(135deg, var(--bg-top) 0%, var(--bg-bot) 100%);
+  padding: 40px 64px 32px;
+  -webkit-font-smoothing: antialiased;
+  font-feature-settings: "kern" 1, "liga" 1, "cv02" 1, "cv11" 1;
+}
+
+.page {
+  max-width: 1560px;
+  margin: 0 auto;
+}
+
+/* ── header ─────────────────────────────────────────── */
+.eyebrow {
+  font-family: var(--sans);
+  font-size: 12px;
+  font-weight: 500;
+  letter-spacing: 0.22em;
+  color: var(--muted);
+  text-transform: uppercase;
+  margin-bottom: 10px;
+}
+.eyebrow.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; }
+
+h1 {
+  font-family: var(--sans);
+  font-size: 40px;
+  font-weight: 600;
+  letter-spacing: -0.02em;
+  line-height: 1.15;
+  color: var(--ink);
+  margin-bottom: 88px;
+}
+h1.cn { font-family: var(--cn); letter-spacing: 0.02em; font-weight: 600; }
+
+/* ── diagram frame ──────────────────────────────────── */
+.diagram { position: relative; }
+
+.section-label {
+  font-family: var(--sans);
+  font-size: 11px;
+  font-weight: 500;
+  letter-spacing: 0.22em;
+  color: var(--muted);
+  text-transform: uppercase;
+  text-align: center;
+  margin-bottom: 20px;
+}
+.section-label.cn { font-family: var(--cn); letter-spacing: 0.4em; text-transform: none; font-size: 12px; }
+.section-label.bottom { margin: 20px 0 0; }
+
+/* ── card rows ──────────────────────────────────────── */
+.row {
+  display: flex;
+  gap: 12px;
+  justify-content: center;
+  width: 96%;
+  margin: 0 auto;
+  position: relative;
+}
+.row.top .card { flex: 1; }
+.row.bottom {
+  gap: 0;
+  justify-content: space-between;
+}
+/* flex: 0 0 auto so cards keep their intrinsic (nowrap) width and
+   neighbouring card backgrounds cannot clip a description. */
+.row.bottom .card { flex: 0 0 auto; }
+
+.card {
+  background: var(--card-bg);
+  border: 1px solid var(--card-bd);
+  border-radius: 6px;
+  padding: 14px 10px;
+  text-align: center;
+  min-width: 0;
+  position: relative;
+}
+.card .name {
+  font-family: var(--mono);
+  font-size: 13px;
+  font-weight: 500;
+  color: var(--ink);
+  line-height: 1.2;
+  white-space: nowrap;
+  display: block;
+}
+.card .desc {
+  font-family: var(--sans);
+  font-size: 11px;
+  font-weight: 400;
+  color: var(--muted);
+  margin-top: 4px;
+  line-height: 1.3;
+  min-height: 28px;
+  white-space: nowrap;
+}
+.card .desc.cn { font-family: var(--cn); }
+.row.bottom .card { padding: 10px 6px; }
+.row.bottom .card .name { font-size: 10px; }
+.row.bottom .card .desc { font-size: 9px; min-height: 22px; }
+.row.bottom .card .desc.cn { font-size: 10px; }
+
+/* connectors — pure CSS, guaranteed vertical & parallel */
+.row.top    .card::after,
+.row.bottom .card::before {
+  content: '';
+  position: absolute;
+  left: 50%;
+  transform: translateX(-50%);
+  width: 2px;
+  background: var(--brand);
+}
+.row.top    .card::after  { top: 100%; height: 40px; }
+.row.bottom .card::before { bottom: 100%; height: 40px; }
+
+/* ── bus row (Cordis) ───────────────────────────────── */
+.bus-row {
+  position: relative;
+  width: 96%;
+  margin: 40px auto;
+}
+.bus {
+  height: 60px;
+  background: var(--brand);
+  color: #ffffff;
+  border-radius: 8px;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  font-family: var(--sans);
+  font-size: 18px;
+  font-weight: 500;
+  letter-spacing: 0.01em;
+}
+.bus .dot { padding: 0 12px; opacity: 0.75; }
+.bus .vendored {
+  font-family: var(--mono);
+  font-size: 15px;
+  font-weight: 400;
+  opacity: 0.8;
+  margin-left: 8px;
+}
+.bus.cn .core { font-family: var(--cn); }
+
+/* ── cordis.yml side box (positioned outside bus width) ─ */
+.yml-side {
+  position: absolute;
+  left: calc(100% + 20px);
+  top: 50%;
+  transform: translateY(-50%);
+  width: 130px;
+  display: flex;
+  flex-direction: column;
+  align-items: flex-start;
+}
+.yml-arrow {
+  position: absolute;
+  left: -30px;
+  top: 50%;
+  transform: translateY(-50%);
+  width: 30px;
+  height: 12px;
+}
+.yml-arrow svg { display: block; }
+.yml-box {
+  width: 100%;
+  background: var(--card-bg);
+  border: 1px solid var(--card-bd);
+  border-radius: 6px;
+  padding: 12px 10px;
+  text-align: center;
+}
+.yml-box .file {
+  font-family: var(--mono);
+  font-size: 13px;
+  font-weight: 500;
+  color: var(--ink);
+}
+.yml-box .sub {
+  font-family: var(--sans);
+  font-size: 10px;
+  color: var(--muted);
+  margin-top: 4px;
+  line-height: 1.3;
+}
+.yml-box .sub.cn { font-family: var(--cn); letter-spacing: 0.05em; }
+.yml-note {
+  font-family: var(--sans);
+  font-size: 10px;
+  color: var(--muted);
+  margin-top: 10px;
+  width: 100%;
+  text-align: center;
+  line-height: 1.4;
+}
+.yml-note.cn { font-family: var(--cn); letter-spacing: 0.05em; }

+ 97 - 0
.agents/skills/dsh-arch-diagram/render.sh

@@ -0,0 +1,97 @@
+#!/bin/bash
+# render.sh — Chrome headless renderer for the DeepSeek Harness architecture diagram.
+#
+# Writes arch-en.png and arch-zh.png (3072×1160, ~600 KB each) to the given output
+# directory. Default is <repo>/assets/, which is where the README image references
+# resolve.
+#
+# Usage:
+#   bash render.sh                    # writes to <repo>/assets/
+#   bash render.sh /some/other/dir    # writes there instead
+#
+# Env overrides:
+#   CHROME=/path/to/Chrome       # non-standard Chrome location
+#   PORT=<n>                     # override the local http.server port
+
+set -e
+
+SKILL_DIR="$(cd "$(dirname "$0")" && pwd)"
+REPO_ROOT="$(cd "$SKILL_DIR/../../.." && pwd)"
+OUT_DIR="${1:-$REPO_ROOT/assets}"
+BIND_PORT="${PORT:-0}"   # 0 → kernel picks a free port
+SERVER_LOG="$(mktemp -t dsh-arch-diagram-server.XXXXXX.log)"
+
+# Locate a Chrome / Chromium binary. Honour $CHROME if set; otherwise probe
+# common per-platform paths so `bash render.sh` works on macOS + Linux out
+# of the box.
+if [ -z "$CHROME" ]; then
+  for candidate in \
+    "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
+    "/Applications/Chromium.app/Contents/MacOS/Chromium" \
+    "$(command -v google-chrome 2>/dev/null || true)" \
+    "$(command -v google-chrome-stable 2>/dev/null || true)" \
+    "$(command -v chromium 2>/dev/null || true)" \
+    "$(command -v chromium-browser 2>/dev/null || true)"; do
+    if [ -n "$candidate" ] && [ -x "$candidate" ]; then
+      CHROME="$candidate"; break
+    fi
+  done
+fi
+
+if [ -z "$CHROME" ] || [ ! -x "$CHROME" ]; then
+  echo "No Chrome / Chromium binary found." >&2
+  echo "Tried: macOS default, google-chrome, google-chrome-stable, chromium, chromium-browser." >&2
+  echo "Set CHROME=/path/to/binary and rerun." >&2
+  exit 1
+fi
+
+mkdir -p "$OUT_DIR"
+
+python3 -u -m http.server "$BIND_PORT" --bind 127.0.0.1 --directory "$SKILL_DIR" \
+  >"$SERVER_LOG" 2>&1 &
+SERVER_PID=$!
+cleanup() { kill "$SERVER_PID" 2>/dev/null; rm -f "$SERVER_LOG"; }
+trap cleanup EXIT INT TERM
+
+# Discover the actual bound port from Python's own startup line
+# ("Serving HTTP on 127.0.0.1 port <N> ..."). Works whether the kernel
+# picked it or PORT was set explicitly; no external `lsof` needed.
+PORT=""
+for _ in $(seq 1 40); do
+  PORT=$(awk '/Serving HTTP on/ {print $6; exit}' "$SERVER_LOG" 2>/dev/null || true)
+  [ -n "$PORT" ] && break
+  # Bail early if the server died (e.g. explicit PORT already in use).
+  kill -0 "$SERVER_PID" 2>/dev/null || break
+  sleep 0.05
+done
+if [ -z "$PORT" ]; then
+  echo "Failed to detect local server port. Server log:" >&2
+  cat "$SERVER_LOG" >&2 || true
+  exit 1
+fi
+
+# Chrome/Chromium refuses to run as root without --no-sandbox. Rendering
+# a local static HTML doc under a headless browser doesn't need Chrome's
+# own sandbox, so passing the flag when EUID is 0 makes the script work
+# in Codex/CI container environments that default to root.
+CHROME_EXTRA_ARGS=()
+if [ "$(id -u)" = "0" ]; then
+  CHROME_EXTRA_ARGS+=(--no-sandbox)
+fi
+
+for lang in en zh; do
+  out="$OUT_DIR/arch-$lang.png"
+  "$CHROME" \
+    "${CHROME_EXTRA_ARGS[@]}" \
+    --headless=new \
+    --disable-gpu \
+    --hide-scrollbars \
+    --force-device-scale-factor=2 \
+    --window-size=1820,580 \
+    --virtual-time-budget=8000 \
+    --screenshot="$out" \
+    "http://127.0.0.1:$PORT/harness-arch-$lang.html" \
+    2>/dev/null
+  size=$(du -h "$out" | awk '{print $1}')
+  echo "[$lang] wrote $out ($size)"
+done

+ 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: 53dd3896eb15800125673e7c44f7de02daca9376
-README.zh.md: ab826f62658248249ec18c57b35c0065c0f909d1
+README.md: 3380558e6c956cdc7f1b748b9ea8d3d455f781db
+README.zh.md: 9f415af0a6582c455fdb8e8bb5400dd28b42a161

+ 229 - 9
README.md

@@ -1,20 +1,240 @@
-# DeepSeek Harness
+<!--
+  README.md — English side of the pair.
+  If you edit this, update README.zh.md in the same commit, then run:
+    pnpm run verify-translation-pairing --write
+  to refresh README.i18n.yaml.
+-->
+
+<div align="center">
+
+<!-- TODO: replace with wordmark / logo asset once designed -->
+<h1>DeepSeek Harness</h1>
+
+**The plugin-first agent SDK. Every capability &mdash; including the loop &mdash; is a plugin.**
+
+<p>
+  <a href="LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue" alt="license"></a>
+  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%E2%89%A522.19-3c873a" alt="node"></a>
+  <a href="https://pnpm.io"><img src="https://img.shields.io/badge/pnpm-workspace-f69220" alt="pnpm"></a>
+  <a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/TypeScript-strict-3178c6" alt="typescript"></a>
+  <a href="https://agentclientprotocol.com"><img src="https://img.shields.io/badge/protocol-ACP-4a6ef5" alt="ACP"></a>
+  <a href="https://discord.gg/4nyuPgFzdE"><img src="https://img.shields.io/badge/Discord-join-5865F2?logo=discord&logoColor=white" alt="Discord"></a>
+  <a href="https://x.com/Deepseekharness"><img src="https://img.shields.io/badge/X-@Deepseekharness-000000?logo=x&logoColor=white" alt="X"></a>
+</p>
 
 English | [中文](README.zh.md)
 
-The **DeepSeek Harness SDK** is a plugin-based SDK for building agent harnesses.
+<!-- TODO: deepseek.com/harness-sdk placeholder URLs — swap for the final canonical URLs when ready. -->
+[Docs](https://deepseek.com/harness-sdk/docs) &nbsp;·&nbsp; [Landing page](https://deepseek.com/harness-sdk) &nbsp;·&nbsp; [Community](#community)
+
+</div>
+
+<br>
+
+<p align="center">
+  <img src="./assets/arch-en.png" alt="DeepSeek Harness — System overview" width="100%">
+</p>
+
+## What is this?
+
+DeepSeek Harness is a TypeScript SDK for building AI agents on top of the [Cordis](https://github.com/cordiverse/cordis) microkernel. **Every service, including the ReAct loop, is a plugin registered through `ctx.*`.** A batteries-included service registry ships in the box — LLM adapters, sandboxed execution, filesystem with policy, web search, sub-agents, dynamic workflows, session persistence, and more — and a `cordis.yml` at your project root chooses which get loaded. You can replace any of them, add your own, or leave the shipped defaults alone.
 
-## Development
+## Getting started
 
-This monorepo is built on the [Cordis](https://github.com/cordiverse/cordis) framework (vendored as source under `vendor/`), microkernel-style: everything is a plugin.
+**New project** (one-command scaffold):
 
 ```sh
+npm create @deepseek-ai/harness   # coming soon, not yet on npm
+```
+
+**From source** (read the code / run demos / contribute):
+
+```sh
+git clone https://github.com/deepseek-harness/deepseek-harness.git
+cd deepseek-harness
 pnpm install
-pnpm run test          # vitest
-pnpm run demo:repl     # REPL agent demo (needs DEEPSEEK_API_KEY)
-pnpm run demo:acp      # ACP server agent demo (needs DEEPSEEK_API_KEY)
+export DEEPSEEK_API_KEY=sk-...    # optional — omit and use pnpm run demo:echo (mock, no key)
+pnpm run demo:repl
+```
+
+Requires **Node `^22.19 || ≥24`** and **pnpm ≥ 11.7** (Node engine and pnpm pinned in `package.json`; `corepack enable` picks up the exact pnpm version). Node 23 is not on the support matrix.
+
+**Heads up:** `demo:repl` runs real `read` / `write` / `edit` file tools and `bash` in your current working directory — best run from a scratch dir or a git-clean project so you can review the changes.
+
+## Use it in your editor
+
+Harness ships an [Agent Client Protocol (ACP)](https://agentclientprotocol.com) server. ACP lets an editor drive an agent from its sidebar; [Zed](https://zed.dev) supports it natively.
+
+The ACP server command (from your local clone):
+
+```sh
+pnpm run demo:acp
 ```
 
-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/).
+Zed side — Zed's `settings.json` (Cmd-Shift-P → "zed: open settings") takes an `agent_servers` entry:
+
+```json
+{
+  "agent_servers": {
+    "DeepSeek Harness": {
+      "command": "pnpm",
+      "args": ["--dir", "/path/to/deepseek-harness", "run", "demo:acp"],
+      "env": { "DEEPSEEK_API_KEY": "sk-..." }
+    }
+  }
+}
+```
+
+`--dir` points at your local clone. Zed launches the agent as a subprocess; each Zed session maps to its own agent instance, with chat in the sidebar and tool calls (arguments, results, file diffs) rendered inline in the editor. Configuration details in [`examples/acp-agent`](./examples/acp-agent) (including the snapshot-tested surface).
+
+**VS Code / Cursor** — install an ACP client extension for either editor, such as [ACP Client](https://marketplace.visualstudio.com/items?itemName=formulahendry.acp-client) (`formulahendry.acp-client`) or [ACP Pro](https://marketplace.visualstudio.com/items?itemName=duclvz.acp-pro) (`duclvz.acp-pro`), and point a custom agent at `pnpm run demo:acp`.
+
+**Other ACP clients** — same launch. Feature-by-feature support matrix in [`packages/ui/acp/acp-feature-support.md`](./packages/ui/acp/acp-feature-support.md).
+
+## Embed it in your own app
+
+Harness bootstraps from a `cordis.yml` via [`@deepseek-ai/dsh-app-boot`](./packages/ui/app-boot). For library-style integration into your own Node.js service, the same boot helpers apply:
+
+```ts
+// my-app.ts
+import {
+  boot,
+  installFailLoud,
+  loadEnv,
+  resolveConfigPath,
+} from '@deepseek-ai/dsh-app-boot'
+
+installFailLoud('my-app')
+loadEnv('my-app')
+
+const ctx = await boot('my-app', resolveConfigPath('./cordis.yml', undefined))
+// ctx is the Cordis root Context; every service you mount in cordis.yml
+// is reachable via ctx.* (ctx.agents, ctx.sessions, ctx.tools, …).
+// The app plugins loaded from cordis.yml keep the process alive on their own
+// (stdio agents hold stdin; the ACP agent holds an RPC connection).
+// To shut down programmatically, call `await ctx.fiber.dispose()`.
+```
+
+`boot()` returns once the whole plugin tree has settled. Two separate failure paths: a module-import failure rejects the `boot()` Promise directly, so the caller's `await` throws — handle it with `try/catch`. `installFailLoud` covers a different case — a late plugin-init rejection surfacing *after* `boot()` has already resolved, which would otherwise become an unhandled rejection and die silently. In `cordis.yml`, the entry-point app plugin — `dsh-stdio-agent` for a REPL, `dsh-acp-agent` for an ACP server, or a custom one — sits alongside whichever services should load. Full helper surface: [`packages/ui/app-boot`](./packages/ui/app-boot).
+
+For end-to-end examples, see [`examples/`](./examples):
+
+- [`echo-agent`](./examples/echo-agent) — a minimal setup with a mock LLM and an echo tool
+- [`coding-agent`](./examples/coding-agent) — a full coding agent wired to the real DeepSeek LLM
+- [`acp-agent`](./examples/acp-agent) — ACP server, with a sandbox composition variant
+
+## Demo
+
+Harness driving Zed as an ACP agent — chat in the sidebar, tool calls (bash, file edits, diffs) rendered inline in the editor:
+
+<p align="center">
+  <video src="https://github.com/user-attachments/assets/a2bee95d-684f-41f4-b55f-1c14db0f24fa" controls width="800">
+    Your browser does not support inline video; download it from <a href="./assets/demo-acp.mp4">assets/demo-acp.mp4</a>.
+  </video>
+</p>
+
+<!-- TODO: additional feature-showcase clips go here (Code Mode / Dynamic Workflows / Self-installing plugins). -->
+
+## Write a plugin
+
+A Harness function/namespace plugin exports `name`, `inject`, and `apply` — cordis's Loader reads those separately. **`export default` breaks this shape** ([why](./docs/postmortem/0001-acp-default-export-drops-inject.md)): the Loader keeps only the `apply` function and silently drops `inject` / `name`, so the plugin fails to load with `cannot get property … without inject`. Inside `apply(ctx)`, tools / LLM adapters / services register through `ctx.*`.
+
+The minimal echo tool from [`examples/echo-agent`](./examples/echo-agent):
+
+```ts
+// echo-tool.ts
+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()}` }]
+    },
+  }))
+}
+```
+
+`parameters` uses the [schemastery](./vendor/schemastery) JSON-Schema-shaped DSL — one field per property, with `required: true` for mandatory ones. A leaf `cordis.yml` is a flat `EntryOptions[]` the Loader iterates; this tool's entry looks like:
+
+```yaml
+- id: echo-tool
+  name: './echo-tool.ts'          # your tool
+```
+
+Alongside it, a bootable config also needs an LLM adapter and a `stdio-agent` app entry whose `config.model` points at an id that adapter registers. The minimal runnable version — mock LLM + this echo tool + a `stdio-agent` entry wired to `mock-echo` — is [`examples/echo-agent`](./examples/echo-agent), launched via:
+
+```sh
+pnpm run demo:echo
+```
+
+LLM-adapter and UI-plugin shapes: [`docs/cookbook/extension-cookbook.md`](./docs/cookbook/extension-cookbook.md).
+
+## Packages
+
+All packages ship under the `@deepseek-ai/dsh-*` scope. Grouped by family:
+
+| Family | What lives here |
+|---|---|
+| **Core** (`packages/core/`) | `dsh-scope` · `dsh-session` · `dsh-tools` · `dsh-agent` · `dsh-agent-loop` · `dsh-system-prompt` |
+| **LLM** (`packages/llm/`) | `dsh-llm` (the seam) + `dsh-llm-deepseek` (hand-rolled) and `dsh-llm-pi-ai` (library-backed twin — same DeepSeek endpoint, different internals, kept for design verification) |
+| **Bash** (`packages/bash/`) | Shell execution: local + sandboxed backends, model-facing `bash` tool |
+| **Filesystem** (`packages/fs/`) | Filesystem service with a policy layer, `read` / `write` / `edit` tools |
+| **Web** (`packages/web/`) | Web search (Perplexity, Exa, DeepSeek) + fetch, model-facing tool |
+| **Sandbox** (`packages/sandbox/`) | Process-confinement seam (bwrap / Landlock / Seatbelt) — wraps a caller's argv under a per-call policy; execution itself lives in `ctx.bash` |
+| **Code runtime** (`packages/code-runtime/`) | JS worker runtime that Code Mode dispatches into |
+| **Sub-agents** (`packages/subagent/`) | `spawn`, `fork`, plus in-process / subprocess / ACP-backed backends |
+| **Workflows** (`packages/workflow/`) | Dynamic workflow orchestration (worker-thread execution) |
+| **Skills** (`packages/skill/`) | Skill-provider registry (`ctx.skills`) + a local-filesystem provider |
+| **Session persistence** (`packages/session-persistence/`) | Event-log persistence: JSONL and SQLite backends |
+| **Session query** (`packages/session-query/`) | `ctx.sessionQuery` — unified logical-corpus reads over live sessions + persistence |
+| **Compact** (`packages/compact/`) | Context compression / summarization |
+| **Context** (`packages/context/`) | Opt-in request-context enrichment (e.g. `dsh-time-context` — dynamic time-in-prompt) |
+| **Cordis toolset** (`packages/cordis/`) | Model-facing tools that inspect / mount / unmount cordis plugins at runtime |
+| **UI apps** (`packages/ui/`) | `dsh-stdio-agent` (REPL) · `dsh-acp-agent` (ACP server) · `dsh-app-boot` · approval + ask-user primitives |
+| **Hooks** (`packages/hooks/`) | Hook protocol + Claude Code / OpenAI Codex hook-config bridges |
+| **Guards** (`packages/guard/`) | Advisory loop-hygiene plugins (e.g. `repeat-tool-guard` for repeated-call escalation) |
+| **Timeouts** (`packages/timeout/`) | `timeout-policy` — a zero-config `tools/execute` wrapper enforcing per-tool `timeoutMs` |
+| **Todo** (`packages/todo/`) | The model-facing `todo_write` tool (whole-list task tracker) |
+| **Support** (`packages/support/`) | `invariants` — runtime diagnostic plugin mounted unconditionally by the shipped `dsh-agent-spine-demo` bundle; plus test/dev-only helpers (`llm-replay`, `acp-snapshot`, `subagent-mock`) |
+| **Example bundles** (`packages/examples/`) | Ready-to-run demo compositions the top-level `demo:*` scripts launch: `dsh-agent-spine-demo` (default spine + capabilities), `dsh-stdio-demo` (REPL), `dsh-acp-demo` (ACP server), `dsh-jsonrpc-demo` |
+| **Utils** (`packages/util/`) | Internal utility packages (`brand`, `timeout`) |
+
+For the full module dependency graph, see [`docs/module-graph.md`](./docs/module-graph.md).
+
+## Deep dives
+
+To understand what makes DeepSeek Harness different, start here:
+
+- [Architecture](./docs/architecture.md) — the service taxonomy and the microkernel structure
+- [Agent lifecycle](./docs/agent-lifecycle.md) — how a turn flows through the loop, with sequence diagrams
+- [Cordis primer](./docs/cordis-primer.md) — a working introduction to the underlying plugin framework
+- [Tool execution pipeline](./docs/tool-execution-pipeline.md) — how a tool call passes through permission gates, hooks, and logging
+- [Capability seams](./docs/capability-seams.md) — the extension points each service exposes
+- [Code Mode](./docs/rfc/implemented/feature/2026-06-15-code-mode.md) — the model writes one JavaScript program per turn that chains many bash / tool calls, executed in a single runtime pass. **One model round-trip per multi-step operation**, not one per call.
+- [Dynamic Workflows](./docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md) — the model writes a plain-JS orchestrator that fans out sub-agents in parallel, joins their results, and returns to the parent — instead of a chain of sub-agent tool calls.
+- [Self-referential Cordis toolset](./docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md) — the SDK's own plumbing (`cordis_inspect`, `cordis_mount`, `cordis_unmount`) is exposed as tools, so the model can inspect its own runtime and load new plugins on the fly.
+
+Docs site: **[deepseek.com/harness-sdk/docs](https://deepseek.com/harness-sdk/docs)**.
+
+## Community
+
+<a name="community"></a>
+
+- **[GitHub Issues](https://github.com/deepseek-harness/deepseek-harness/issues)** — bug reports
+- **[GitHub Discussions](https://github.com/deepseek-harness/deepseek-harness/discussions)** — questions, ideas, RFCs
+
+Real-time chat on <a href="https://discord.gg/4nyuPgFzdE"><b>Discord</b></a>. Release announcements on <a href="https://x.com/Deepseekharness"><b>X / Twitter</b></a>.
+
+## License
 
-For agents, follow [AGENTS.md](AGENTS.md).
+[BSD 3-Clause](./LICENSE) &copy; DeepSeek

+ 229 - 9
README.zh.md

@@ -1,20 +1,240 @@
-# DeepSeek Harness
+<!--
+  README.zh.md — Chinese pair.
+  If you edit this, update README.md in the same commit, then run:
+    pnpm run verify-translation-pairing --write
+  to refresh README.i18n.yaml.
+-->
+
+<div align="center">
+
+<!-- TODO: 待设计后替换为 logo / wordmark 资源 -->
+<h1>DeepSeek Harness</h1>
+
+**插件优先的 agent(智能体) SDK。每一项能力 &mdash; 包括 loop 本身 &mdash; 都是插件。**
+
+<p>
+  <a href="LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue" alt="license"></a>
+  <a href="https://nodejs.org"><img src="https://img.shields.io/badge/node-%E2%89%A522.19-3c873a" alt="node"></a>
+  <a href="https://pnpm.io"><img src="https://img.shields.io/badge/pnpm-workspace-f69220" alt="pnpm"></a>
+  <a href="https://www.typescriptlang.org"><img src="https://img.shields.io/badge/TypeScript-strict-3178c6" alt="typescript"></a>
+  <a href="https://agentclientprotocol.com"><img src="https://img.shields.io/badge/protocol-ACP-4a6ef5" alt="ACP"></a>
+</p>
 
 [English](README.md) | 中文
 
-**DeepSeek Harness SDK** 是用于构建 agent harness(智能体框架)的 SDK,采取基于插件的设计。
+<!-- TODO: deepseek.com/harness-sdk 是占位 URL,最终域名就绪后替换。 -->
+[文档](https://deepseek.com/harness-sdk/docs) &nbsp;·&nbsp; [Landing page](https://deepseek.com/harness-sdk) &nbsp;·&nbsp; [社群](#community)
+
+</div>
+
+<br>
+
+<p align="center">
+  <img src="./assets/arch-zh.png" alt="DeepSeek Harness · 系统一览" width="100%">
+</p>
+
+## 这是什么?
+
+DeepSeek Harness 是一个用 TypeScript 写的 AI agent SDK,构建在 [Cordis](https://github.com/cordiverse/cordis) 微内核之上。**所有服务,包括默认的 ReAct loop,都是通过 `ctx.*` 注册的插件。** 仓库里带了一整套开箱即用的服务 —— LLM 适配、沙盒执行、带策略的文件读写、网页搜索、子 agent、动态工作流、会话持久化等 —— 由项目根目录下的 `cordis.yml` 决定加载哪些。你可以替换任何一项、加装自己的,或者保留默认。
 
-## 开发
+## 上手
 
-本 monorepo 基于 [Cordis](https://github.com/cordiverse/cordis) 框架构建(以源码形式收录在 `vendor/` 下),采用微内核风格:所有功能都以插件形式提供。
+**新起一个项目**(一条命令生成脚手架):
 
 ```sh
+npm create @deepseek-ai/harness   # coming soon, not yet on npm
+```
+
+**克隆仓库**(读代码 / 跑 demo / 贡献代码):
+
+```sh
+git clone https://github.com/deepseek-harness/deepseek-harness.git
+cd deepseek-harness
 pnpm install
-pnpm run test          # vitest
-pnpm run demo:repl     # REPL agent demo (needs DEEPSEEK_API_KEY)
-pnpm run demo:acp      # ACP server agent demo (needs DEEPSEEK_API_KEY)
+export DEEPSEEK_API_KEY=sk-...    # optional — omit and use pnpm run demo:echo (mock, no key)
+pnpm run demo:repl
+```
+
+需要 **Node `^22.19 || ≥24`** 和 **pnpm ≥ 11.7**(Node 引擎与 pnpm 版本由 `package.json` 的 `engines` / `packageManager` 字段锁定;`corepack enable` 会自动装对 pnpm 版本)。Node 23 不在支持范围内。
+
+**注意:** `demo:repl` 会用真实的 `read` / `write` / `edit` 文件工具和 `bash` 操作**当前工作目录**,最好在空目录或干净的 git 项目里运行,方便随时 review 改动。
+
+## 接入编辑器
+
+Harness 内置了一个 [Agent Client Protocol (ACP)](https://agentclientprotocol.com) server。ACP 是一个把 agent 挂到编辑器边栏作为后端的协议;[Zed](https://zed.dev) 目前原生支持。
+
+ACP server 的启动命令(在 clone 的仓库根目录下):
+
+```sh
+pnpm run demo:acp
+```
+
+Zed 端 —— 在 Zed 的 `settings.json`(Cmd-Shift-P → "zed: open settings")里加上 `agent_servers` 一节:
+
+```json
+{
+  "agent_servers": {
+    "DeepSeek Harness": {
+      "command": "pnpm",
+      "args": ["--dir", "/path/to/deepseek-harness", "run", "demo:acp"],
+      "env": { "DEEPSEEK_API_KEY": "sk-..." }
+    }
+  }
+}
+```
+
+`--dir` 指向本地仓库路径。Zed 把 agent 作为子进程拉起,每个 Zed session 对应一个独立的 agent 实例;编辑器边栏可以直接对话,tool 调用(参数、结果、文件 diff)内联渲染到编辑区。完整配置说明见 [`examples/acp-agent`](./examples/acp-agent)。
+
+**VS Code / Cursor** —— 两个编辑器都可以装 ACP 客户端插件,比如 [ACP Client](https://marketplace.visualstudio.com/items?itemName=formulahendry.acp-client)(`formulahendry.acp-client`)或 [ACP Pro](https://marketplace.visualstudio.com/items?itemName=duclvz.acp-pro)(`duclvz.acp-pro`),把 `pnpm run demo:acp` 配成自定义 agent 即可接入。
+
+**其他 ACP 客户端** —— 接入方式相同。支持哪些 ACP 特性见 [`packages/ui/acp/acp-feature-support.md`](./packages/ui/acp/acp-feature-support.md)。
+
+## 嵌入自己的应用
+
+Harness 是通过 [`@deepseek-ai/dsh-app-boot`](./packages/ui/app-boot) 从一份 `cordis.yml` 引导起来的。如果希望在个人 Node.js 服务里以库的形式集成,可以用同样的引导方式:
+
+```ts
+// my-app.ts
+import {
+  boot,
+  installFailLoud,
+  loadEnv,
+  resolveConfigPath,
+} from '@deepseek-ai/dsh-app-boot'
+
+installFailLoud('my-app')
+loadEnv('my-app')
+
+const ctx = await boot('my-app', resolveConfigPath('./cordis.yml', undefined))
+// ctx is the Cordis root Context; every service you mount in cordis.yml
+// is reachable via ctx.* (ctx.agents, ctx.sessions, ctx.tools, …).
+// The app plugins loaded from cordis.yml keep the process alive on their own
+// (stdio agents hold stdin; the ACP agent holds an RPC connection).
+// To shut down programmatically, call `await ctx.fiber.dispose()`.
+```
+
+`boot()` 会在整棵插件树 settle 完之后返回。两条失败路径要分开处理:模块导入失败会直接 reject `boot()` 的 Promise,`await` 处会抛出,调用方用 `try/catch` 接住即可。`installFailLoud` 负责的是另一件事 —— `boot()` 返回之后才浮出来的 late plugin-init rejection,如果不接就会变成无人处理的 unhandled rejection 静默死掉。`cordis.yml` 里的 app 插件入口 —— `dsh-stdio-agent`(REPL)、`dsh-acp-agent`(ACP server)或自定义 —— 搭配想加载的服务。完整的 helper 表见 [`packages/ui/app-boot`](./packages/ui/app-boot)。
+
+完整的组合示例见 [`examples/`](./examples):
+
+- [`echo-agent`](./examples/echo-agent) —— mock LLM + echo tool 的最小示例
+- [`coding-agent`](./examples/coding-agent) —— 接真实 DeepSeek LLM 的完整 coding agent
+- [`acp-agent`](./examples/acp-agent) —— ACP server,含一个沙盒 composition variant
+
+## 演示
+
+Harness 作为 ACP agent 挂在 Zed 里 —— 边栏对话,工具调用(bash、文件编辑、diff)内联渲染在编辑区:
+
+<p align="center">
+  <video src="https://github.com/user-attachments/assets/a2bee95d-684f-41f4-b55f-1c14db0f24fa" controls width="800">
+    浏览器不支持内联视频,可下载 <a href="./assets/demo-acp.mp4">assets/demo-acp.mp4</a> 查看。
+  </video>
+</p>
+
+<!-- TODO: 后续加各功能特色演示视频(Code Mode / 动态工作流 / 自安装插件) -->
+
+## 编写插件
+
+Harness 的 function/namespace 插件通过分开的 `name` / `inject` / `apply` 命名导出注册,cordis Loader 读的是这些字段。**`export default` 不适用于这种形态** —— Loader 只会拿到 `apply` 函数,`inject` / `name` 被静默丢掉,加载时报 `cannot get property … without inject`(详见 [postmortem 0001](./docs/postmortem/0001-acp-default-export-drops-inject.md))。`apply(ctx)` 内通过 `ctx.*` 注册 tool、挂载 LLM adapter 或暴露 service。
+
+下面这个是 [`examples/echo-agent`](./examples/echo-agent) 里的真实 echo tool 插件:
+
+```ts
+// echo-tool.ts
+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()}` }]
+    },
+  }))
+}
+```
+
+`parameters` 是 [schemastery](./vendor/schemastery) 的 JSON-Schema 风格 DSL —— 每个字段一项定义,`required: true` 标记必填。leaf `cordis.yml` 是 Loader 迭代的一个 flat `EntryOptions[]`,这个工具的条目长这样:
+
+```yaml
+- id: echo-tool
+  name: './echo-tool.ts'          # your tool
+```
+
+同一份配置里还要有 LLM adapter 和一个 `stdio-agent` app 条目,`config.model` 指向 adapter 里注册的某个 model id。最小可跑组合 —— mock LLM + 这个 echo tool + 接到 `mock-echo` 的 `stdio-agent` —— 见 [`examples/echo-agent`](./examples/echo-agent),运行命令:
+
+```sh
+pnpm run demo:echo
 ```
 
-面向开发者:先读[开发指南](docs/development.md),了解本地环境搭建、钩子、环境变量与质量门禁,动手改 package 之前再读[架构设计](docs/architecture.md)和[文档关系图索引](docs/graph-atlas.md)。局部上下文见 [packages/](packages/) 与 [vendor/](vendor/)。
+LLM adapter 与 UI 插件的写法见 [`docs/cookbook/extension-cookbook.md`](./docs/cookbook/extension-cookbook.md)。
+
+## Packages
+
+所有包都在 `@deepseek-ai/dsh-*` scope 下,按目录分组:
+
+| 分组 | 包含 |
+|---|---|
+| **Core**(`packages/core/`)| `dsh-scope` · `dsh-session` · `dsh-tools` · `dsh-agent` · `dsh-agent-loop` · `dsh-system-prompt` |
+| **LLM**(`packages/llm/`)| `dsh-llm`(seam)+ `dsh-llm-deepseek`(手写实现)与 `dsh-llm-pi-ai`(第三方库实现的孪生 —— 打同一个 DeepSeek endpoint,内部走不同代码路径,用于设计验证)|
+| **Bash**(`packages/bash/`)| 命令行执行:本地 + 沙盒后端,模型可调用的 `bash` tool |
+| **Filesystem**(`packages/fs/`)| 带策略层的文件服务,`read` / `write` / `edit` tools |
+| **Web**(`packages/web/`)| 网页搜索(Perplexity、Exa、DeepSeek)+ fetch,模型可调用的 tool |
+| **Sandbox**(`packages/sandbox/`)| 进程隔离接缝(bwrap / Landlock / Seatbelt)—— 按每次调用的策略包一层 argv,真正的执行由 `ctx.bash` 负责 |
+| **Code runtime**(`packages/code-runtime/`)| Code Mode 分发进入的 JS worker 运行时 |
+| **Sub-agents**(`packages/subagent/`)| `spawn` / `fork`,以及进程内 / 子进程 / ACP 后端 |
+| **Workflows**(`packages/workflow/`)| 动态工作流编排(worker 线程执行)|
+| **Skills**(`packages/skill/`)| Skill provider 注册中心(`ctx.skills`)+ 本地文件系统 provider |
+| **Session persistence**(`packages/session-persistence/`)| 事件日志持久化:JSONL 与 SQLite 后端 |
+| **Session query**(`packages/session-query/`)| `ctx.sessionQuery` —— 把 live sessions 和持久化层合成同一份逻辑语料的统一查询 |
+| **Compact**(`packages/compact/`)| 上下文压缩 / 摘要 |
+| **Context**(`packages/context/`)| 可选的请求上下文增强(如 `dsh-time-context` —— 系统提示词里注入动态时间)|
+| **Cordis toolset**(`packages/cordis/`)| 模型可调用的、在运行时查看 / 挂载 / 卸载 cordis 插件的 tools |
+| **UI apps**(`packages/ui/`)| `dsh-stdio-agent`(REPL)· `dsh-acp-agent`(ACP server)· `dsh-app-boot` · approval / ask-user 基础件 |
+| **Hooks**(`packages/hooks/`)| Hook 协议 + Claude Code / OpenAI Codex 的 hook 配置桥 |
+| **Guards**(`packages/guard/`)| 建议性的 loop 健康插件(如 `repeat-tool-guard` —— 检测同一 tool 重复调用并升级 advisory)|
+| **Timeouts**(`packages/timeout/`)| `timeout-policy` —— 零配置的 `tools/execute` 包装,按 tool 声明的 `timeoutMs` 强制超时 |
+| **Todo**(`packages/todo/`)| 模型可调用的 `todo_write` tool(整表任务追踪)|
+| **Support**(`packages/support/`)| `invariants` —— 由默认组合 `dsh-agent-spine-demo` 无条件挂载的运行时诊断插件;此外是仅测试/开发用的辅助包(`llm-replay`、`acp-snapshot`、`subagent-mock`)|
+| **Example bundles**(`packages/examples/`)| 顶层 `demo:*` 脚本直接跑的组合示例包:`dsh-agent-spine-demo`(默认 spine + 能力)、`dsh-stdio-demo`(REPL)、`dsh-acp-demo`(ACP server)、`dsh-jsonrpc-demo` |
+| **Utils**(`packages/util/`)| 内部工具包(`brand`、`timeout`)|
+
+完整的模块依赖图见 [`docs/module-graph.md`](./docs/module-graph.md)。
+
+## 深入阅读
+
+想理解 DeepSeek Harness 为什么与众不同,从这里入手:
+
+- [架构](./docs/architecture.md) —— 服务分类和微内核结构
+- [agent 生命周期](./docs/agent-lifecycle.md) —— 一次 turn 在 loop 里的流转(含时序图)
+- [Cordis 入门](./docs/cordis-primer.md) —— 底层插件框架的实用入门
+- [工具执行流水线](./docs/tool-execution-pipeline.md) —— 一次 tool 调用如何经过权限校验、hooks 和日志
+- [能力接缝](./docs/capability-seams.md) —— 每个服务暴露的替换点
+- [Code Mode](./docs/rfc/implemented/feature/2026-06-15-code-mode.md) —— 模型每个 turn 写一段 JS 程序,在一次运行里串起多次 bash / tool 调用。**多步操作 → 一次模型往返**,不是每次调用一次往返
+- [动态工作流](./docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md) —— 模型写一段 JS orchestrator,把多个 sub-agent 并行 fan out、合并结果、再回到父 agent —— 而不是链式地调 subagent tool
+- [自引用的 Cordis 工具集](./docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md) —— SDK 自身的插件管理机制(`cordis_inspect` / `cordis_mount` / `cordis_unmount`)以 tool 的形式暴露给模型,让模型能在运行时查看当前运行时并按需挂载新插件
+
+文档站:**[deepseek.com/harness-sdk/docs](https://deepseek.com/harness-sdk/docs)**。
+
+## 社群
+
+<a name="community"></a>
+
+- **[GitHub Issues](https://github.com/deepseek-harness/deepseek-harness/issues)** —— Bug 反馈
+- **[GitHub Discussions](https://github.com/deepseek-harness/deepseek-harness/discussions)** —— 功能建议、设计讨论、Q&A
+
+企业微信讨论群通过腾讯问卷申请入群,专人筛选后邀请:
+
+<img src="./assets/community-wecom-survey.png" alt="腾讯问卷 · 企业微信社群入群申请" width="220">
+
+## License
 
-面向 agent:遵循 [AGENTS.md](AGENTS.md)。
+[BSD 3-Clause](./LICENSE) &copy; DeepSeek

BIN
assets/arch-en.png


BIN
assets/arch-zh.png


BIN
assets/community-wecom-survey.png


BIN
assets/demo-acp.mp4