From b8d4790e98e20b2b8926ad4431225551f9732968 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sun, 14 Jun 2026 23:07:52 +0800 Subject: [PATCH 1/2] docs: sync high-authority docs with the doc-sync gate and dsh-invariants (P1-16) The `yarn doc-sync` gate (doc-typecheck + verify-event-taxonomy) and the @deepseek-ai/dsh-invariants package both exist now, but the instruction docs never caught up and the gate's markdown scope (README.md, docs/**/*.md, packages/*/README.md) does not cover AGENTS.md / packages/AGENTS.md, so they drifted silently. - AGENTS.md: add invariants/ to the Repository Layout; add doc-typecheck / verify-event-taxonomy / doc-sync to Commands; rewrite the false "CI has no doc-sync gate" sentence to describe the gate's actual coverage and what remains outside it (AGENTS.md, packages/README.md, prose drift). - packages/AGENTS.md: fix the same stale "no doc-sync gate" line. - packages/README.md: add dsh-invariants to the dependency graph and the package table. Verification: `yarn doc-sync` green; `grep -rn "no doc-sync gate"` returns nothing; the three command names + dsh-invariants are present. --- AGENTS.md | 8 +++++++- packages/AGENTS.md | 2 +- packages/README.md | 2 ++ 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 28be76ff13..ddda1af98e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -29,6 +29,7 @@ packages/ Harness packages, all named @deepseek-ai/dsh-: tools/ tool registry + tools/execute waterfall agent/ Agent interface, registry, agent/* event vocabulary agent-loop/ THE concrete plugin: LoopAgent + the loop driver + invariants/ dev-mode event-contract invariants + session-log freeze bash/ abstract bash executor seam (ctx.bash) — interface only bash-local/ local-subprocess BashExecutor implementation tool-bash/ model-facing bash/bash_output/bash_kill tool schemas @@ -62,6 +63,11 @@ yarn build # tsc -b tsconfig.build.json && tsdown (JS bundles into lib/ yarn knip # dead-code / unused-dependency check yarn publint # package.json publish-correctness check (publishable packages/*) yarn hygiene # knip + publint + yarn constraints +yarn doc-typecheck # typecheck every ```ts block in README.md, docs/**/*.md, + # packages/*/README.md (doc/code drift gate) +yarn verify-event-taxonomy # assert the event-taxonomy table in docs/architecture.md + # matches the interface Events declarations in source +yarn doc-sync # doc-typecheck + verify-event-taxonomy (CI runs this) yarn demo:echo # run examples/echo-agent (no API key; type "echo hi" to # see a tool call) — the mock skeleton yarn demo:coding # run examples/coding-agent — the real agent (needs @@ -117,7 +123,7 @@ This codebase aims to be **very type-safe and well documented** for maintainabil In the **core** packages (`packages/llm`, `packages/tools`, `packages/agent`, `packages/agent-loop`, `packages/session`, `packages/system-prompt`), **type gymnastics are acceptable when they improve the DX of plugin authors** for common plugin types. The `defineTool` typed schema DSL in `dsh-tools` is the canonical example: the `SchemaSpec` to `InferArgs` type-level mapping gives tool authors zero-cast typed `execute` args, and the cost of the conditional types stays inside the core package. -Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI has no doc-sync gate, so this is on the author. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices. +Verbose documentation is fine **as long as docs and code stay strictly in sync**. Out-of-sync docs are worse than no docs. **When you change code, update its docs in the SAME change** — grep the package README and the module/JSDoc comments for the old behavior (config keys, defaults, error codes, wire field names, event names) and fix every hit. CI runs `yarn doc-sync` (`doc-typecheck` + `verify-event-taxonomy`), which typechecks every fenced `ts` block in `README.md`, `docs/**/*.md`, and `packages/*/README.md` and verifies the event-taxonomy table against source — but that scope does NOT cover `AGENTS.md`, `packages/AGENTS.md`, or `packages/README.md`, nor does it catch prose drift (config keys, defaults, error codes), so keeping those in sync remains on the author. Every module has a module-level doc comment explaining its role. Every exported class, interface, type, function, and non-obvious method has a JSDoc that explains semantics (not just the name) — contracts (what events fire when), disposal behavior, error behavior, and extension intent. Internal helpers get docs only where non-obvious. Prefer one-liners when one line suffices. **Markdown is not hard-wrapped**: write one line per paragraph and let the editor soft-wrap. Hard line breaks mid-paragraph make docs harder to edit and diff — a one-word change reflows and re-diffs the whole paragraph. This applies to prose only: leave fenced code blocks, tables, and list structure intact (a wrapped list item folds to one line per bullet). Code comments / JSDoc are exempt — they stay under the linter's column limit. diff --git a/packages/AGENTS.md b/packages/AGENTS.md index a246559c2c..6c1f980d95 100644 --- a/packages/AGENTS.md +++ b/packages/AGENTS.md @@ -11,6 +11,6 @@ Naming notes: - Files `src/index.ts` export the service default + all public types - `src/types.ts` contain only types — no runtime code - Tests live at package level under `tests/`, not `src/__tests__/` -- A package's README and module/JSDoc comments are part of the change: when you alter behavior (config keys, defaults, error codes, wire fields), update them in the same commit. CI has no doc-sync gate, so stale docs are on the author. +- A package's README and module/JSDoc comments are part of the change: when you alter behavior (config keys, defaults, error codes, wire fields), update them in the same commit. CI runs `yarn doc-sync`, which typechecks fenced `ts` blocks in `packages/*/README.md` and verifies the event-taxonomy table — but it does NOT cover this file or prose drift (config keys, defaults, error codes), so those stay on the author. Read the per-package README.md for package-specific details: service API, events, extension points, TODOs. diff --git a/packages/README.md b/packages/README.md index e61d3a976a..899c292482 100644 --- a/packages/README.md +++ b/packages/README.md @@ -16,6 +16,7 @@ dsh-tool-bash ← dsh-bash, dsh-tools (bash tool schemas) dsh-llm-deepseek ← dsh-llm (DeepSeek adapter) dsh-llm-pi-ai ← dsh-llm (pi-ai-backed adapter) dsh-agent-loop ← dsh-llm, dsh-session, dsh-system-prompt, dsh-tools, dsh-agent +dsh-invariants ← dsh-llm, dsh-session, dsh-agent (dev-mode contract checks) ``` The rule: plugins depend on interfaces, never on the concrete loop. `dsh-agent-loop` is swappable — UI/hook/tool plugins keep working against the `dsh-agent` vocabulary if the loop is replaced. A swappable capability splits into interface / implementation / consumer packages (the bash trio is the template — see [ADR 0009](../docs/adr/0009-capability-seams.md)). @@ -35,6 +36,7 @@ The rule: plugins depend on interfaces, never on the concrete loop. `dsh-agent-l | `tool-bash/` | Model-facing `bash`/`bash_output`/`bash_kill` tool schemas | (registers on `ctx.tools`) | | `llm-deepseek/` | DeepSeek API adapter (hand-rolled fetch/SSE) | (registers on `ctx.llm`) | | `llm-pi-ai/` | DeepSeek adapter via `@earendil-works/pi-ai` (design twin) | (registers on `ctx.llm`) | +| `invariants/` | Dev-mode event-contract invariants + session-log freeze | (listens on `session/*`, `agent/*`) | Each package has its own `README.md` with purpose, service API, events, extension points, and deliberate non-goals (TODOs). From bcfff6f1ee47990a1609d517280a18ea21f35fe1 Mon Sep 17 00:00:00 2001 From: Tianyi Cui <53024+tianyicui@users.noreply.github.com> Date: Sun, 14 Jun 2026 23:14:46 +0800 Subject: [PATCH 2/2] docs: correct the doc-sync gate claim in the code-review skill (PR1 review) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codex review of PR1 found a semantically-identical stale claim outside the three files first touched: .agents/skills/dsh-code-review/SKILL.md said "the doc-sync rule has no gate", which is the same P1-16 drift. doc-sync DOES gate compilable ts blocks and the event-taxonomy table; only prose drift (config keys, defaults, error codes, wire fields) is ungated. Reworded to say exactly that. (ADR 0014 was also checked and is correct as-is — it is the decision record that establishes the gate and already describes it as existing.) --- .agents/skills/dsh-code-review/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.agents/skills/dsh-code-review/SKILL.md b/.agents/skills/dsh-code-review/SKILL.md index 9af4380dde..6e28c77306 100644 --- a/.agents/skills/dsh-code-review/SKILL.md +++ b/.agents/skills/dsh-code-review/SKILL.md @@ -17,7 +17,7 @@ This is a where-to-look map, not a rules list. The rules live in the docs below ## Where to look first (review-specific, not in the docs) -1. **Docs in sync?** If the PR changes a config key, default, error code, wire field, or event name, did it update the package README + module/JSDoc in the same diff? Stale docs are the most common miss (the doc-sync rule has no gate). +1. **Docs in sync?** If the PR changes a config key, default, error code, wire field, or event name, did it update the package README + module/JSDoc in the same diff? Stale docs are the most common miss — `yarn doc-sync` only gates compilable `ts` blocks and the event-taxonomy table, so prose drift (config keys, defaults, error codes, wire fields) has no gate and is on the reviewer to catch. 2. **HMR-safety test present?** Any new registry/registration needs a test that disposes the contributing fiber and asserts cleanup. Its absence is a blocking gap. 3. **Gates green?** typecheck, lint, test, test:coverage (100% per-file on `packages/*/src`), knip, build, publint, constraints. Don't re-review what a gate already enforces — trust the gate, spend attention on what gates can't check (intent, contracts, doc sync). 4. **e2e verifies the world, not the agent's self-report.** For real-API tests, confirm the assertion re-runs the command/checks the file externally — a keyword probe lets a cheating agent pass (see AGENTS.md e2e bullet).