# dsh-agent-notes **English** | [中文](README.md) [![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-ai/deepseek-harness) [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE) Turn "why we changed it this way and what we gave up" into **mechanically checked** decision notes inside a repository, delivered as a DeepSeek Harness plugin. > The method is distilled from [czm15053/write-notes-like-deepseek](https://github.com/czm15053/write-notes-like-deepseek), which in turn distills the `.agents/notes/` practice of [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness). > This plugin packages that method as a native DSH plugin: a skill, session switches, real gates, and upstream merging. ## What it solves Code can express *how the system currently runs*; it cannot express **why it must run that way, and what was given up**. So every new session will: "optimize away" an awkward-looking block that was deliberately written that way to avoid a deadlock; punch through global structure to satisfy a local need; and re-propose a design already proven to run out of memory three months ago. This plugin makes the rules **hard to walk around**: same repository as the code, same change, mechanically checked, old decisions sealed with a tamper-evident hash. ## Install ```sh # From a local directory (during development) dsh plugin add /path/to/dsh-agent-notes # Or from GitHub dsh plugin add github:iuuuuuuuu/dsh-agent-notes ``` Then enable `dsh-agent-notes` in the Web/Desktop plugin list and **restart DSH**. ## Usage ``` /agent-notes Show switch and note-tree status /agent-notes on Enable for this session (persisted across reloads) /agent-notes on --global Change the global default (all sessions without an override) /agent-notes reset Clear this session's override, returning to the global default /agent-notes init Scaffold .agents/notes in the current repository /agent-notes gate Run the real gates (also: gate tree / gate format / gate archived) ``` Once enabled, the model also gains: - an **`agent-notes` skill** — the full method, class rules, templates, and archival policy, loaded on demand; - an **`agent_notes_gate` tool** — runs the verify scripts and returns their **process exit code**, not a claim of compliance; - an **`agent_notes_status` tool** — current switch and note-tree overview; - a **session-scoped policy section** — injected only into sessions where the switch is on, leaving the global system prompt untouched. ## What a note looks like The path *is* the state; there is no index file: ``` .agents/notes/{lifecycle}/{class}/yyyy-mm-dd-topic.md ``` | lifecycle | meaning | |---|---| | `proposed/` | A proposal that has not shipped | | `implemented/` | Shipped, kept current with the code | | `rejected/` | Deliberately declined; kept only while it prevents a repeat mistake | | `archived/` | Sealed with a SHA-256 digest, append-only | The class set is closed (six): `feature`, `bug-fix`, `simplification`, `architecture`, `process`, `testing`. ## Gates: the exit code is the verdict ```sh node skills/agent-notes/scripts/verify-agent-note-tree.ts # layout / class / filename / relative links node skills/agent-notes/scripts/verify-agent-note-format.ts # header / required sections / alternatives / no proposal titles node skills/agent-notes/scripts/verify-archived-agent-notes.ts # archive seals are append-only ``` These gates are **proven to actually fail** by fault injection (see below). The plugin exposes the capability to the model, but **enforcement belongs in the host repository's CI**: ```yaml # .github/workflows/verify-notes.yml (template: skills/agent-notes/templates/verify-notes.yml) - run: node skills/agent-notes/scripts/verify-agent-note-*.ts ``` ## Upstream merging Bundled content comes from a pinned upstream commit and can be checked and merged: ```sh node tools/sync-upstream.mjs --check # report drift only, zero writes (non-zero exit on drift, CI-ready) node tools/sync-upstream.mjs # show a per-file diff summary; needs --yes to write node tools/sync-upstream.mjs --yes # actually overwrite the bundled copy and record the manifest node tools/sync-upstream.mjs --ref # use another ref ``` **Why the default ref is a commit rather than `main`**: jsDelivr's manifest cache for branch names lags in practice — anchoring at `@main` returned a pre-refactor directory layout, so path matching failed. Pinning a commit yields that commit's real tree. This was learned the hard way, not assumed. After merging, always re-run: ```sh node --test tools/*.test.mjs && node tools/fault-injection.mjs ``` ## Self-check and tests ```sh npm test # behavior tests (real subprocesses, real files) npm run gate:fault-injection # prove the gates can go red rather than being always-green npm run verify # package self-check: manifest / patch / zero-dep / bilingual docs + badge / vendored-vs-upstream digests npm run sync:check # whether upstream has moved npm run evidence # live evidence against DSH's own real SkillRegistry npm run check # runs the four above in sequence ``` `fault-injection` injects, for each gate, the exact defect it should catch (illegal class, bad filename, missing alternatives, a proposal title left in `implemented`, a tampered or deleted sealed archive, …), asserts a non-zero exit, then removes the defect and asserts a return to zero. **If any gate fails to react, the script itself exits non-zero** — and I verified that by injecting a deliberately failing assertion into the script. > `npm run evidence` and the integration tests need to locate a DSH installation. They auto-detect `$DSH_HOME`, `~/.dsh`, and each profile's `node_modules`; for non-standard layouts such as a bundled desktop install, point at it explicitly: > > ```sh > DSH_DIST=/path/to/dsh/lib/bin.js npm run evidence > ``` > > When detection fails, `evidence` **fails loudly (exit code 2)** rather than pretending to pass; the integration tests degrade to a same-contract harness and state which mode they used in their output. ## Design constraint (why zero dependencies) This plugin **imports no `@deepseek-ai/*` package**. That is measured, not stylistic: a profile's `node_modules` resolves `@deepseek-ai` only to `cosmokit`/`schemastery`, so a plugin cannot reach the DSH type packages at runtime. Therefore: - host APIs are used **structurally** (`ctx.skills` / `ctx.tools` / `ctx.commands` / `ctx.systemPrompt` / `ctx.agents`), and a missing capability degrades to off instead of crashing; - only Node built-ins are used; - tools are registered as **plain objects** (DSH accepts a raw `ToolDefinition`; that is how MCP-sourced tools arrive). `tools/verify-plugin.mjs` enforces this: any `@deepseek-ai/*` import added under `lib/` turns the self-check red. ## Components | File | Responsibility | |---|---| | `lib/index.js` | Assembly; mount/unmount of the session-scoped policy | | `lib/state.js` | Global default + per-session override, both persisted (atomic writes) | | `lib/notes.js` | Note-tree discovery, real gate execution, scaffolding | | `lib/skill.js` | The `agent-notes` skill provider (strips frontmatter) | | `lib/policy.js` | The injected policy text | | `lib/commands.js` | The `/agent-notes` command | | `lib/tools.js` | The `agent_notes_gate` / `agent_notes_status` tools | | `skills/agent-notes/` | Vendored upstream content (SKILL.md, references, templates, scripts, assets) | | `tools/` | Upstream merge, self-check, fault injection, tests | ## Known limitations - The **board template references external Google Fonts**, so offline use falls back to system fonts; functionality is unaffected. - Upstream syncing depends on jsDelivr reachability; when unreachable, `sync` fails loudly rather than skipping silently. - DSH is in developer preview. No `peerDependencies` are declared (this plugin depends on no DSH package), but host API changes may require follow-up. - Session switches persist **by session id**; after a session is deleted its override remains in the state file, and there is currently no GC. - Host-repository CI wiring is left to you; the plugin does not modify repositories. ## License MIT. Vendored upstream content remains under its authors' copyright; see the notes inside `skills/agent-notes/` and the upstream repository. --- [![](https://img.shields.io/badge/powered_by-dsh-4D6BFE?style=flat-square&logo=deepseek&logoColor=white)](https://github.com/deepseek-ai/deepseek-harness)