Cyning12/SpecWave

Cyning12/dsh-coding-kit

DeepSeek Harness 的 ICVO 编码规范套件:bundle 插件加载时仅注册工具,须调用 apply_coding_standards 才注入规范;另附 P0 门禁 CLI(npx dsh-coding-kit),含 G1–G7 过程命令、skills install 与 IDE 块刷新。

工作流与自动化deepseek-harnessdshdsh-plugins

SpecWave

简体中文 | English

SpecWave (spec-wave@3.4.0) is a multi-host coding CLI — one declarative adapt table lands natively on Cursor, Claude Code, optional DSH, agents, and more — with P0 gate / Harness process commands and IDE landing. Discipline assets remain ICVO (Inform · Constrain · Verify · Orchestrate).

Loading ≠ injecting. Installing or loading the optional DSH plugin does not automatically rewrite the system prompt. apply() only registers tools. Only after you or the model calls apply_coding_standards will later turns' runtime context contain # Coding Standards.

New here? First-hour terms — task.md / Harness / hats / kit-* — are defined in GLOSSARY.md (bilingual).

Formerly SpecGate / dsh-coding-kit — rename history and migration: MIGRATION.md.

Prerequisites

RequirementNotes
Node.js^22.19.0 or >=24.0.0 (see package.json#engines)
Not supportedNode 20 (and earlier) — engines will fail; upgrade before npx / install
node -v   # expect v22.19+ or v24+

Quick start (5 steps)

Primary entry is npx spec-wave from npm spec-wave@3.4.0. Plugin surface and CLI surface do not replace each other.

# 1) Confirm package (pin recommended)
npx spec-wave@3.4.0 --version

# 2) Validate adapt table (dry)
npx spec-wave@3.4.0 host validate

# 3) Materialize hosts (dry-run, then write)
npx spec-wave@3.4.0 host apply --tools cursor,claude,dsh --profile core
npx spec-wave@3.4.0 host apply --tools cursor,claude,dsh --profile core --yes

# 4) Or first-time init (process root + host select)
npx spec-wave@3.4.0 init --preset harness-only --tools cursor,claude,dsh --yes

# 5) After you have a task.md — mechanical gate (exit 2 = hard stop)
npx spec-wave@3.4.0 verify --task docs/tasks/active/task_<slug>.md

After --yes, Cursor should see kit-verify / …; Claude Code /kit:verify; DSH .dsh/skills/kit-*. Full host matrix and Entry A/B encyclopedia: Multi-host matrix · Entry A · DSH plugin · Entry B · CLI. Concepts: Core objects · GLOSSARY.md.

Empty repo: minimal green when test_strategy=required

CLI never writes example tasks into your docs/tasks/ (S2). You copy the template yourself:

  1. npx spec-wave@3.4.0 sync prompts --yes (materializes docs/harness/templates/TASK_TEMPLATE.md among prompts).
  2. Copy the template → docs/tasks/active/task_<slug>.md (your action).
  3. If meta sets test_strategy=required: add a failing automated test for the critical path before hat 30 changes implementation; then implement until green.
  4. Human-gate table must be 4 columns; HG-AUDIT-R1 → approved before hat 30 may change code.
  5. npx spec-wave@3.4.0 task lint --file docs/tasks/active/task_<slug>.md then verify --task ….

Details: template path above · Core objects · GLOSSARY.md.

Which entry to choose

Who you areEntryDo NOT
Cursor / Claude Code / CI on existing reposnpx spec-wave (+ optional host apply)Don't treat the plugin init_coding_kit and the CLI init as the same entry
DSH session / model calling tools (optional)dsh plugin add spec-wave (dsh-coding-kit deprecated — do not add the old name)Don't just npm install (without the bundle layer the tools won't appear)

Transition bins specgate and dsh-coding-kit still work; new scripts should use npx spec-wave.

Multi-host matrix

One declarative table → native landing on several hosts (always_on + skills + commands). Verify truth stays in the CLI (failClosed exit 2); IDE slash/commands only orchestrate. Installing the npm package does not materialize IDE files (no postinstall); run init --tools / host apply explicitly.

