new
Start a dossier wave from a goal sentence; the sole entrypoint. Invoke when the user says "ds:new" or "start a dossier", or when work meets the start rule — more than one session, more than 5 files, or an operator step.
- License 许可
- ISC
- 最近更新
- 2026-11-13
- Stars
- ★ 3
- Forks
- 0
01 前言 Front Matter
- name
- new
- description
- Start a dossier wave from a goal sentence; the sole entrypoint. Invoke when the user says "ds:new" or "start a dossier", or when work meets the start rule — more than one session, more than 5 files, or an operator step.
- argument-hint
- "<goal sentence>" | <slug>
03 SKILL.md 正文
ds:new — start a wave
Creates .scratchpad/dossier/<YYYY-MM-DD>-<slug>/DOSSIER.md per ${CLAUDE_PLUGIN_ROOT}/FORMAT.md, then asks the operator for goal, scope and repos.
Inputs
"<goal sentence>"from$ARGUMENTS— the normal start. Runds:grill "<goal sentence>"first, then come back with the slug it confirms; step 1.5 consumes its draft. Skip the grill only when the goal is one line with no open decision, and derive the slug from it.<slug>(kebab-case, ≤30 chars) — the start after a grill, or for a backfill. Empty → ask for the goal sentence.- Date defaults to today (
date +%Y-%m-%d). Override by prompt when backfilling historical work.
Steps
0. Helpers
§S lines append via "${CLAUDE_PLUGIN_ROOT}"/cli/ds s-append <dir> "<event>" (FORMAT.md §15) — pass the text after the timestamp, which the script prepends; ds new-finish (step 5) writes the DONE line. The initial scaffold is a full Write (new file).
1. Validate slug + path
- Slug matches
^[a-z0-9][a-z0-9-]{0,29}$. Anything else is refused with an explanation. - Run
"${CLAUDE_PLUGIN_ROOT}"/cli/ds rootand computedir=<root>/.scratchpad/dossier/<date>-<slug>/from the path it prints. Every.scratchpad/path below is under that root. In a linked worktree with no ledger yet, the root is the primary checkout, so removing the worktree cannot delete the ledger. - Collision check:
direxists or.scratchpad/dossier/_archive/<date>-<slug>/exists (a same-day close+reopen) → ask the operator to bump to<slug>-2,<slug>-3, etc. Checking_archive/too avoids two INDEX rows keyed to one slug (Vm.1). - Ignore check: in a git work tree,
git -C <root> check-ignore -q .scratchpad/exiting 1 means the ledger will show as untracked and agit add -Awould commit it; any exit other than 0 or 1 means the check could not run, so say that. Carry the result into the step-6 report with the per-clone fix — append.scratchpad/to the filegit -C <root> rev-parse --git-path info/excludenames — and leave the choice to the operator; some repos track.scratchpad/on purpose.
1.5. Grill gate (conditional)
Fires only when a grill artifact exists for this slug, so trivial ds:new runs are untouched. <slug> is the RESOLVED slug from step 1 (post-collision-bump; a bumped <slug>-2 starts without <slug>'s grill):
"${CLAUDE_PLUGIN_ROOT}"/cli/ds assert-grill .scratchpad "<slug>"
The helper discovers the newest .grill/<date>-<slug>.md by slug — grill's own date may be days older than today (multi-day --resume, pending-external waits) and the gate still finds it. Route on the exact exit code:
| exit | meaning | action |
|---|---|---|
| 0 | complete (path printed) | consume its ## Draft §G/§C in step 2 — do NOT re-ask; after the step-3 Write lands, stamp via ds assert-grill --consume .scratchpad "<slug>" "<date>-<slug>" (atomic tmp+mv per Vm.8; refuses a double-consume) |
| 1 | no artifact | proceed normally — grill is never required; step 2's clarify lever recommends it |
| 2, 3 | artifact incomplete / unconfirmed | REFUSE scaffold; point at ds:grill --resume <slug> (or delete the artifact to abandon) |
| 4 | artifact already consumed | proceed normally; recommend a fresh ds:grill "<goal sentence>" — a consumed grill never feeds twice |
| 69, 70 | cli/ds did not run (69: no Node.js 22.18+; 70: internal error) |
REFUSE scaffold; report the stderr line |
A new slug does not bypass an open grill. When this session left a grill under another slug incomplete or unconfirmed, refuse the scaffold and point at ds:grill --resume <that slug>, unless the operator abandons it.
2. Gather inputs (operator-interactive)
Ask one block at a time, tersely, no preamble:
- §G goal — one-line outcome, then up to 5 scope bullets (IN / NOT IN).
- §C constraints — locked decisions, stack notes. Bullets, ≤10.
- §X repos — each repo this dossier touches, as
<org>/<name>or an absolute path. Operator-provided; no git-remote magic. - Initial §T tasks — ask for T1..Tn now; an empty answer leaves §T empty. Give a row
who=Honly after the agent tried to prove it in a scratch fixture (a throwaway directory, an isolated tmux socket, a disposable session) and could not. A re-check that waits on a date gets its own row with aT<n>+<k>dneed, sods close --carrycarries it; a row that joins it to work done now holds the wave open until the date.
A wide refactor is sequenced expand–contract. One mechanical change whose blast radius breaks many call sites at once (rename a column, retype a shared symbol) cannot land green as one task. Expand first: add the new form beside the old. Then migrate the call sites in batches, one task each, each needs the expand. Contract last: delete the old form in a task that needs every batch.
Clarify before freezing (the highest-value lever): an underspecified §G or §C decision — ambiguous scope, an unstated choice, more than one plausible approach — gets its resolving question NOW, before §T is authored. A vague goal yields vague tasks, and one or two sharp questions here beat a wrong build. More than a couple of open questions → recommend ds:grill <slug> (full interrogation protocol, artifact-gated). "Just go" → record the assumption as a §C bullet so it stays auditable.
§I, §V, §B, §S and §Z grow during the build; the scaffold leaves them empty.
2.5. Resolve pins (proactive verify)
From the stack named in §C plus the repos in §X, derive a pin-spec list and resolve current versions once (shared 24h cache, offline-safe):
"${CLAUDE_PLUGIN_ROOT}"/cli/ds resolve-pins eol:<slug>... <ecosystem>:<pkg>...
eol:results → §C bullets (current stable / EOL note).- A version, SHA or deprecation claim in §C that no spec covers →
dossier:verifychecks it against a primary source. - package results → the §I "Pinned deps" table (FORMAT.md §6).
- Map the libs actually named to specs (e.g. "Go backend + React UI" →
eol:go npm:react npm:react-dom go:<module>). The model does the stack→spec mapping; do not blind-parse §C prose into specs. {"offline": true}/latest: null, or exit 69 (no Node.js 22.18+) / 70 (internal error) → record the pin asofflineand proceed; the scaffold continues either way.go:<module>without a/vNsuffix names the v0/v1 path, so the resolver walks/v2through/v12and answers from the highest that resolves — pin the module path insrc, not the one you asked for. Awarningon the object means a probe went unanswered: the version is a floor, not the ceiling.
These fold into the single atomic step-3 Write — no extra commit, no TDD cycle.
2.6. Subtraction pass (ungrilled wave only)
Runs when step 1.5 exited 1 or 4 — no grill fed this wave, so no set audit or subtraction pass has seen it — and whetstone is installed. Spawn the subtraction pass (whetstone doubt-pass, "Subtraction pass": its template, its model rule) on the draft §G, §C and §T as the artifact, with §G as the contract. One cycle. Show each cut to the operator and ask which to take; a cut never edits a §C bullet the operator gave without that answer. Hold the SUBTRACT: line and append it to §S after step 3 as ds:new — subtract=<verdict>. Without whetstone, skip it and say so in the step-6 report.
2.7. Write the contract
The repo decides the home. .dossier/ exists → the repo opted into tracked contracts: write .dossier/<date>-<slug>.md and commit it before the first task — citable as evidence, outliving the wave. Otherwise write <wave-dir>/CONTRACT.md beside the ledger and price that home out loud: untracked wherever .scratchpad/ is gitignored (the assumed setup), archived with the wave, citable by nobody, and its criteria run as shell from a file no diff ever showed a reviewer — where a tracked contract's criteria appear in the commit that added them. Name the opt-in (mkdir .dossier, track it) so the choice stays the operator's. Never create .dossier/ yourself — a tracked directory appearing in a repo that did not ask for one is the artifact rule this split exists to respect.
Either way the content is FORMAT.md §2.5's — consumer, reached-via, budget, an optional milestone (the cutover row, when rows run after it), and a ## done-when table whose every row is a command with an expected exit code. ds:converge and the UserPromptSubmit hook resolve both homes, tracked first.
consumer is the field that asks whether the work reaches anyone, and the one nobody writes unprompted. Ask for it plainly: who runs this, and by what path does it get to them? A wave once hardened a checker through three review rounds while no consumer could execute it, and no step in this skill had ever asked. ds:converge refuses a contract whose consumer row is missing or empty (CONVERGE: PARSE, exit 2), so a contract written without the answer fails its first run.
A criterion that cannot be written as a command is a criterion nobody can check. Turn it into one, or drop it and say what was dropped.
A done-when command reads source and repo state only. It does not read a deployed target, a pushed remote, or anything that waits on an operator step. A runtime rewrite or an operator delay then fails the check. Put pushes, deploys and reloads in who=H rows. ds close --carry carries them as after: rows.
A §T row marked route=delegate adds the done-when row `<plugin>/cli/ds delegation-check <dossier-dir>` with exit 0 guard (it passes before any row is built), so ds:converge checks each delegated row's review and rebuild lines.
In the tracked home, commit the contract after the step-3.7 sign-off and before the first task — the UserPromptSubmit hook counts budget from the commit that added the contract.
3. Scaffold DOSSIER.md
Compute fields:
title = <slug>
header_line = `<date>` · `live`
Write the file at <dir>/DOSSIER.md per FORMAT.md §2 section order:
# <slug>
`<date>` · `live`
## Goal
<goal-from-step-2>
Scope:
<scope-bullets>
## Constraints
<constraint-bullets>
## Interfaces
_(empty — populate when first contract lands)_
## Invariants
| id | invariant | check |
|----|-----------|-------|
## Tasks
| id | state | who | task | needs | cite | verify |
|----|-------|-----|------|-------|------|--------|
<initial-tasks-if-provided>
## Bugs
| id | bug | root cause | invariant added | fix cite |
|----|-----|------------|-----------------|----------|
## Repos
| repo | branch | ahead | tag | pushed | notes |
|------|--------|-------|-----|--------|-------|
<repo-rows-from-step-2-with-placeholders>
## Status
<!-- Each entry is its own paragraph (blank lines before AND after). Per FORMAT.md §11. -->
<YYYY-MM-DD HH:MM:SS> ds:new — created slug=<slug>
## Closeout
_(empty — written by ds:close)_
Write <dir>/DOSSIER.md directly: the file is new, and step 3.5 catches a partial write.
3.5. Assert scaffold completeness
Before touching INDEX or §S, confirm the write landed intact:
"${CLAUDE_PLUGIN_ROOT}"/cli/ds assert-scaffold "<dir>"
It exits 1 naming any missing §-section (or the title line) — deterministic, so nobody eyeballs the Write output. On failure step 5 waits: report the missing sections, re-run the step-3 Write to repair, then re-assert. Mirrors the post-move assertion ds:close runs via ds archive-move. Exit 69 (no Node.js 22.18+) or 70 (internal error) means the assertion did not run: report its stderr line and stop before step 5.
3.6. Baseline the contract
A row that passes before the work cannot judge the work. Run every row once, now:
"${CLAUDE_PLUGIN_ROOT}"/cli/ds converge --baseline <contract-path>
BASELINE: OK (exit 0) appends ds:converge — baseline OK … to §S; then go to step 3.7. BASELINE: FAIL <ids> (exit 1) appends ds:converge — baseline FAIL <ids> to §S (nothing is written when no live wave owns the contract) and names each row that passed or did not run (exit 124, 126 or 127), or each guard row that failed: rewrite the row so it fails until the work lands (a script the wave has not written yet: test -f tools/x.ts && node tools/x.ts), or, for a row that must stay green throughout (a full CI run), end its expect cell with guard (exit 0 guard), then rerun. Which row is a guard is model-judgment; the baseline line lists every guard so the operator sees them. CONVERGE: PARSE (exit 2) is a contract to fix first.
3.7. Sign off the design
The sign-off judges the design before any build, from a notes file and the lines it cites, so it reads nothing else. One design covers one slice. This step signs off the wave's first slice. ds:build step 5.7 signs off each later slice before its build.
-
Write the first slice's design to
<root>/.scratchpad/tmp/<date>-<slug>/design-notes.md: the goal in the operator's words, each claim about current code with itspath:Ncite, a## done-whentable in the contract's shape (a row that must stay green ends its expect cell withguard), and oneREMOVES: <name>line per skill, file or command the wave deletes or renames. -
Run the computed checks until they pass:
"${CLAUDE_PLUGIN_ROOT}"/cli/ds design-check <notes> <repo>DESIGN: OK(exit 0) writes<notes minus .md>-evidence.mdwith every cited line.DESIGN: FAIL <n>(exit 1) names each cite that does not resolve, each check that passes today or did not run, and each file that names aREMOVES:item and is not in the notes: fix the notes and run it again.DESIGN: PARSE(exit 2) is a notes file to fix first. -
With
evidencein the session's agent list, spawn oneevidenceagent with the notes path, the evidence path, the repo path and the findings path below. It runs its own checks, then spawnssignoff, and returns thesignoffreply. Otherwise, withsignoffin the list, spawn onesignoffagent. The plugin ships neither: they are the operator's own agents (ADAPTERS.md). Asignoffagent may have no read tool, so put the full text of the notes file and the evidence file in its mission. Name a separate findings file for either agent,<root>/.scratchpad/tmp/<date>-<slug>/signoff-findings.md. Read the findings from that file, or from the reply when the file is empty (anevidenceagent that stops early writes its findings in the reply). There is one line per finding:block:ornote:, thenmissing: <what>, at <file:line or section>orevidence missing: <fact>, at <file:line>. Ablock:finding makes the build wrong or unsafe; every other finding is anote:. The reply ends withSIGNOFF: PASSwhen no line isblock:, elseSIGNOFF: CHANGES. Without either agent, the verdict isskipped-absent. -
Append §S
ds:new signoff=<PASS|CHANGES|skipped-absent> notes=<notes>, where<notes>is the design notes path from item 1, never the findings file:ds:buildhands it to the builder and the reviewer as the design. Put eachnote:line in the step-6 report as a follow-up. OnCHANGES, fix eachblock:line once, re-run item 2 (ds design-check), and ask for one re-check; a secondCHANGESgoes to the operator with both lists.
Then commit the contract (tracked home). Whether the sign-off is sound is model-judgment; that the line exists is code: step 5 exits 1 without it.
4. Initial §X refresh
For each repo row added in step 2, run:
"${CLAUDE_PLUGIN_ROOT}"/cli/ds x-refresh <dir> <repo-label> <repo-path>
When it refuses with not a git repo, the row keeps its placeholders plus the note _(repo not found — verify path)_.
5. Finish
"${CLAUDE_PLUGIN_ROOT}"/cli/ds new-finish <dir>
It exits 1 naming the missing line when §S has no ds:new signoff= line: run step 3.7. Otherwise it regenerates .scratchpad/INDEX.md, appends ds:new — DONE slug=<slug> dir=<dir> to §S, prints the ds handoff lines and exits 0.
6. Report
ds:new <slug> → .scratchpad/dossier/<date>-<slug>/DOSSIER.md
§X: <N> repos seeded
follow-ups: <each sign-off note: line, or none>
next:
<each handoff line step 5 printed, verbatim>
Add .scratchpad/ is not gitignored here plus the fix when step 1's ignore check fired.
Idempotency
<dir>/DOSSIER.md already exists → refuse; the operator picks a new slug or opens the existing one via ds:status.
<dir> exists with DOSSIER.md missing (a rare crash mid-scaffold) → recreate it, preserving any §S entries from the partial run.
Cite
- FORMAT.md §2 (section order), §2.5 (wave contract), §10 (§X format), §11 (§S format), §17 (Vm rules)
04 同仓库更多 Skills
suite-review
Run the monthly evidence review of this repo's plugin skills. Count each skill's opportunities and uses with the census, read what happened where a skill was not used, put each skill in one bucket, act, and write the actions as predictions with a check date. Use when the operator says "suite review" or "monthly review", or when the suite-review line on LATER.md is due.
tiger-style
Check the column budget of the lines a change adds, and read that change against the TIGER_STYLE shape rules a script cannot judge. Use when the user asks about line length or column limits, to check code shape, what the column check flagged, or why a commit was blocked on a column budget.
tdd-cycle
Drive one vertical slice of behaviour red-green-refactor, seam agreed before the first test. Use when the user asks to add a feature, fix a bug, write code test-first, says "TDD this", "red green refactor", or "write a failing test first". Inside a live dossier:build covenant, invoke dossier:build instead — it composes this skill's run-slice command as its RED/GREEN proof.
prototype
Build a throwaway prototype to answer a design question. Use when the user wants to sanity-check whether a state model or logic feels right, or explore what a UI should look like.
doubt-pass
Adversarial doubt cycle on a plan or design before any code exists — distinct from post-hoc code review. Use when the user asks to doubt this, stress-test a design before building it, poke holes in a plan, find the flaw in an approach, or before committing to a non-trivial architecture or design decision.
diagnose
Diagnose a hard bug or a performance regression with a feedback loop first, then ranked hypotheses, instrumentation and a regression test. Use when the user says diagnose or debug this, or reports something broken, throwing, failing or slow.