HostWhat host apply writes (profile core)
Cursor.cursor/rules/*.mdc · .cursor/commands/kit-*.md · .cursor/skills/
Claude CodeCLAUDE.md product marker block · .claude/commands/kit/<verb>.md → /kit:verb · .claude/skills/
DSH.dsh/skills/ — hat skills + orchestration kit-* (discoverable via /; no .dsh/commands/)
agents (optional)AGENTS.md fragment · .agents/skills/
CopilotAGENTS.md fragment (shared marker block) · .github/skills/
CodexAGENTS.md fragment (shared marker block) · .agents/skills/
WindsurfAGENTS.md fragment (shared marker block) · .windsurf/skills/
Gemini CLIGEMINI.md (same host-neutral fragment) · .gemini/skills/
opencodeAGENTS.md fragment (shared marker block) · .agents/skills/
Roo CodeAGENTS.md fragment (shared marker block; loaded per official-repo merged PR) · no skills dir (no official convention)
ZedAGENTS.md fragment (shared marker block) · .agents/skills/
ClineAGENTS.md fragment (shared marker block) · .cline/skills/
aider (injection layer)AGENTS.md fragment (injection-layer support: aider does not auto-load AGENTS.md — use aider --read AGENTS.md or .aider.conf.yml with conventions-file: AGENTS.md) · no skills dir (no official convention)

2.2 W6 / 2.3 W6 host additions (same package): the nine hosts above reuse the agents asset face (zero new assets); each landing follows the host's official docs, and hosts without an official skills convention get no skills directory (never fabricated). aider is a documented downgrade — injection layer only.

2.1 additions (same package): Claude /kit: namespace UX · DSH .dsh/skills/kit-* orchestration · optional --profile expanded for kit-hat-* thin shells (default remains core).

2.1.1 · install / upgrade UX (aligned with OpenSpec init --tools):

TopicBehavior
StickySuccessful --yes write of host apply / host update / init (when materializing) updates .coding-kit/host-tools.json (host_ids + profile). Dry-run does not write sticky.
--toolsLIST (e.g. cursor,claude,dsh) · all (every host_id in the adapt table) · none (init only: process root, no host materialize). host apply always requires --tools.
host update (scheme A)Resolve order: CLI --tools → sticky → else exit 1. With sticky, host update --yes refreshes only selected hosts. BREAKING (small) vs 2.1.0 “omit --tools = full table”.
initTTY without --tools → asks (multi-select / all / none). Non-TTY / CI without --tools → exit 1. tools≠none and not --no-host-adapt → in-process host apply + sticky. --no-host-adapt → no apply and no sticky.
# After upgrading the package: refresh sticky hosts (no need to re-list --tools)
npx spec-wave@3.4.0 host update --yes

Full matrix: assets/ide/host-adapt/README.md · dogfood/recording: docs/guides/DOGFOOD_host_adapt_cursor_claude_录屏清单_v1_zh.md · plan: docs/roadmap/PLAN_2_1_1_host_tools_ux_v1_zh.md.

The @deepseek-ai/cordis and @deepseek-ai/dsh-tools entries in peerDependencies are the DSH host plugin contract (needed only when the host loads this package as a plugin; not needed for CLI-only use), and are marked optional in peerDependenciesMeta.

Core objects

The Harness process revolves around two file-level objects. verify --task <task.md> / gate-check --task <task.md> / task close all operate on the first one — this section defines both before you meet them in the command list.

task.md — one executable, verifiable unit of work

  • What it is: a single Markdown file for one unit of work: background/goal, scope, non-goals, failure paths, acceptance criteria, Harness metadata (test_strategy, wiki_delta, …) and the human-gate table. HG-AUDIT-R1 must be approved in that table before hat 30 may change code; npx spec-wave verify --task <task.md> reads the table as truth (chat claims do not count).
  • Where it comes from: copy docs/harness/templates/TASK_TEMPLATE.md, materialized by npx spec-wave sync prompts --yes. The CLI never writes example tasks into your docs/tasks/ — creating the file is always your explicit action.
  • Where it lives: docs/tasks/active/task_<slug>.md while in flight; npx spec-wave task close --file <task> --yes archives it to docs/tasks/done/.

Minimal skeleton (full field list in the template):

# Task: add login rate limiting

> **状态**:`draft`

## Harness 元信息
| 字段 | 值 |
|------|-----|
| **task_slug** | `login-rate-limit` |
| **test_strategy** | `required` |
| **wiki_delta** | `none` |

### 人工闸

| human_gate_id | status | blocks_hats | 说明 |
|---------------|--------|-------------|------|
| HG-AUDIT-R1 | pending | 30 | R1 审查后人签 |

## 范围 / ## 非范围 / ## 失败路径 / ## 验收标准
(逐节照模板填写;验收须含可跑命令)

Gate table: must be 4 columns (last column 说明). A 3-column table is silently ignored by the parser. Do not put bold ** inside the id cell (that makes the whole row fail to parse); wrapping the whole id as **HG-…** is OK.

spec.md — the requirement a task traces back to

  • What it is: the signed-off requirement spec (background / scope / non-scope / acceptance / failure paths) that a task references via 关联 SPEC. npx spec-wave verify --spec <SPEC.md> gates that a written review exists before implementation.
  • Where it comes from: written by you or your agent (hat 10 flow) — the CLI does not materialize spec files.
  • Where it lives: docs/spec/ (this repo keeps specs under docs/spec/<topic>/, e.g. docs/spec/2_2-closed-loop-start/).

The same quickstart chain is printed by npx spec-wave init — step 3 requires your project to be a git repository (run git init first if needed; verify checks git-root ownership). Step 4 (optional) points to npx spec-wave graph scaffold for a reviewable draft under docs/_tech_graph/ (not signed architecture truth; see graph section below). Terminology (Harness / hats / gates / S2) is collected in GLOSSARY.md (bilingual glossary — links back to this section).


Entry A · DSH plugin

Prefer npm (prebuilt, no allowBuilds needed):

dsh plugin --profile web add spec-wave

dsh-coding-kit is deprecated. Use spec-wave as the DSH plugin package name (same product).

Fallback: install from GitHub (needs a Node build; pnpm 10+ may require allowBuilds):

dsh plugin --profile web add github:Cyning12/SpecWave#main

Confirmation layer

dsh --profile web --dump-config

After a successful install, the profile's package.json will show the spec-wave dependency, and dsh.profile.bundles will contain the package name. Users generally don't need to hand-edit bundles; dsh plugin add maintains them.

Activation and invocation

  1. Start DSH with that profile (e.g. dsh --profile web / dsh --profile web web).
  2. Say in the conversation: Please apply the coding standards (or "write code per the coding-kit standards").
  3. The model should call the apply_coding_standards tool.
  4. On success, later turns' runtime context contains # Coding Standards.

Optional parameters: profile=l1|l1+l2|full (default l1+l2); persist=false returns the body only in the current tool result.

Profile tier semantics:

TierContent
l1L1 standards + coding_wiki
l1+l2 (default)all standards + coding_wiki
fullequivalent to l1+l2 in the current version; the enum value is reserved for future bundle extensions (differentiated injected content)

Override root lookup rule (since 1.3.0): apply_coding_standards probes upward from the current working directory for .coding-kit and .dsh/coding-kit, stopping at the nearest ancestor directory containing .git (the git root) — so starting DSH from a monorepo subdirectory still hits the repo-root override, and directories above the git root are never picked up by mistake. Without .git, lookup continues to the filesystem root. The tool output's source=override|package and root= lines make the actual hit observable.

When injected content exceeds 24k characters it is truncated at file boundaries: the cut only falls between files, never injecting half a file; skipped files can be derived from the full set under root minus the tool output's files list, and truncated=true carries the truncation marker.

Initializing the project template (plugin surface)

Initialization goes through the init_coding_kit tool (not the CLI init).

Conversation: Please initialize the coding-kit templates into this project → the model calls init_coding_kit.
Then edit .coding-kit/ and call apply_coding_standards again (source=override). init_coding_kit never overwrites existing files.

Note (asymmetric read/write roots, made explicit in 1.3.0): the read side (apply_coding_standards) looks up to the git root; the write side (init_coding_kit) still writes into the current working directory. Call init_coding_kit from a repo-root conversation, to avoid initializing in a monorepo subdirectory while the read side hits the repo root.

Some IDEs / yaml-language-server treat the root cordis.patch.yml as an RFC6902 JSON Patch and report missing op / path / value. This is a false positive and can be ignored; the file must keep the - insert form — do not convert it to JSON Patch.

Entry B · CLI (Cursor / Claude Code / CI)

P0 gates and G1–G7 (delivered in 1.2.0):

npx spec-wave init [--preset NAME] [--tools all|none|LIST] [--profile core|expanded] [--host-adapt|--no-host-adapt] [--yes]   # NAME vocabulary: harness-only (the only legal value)
npx spec-wave upgrade --yes
npx spec-wave refresh-ide-blocks [--target PATH] [--dry-run] [--yes] [--json]
npx spec-wave check
npx spec-wave verify --task <task.md> [--with-wiki-lint]   # pre-30 gate; since 2.3: review file must also carry a machine-readable passing conclusion (G2)
npx spec-wave verify --spec <SPEC.md>   # SPEC-to-00 review-existence gate (mutually exclusive with --task; --with-wiki-lint applies here too)
npx spec-wave verify   # bare mode (2.3+): repo-wide reviews scan over both review dirs — done tasks fail-closed, active tasks info-only; legacy exemptions via docs/harness/legacy-gate-exempt.yaml
npx spec-wave gate-check --task <task.md>
npx spec-wave audit --task <task.md>
npx spec-wave task lint --file <task.md>
npx spec-wave task close --file <task.md>
npx spec-wave status [--target] [--task] [--json] [--check]
npx spec-wave timeline --task FILE
npx spec-wave lifecycle show [--target PATH] [--json]
npx spec-wave lifecycle dry-run --transition ID --from STATE
npx spec-wave discipline show [--target PATH] [--json]
npx spec-wave graph yaml compile|check|export
npx spec-wave graph scaffold [--target PATH] [--yes] …   # draft tech-graph under docs/_tech_graph (reviewable, not signed truth)
npx spec-wave graph drift [--target PATH] [--input DIR] [--json]   # drift gate: module coverage + edge anchors (report only · no redraw)
npx spec-wave graph ib check [--target PATH] [--input DIR] [--json]   # node IB path gate: nodes[].implementedBy.path (no AST)
npx spec-wave graph indexes check [--target PATH] [--input DIR] [--json]   # opt-in · IB ↔ indexes bidirectional (needs .spec-wave/graph-indexes.yaml · not in default verify)
npx spec-wave graph ast check [--target PATH] [--input DIR] [--json]   # opt-in · symbol + bounded call (not a full callgraph · not in default verify)
npx spec-wave graph ingest|snapshot|axioms
npx spec-wave graph ontology check [--file PATH] [--json]   # + --hgm: instance check of the event-sourced graph against the bundled ontology
npx spec-wave sync index
npx spec-wave sync prompts [--target PATH] [--yes] [--force] [--json]
npx spec-wave skills install [--target DIR] [--out DIR] [--global] [--force] [--with-execute-hats]
npx spec-wave skills build [--with-execute-hats]
npx spec-wave skills check
npx spec-wave host validate [--file PATH] [--json]
npx spec-wave host apply --tools cursor,claude --profile core [--target PATH] [--file PATH] [--json] [--dry-run|--yes]
npx spec-wave host update [--tools LIST|all] [--profile core] [--target PATH] [--file PATH] [--json] [--dry-run|--yes] [--force]
npx spec-wave wiki export --json
npx spec-wave task lint-done
npx spec-wave task lint-wiki-delta
npx spec-wave task check --file PATH

host apply / host update sniff the host-adapt table version and optional @deepseek-ai/dsh-tools peer (U-01): mismatch → exit 2 and no writes (--json includes contract.status). --tools dsh keeps commands=[] (no .dsh/commands/) and lands orchestration as .dsh/skills/kit-*. host update without --tools uses sticky .coding-kit/host-tools.json (else exit 1). See Multi-host in one package above.

This source repo dogfoods graph yaml compile|check|export against docs/_tech_graph/ (not shipped in the npm package; https://github.com/Cyning12/SpecWave/tree/main/docs/_tech_graph).

Tech-graph scaffold (graph scaffold, planned 3.1): from a business-repo root, generates a reviewable draft under docs/_tech_graph/ (main graph · module table · primary flow · REVIEW_CHECKLIST.md). Default is dry-run; --yes writes. Output is draft-marked — not signed architecture truth (HG-GRAPH-MODULES remains for humans). Do not call it an “authoritative auto graph”.

Drift gate (graph drift, 3.1 W3 / 3.2 W2): checks module-table coverage and registered edge anchors (edges[].anchors[].path; skip TBD / empty); drift → exit 2. Optional .spec-wave/graph-drift.yaml: whitelist exemptions (missing file = full check) + optional struct_rel (module table path relative to --input; default 01_struct.md; bad path / illegal type fail-closed). Report only — does not redraw graphs.

Node IB path gate (graph ib check, 3.2 W1): checks nodes[].implementedBy.path exists under --target (skip empty / TBD case-insensitive; missing → exit 2 · missing_ib_path). Nodes without IB stay legal (checked=0 → exit 0). No symbol AST. Report only — no writes.

Indexes gate (graph indexes check, 3.2 W3 · opt-in): bidirectional IB ↔ indexes consistency when .spec-wave/graph-indexes.yaml is present (flow_globs / index_globs). Missing config → usage (exit 1). Not wired into default verify. Do not treat as a hard CI gate in Starter samples.

Symbol / bounded-call gate (graph ast check, 3.3 · opt-in): checks implementedBy.symbol presence plus same-path bounded references; cross-path edges stay non-red. Bounded call ≠ full callgraph. Not in default verify. Missing typescript peer → skip exit 0 (no_ts_peer). Does not replace a consumer-local full-dialect graph:ast-check. Starter CI samples may only add a commented optional step.

Fidelity split (drift / ib / indexes / ast): drift = edges + module table · ib = node paths · indexes = inverted-index opt-in · ast = symbol + bounded call opt-in (do not claim a full callgraph or that default verify already includes AST). Full table: docs/guides/使用手册-v3.0.0-zh.md §10. Consumer graph:ci / Python yaml → SpecWave CLI dual-stack (optional · no forced script deletion): MIGRATION.md.

Repo vocab extension (.spec-wave/graph-vocab.yaml, 3.1 W4): optional consumer file merged with the bundled assets/tech-graph-vocab.yaml on graph yaml compile|check|export. Declare extra edge_types (and/or kinds) so custom explicit edge types stop emitting the “未在 tech-graph 词汇登记档” Warning. Missing file = 3.0.2 builtin-only behavior. Bad YAML / schema / kind id+class conflicts with builtin → exit 2 (fail-loud, names the path/key). Registration is not a closed world: unregistered explicit types still Warning and do not fail the exit code. Diagnose with graph vocab show [--target PATH] [--json].

Graph capability vs. ontology layer (3.0 ONTO-OPEN ruling): the graph surface is open — graph yaml compile|check|export works on consumer-authored graphs today, and graph ontology check [--file PATH] validates the bundled ontology file or a drifted copy you point it at. The bundled ontology (assets/ontology.yaml) is SpecWave's self-use meta-model, however — 不提供自定义本体能力(the ontology layer is not open: no consumer-defined classes/relations; validator open ≠ ontology content open). Re-examination triggers (research doc §7.3): a real consumer request · re-evaluation after the ontology-check surface stays stable for one minor · post-B5 ecosystem pull — via an HG-SCHEMA-CHANGE-style human gate.

init / upgrade / sync index / skills build never overwrite the S2 process domain (docs/tasks/, docs/harness/reviews/, docs/harness/invokes/by-task/, plus legacy bare reviews/ / invokes/by-task/). S2 prefix truth is a single shared constant (S2_TRUTH_PREFIXES in cli-shared; F1 / 1.x MVP). sync prompts writes only the Starter whitelist under docs/harness/prompts/ (11 files) and docs/harness/templates/TASK_TEMPLATE.md — default dry-run; existing files with different content are listed as conflicts and are not overwritten unless you pass --force.

verify --with-wiki-lint (opt-in, non-breaking): appends the lint-wiki-delta check (default tier, scope=all) on top of the existing gates — effective in both --task and --spec modes. On a gap, verify is BLOCKED, lists the issues (which may come from sibling active/done tasks), and prints the exact same rerun command as PR CI: npx --yes spec-wave task lint-wiki-delta --target . (see assets/ci/samples/lint-wiki-delta.yml.example). --json gains a wiki_lint block (ok / issues / scanned). A target without docs/tasks/ directories scans 0 files and never false-blocks. Without the flag, verify behaves exactly as before.

Since 1.7.0 the graph-facing behavior of graph yaml export / graph yaml check is corrected: ① export writes graph_id from the yaml-declared value (data.graph_id, e.g. 00_main) as the single source of truth into graphs/nodes/edges, no longer the path-namespaced id (e.g. l0/00_main) — path ids remain input-compat only (--graph-id / file discovery); ② check --all filters graph.json slices with the same declared-value source as export output, so kit-produced root graph.json and check mutually recognize each other; ③ export preserves edge labels for every mark type (?> / ~> / ::… / […]) — topology-protocol marks are carried as edge attributes instead of dropping the label text; ④ the Mermaid class block emitted by compile is driven by nodes[].kind (flow/struct/external → phase/doc/infra), with id-based inference kept as a fallback for nodes without kind. Exit codes are unchanged. Consumer note: consumers depending on the old export output (namespaced graph_id / dropped labels) must re-run graph yaml export.

check compares manifest.version against the package version three ways (up-to-date / upgradeable / higher). Since 1.5.2, when the manifest carries a non-null from_version (i.e. it was migrated from the old @cyning/harness product line), a "higher" comparison reports a cross-product-line migration (@cyning/harness X → spec-wave Y — version numbers are not comparable across product lines) and suggests npx spec-wave upgrade --yes, instead of a misleading "possible downgrade" warning; since 1.7.0 this criterion