Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 69 additions & 20 deletions .claude/skills/shepherd/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ ephemeral; the files are the record.
`_design_feedback.md`, `_panel.json`, `_state.json`, `_progress.md`, `_design.approved`,
`_create_pr.approved`.
- Per iteration in `iter-N/`: `claim.md`, `review-<use>.md`, `final-review-<use>.md`,
`fulfillment.md`, and the regenerable (gitignored) `diff.patch`, `test-results.txt`
`fulfillment.md`, `followups.md`, and the regenerable (gitignored) `diff.patch`, `test-results.txt`
(plus `baseline.txt` and `predirty.txt` in `iter-1/` only — the pre-change oracle metrics
and any pre-existing dirty paths).

Expand Down Expand Up @@ -79,7 +79,8 @@ reliably type a slash-command. Surface everything they need into the conversatio
- Resolve `registry.base.json` plus optional `.shepherd/registry.json` `uses`.
- Validate every configured `use` against `registry.stage_roles` and `registry.uses`; no
duplicate `use` inside `reviewers` or `final_reviewers`. Single stages (`verify`,
`architect`, `implementer`, `success_criteria`, `fulfillment`) may be absent from config.
`architect`, `implementer`, `success_criteria`, `fulfillment`, `followups`) may be absent
from config.
- Record `oracle.commands`, limits, plan-mode setting, and the fully-resolved registry in
`_progress.md`.
- As each dispatched stage completes, append one ledger line to `_progress.md`: stage ·
Expand All @@ -97,8 +98,9 @@ Resume by phase:
- `phase=design-gate` without the marker → re-present the design + panel (step 4, Design gate) and wait.
- `phase=inner-loop`, `final-review`, or `review-run` → continue that phase.
- `phase=create-pr` + `_create_pr.approved` → go to step 9 (Finish).
- `phase=create-pr` without the marker → dispatch fulfillment first if the latest
`iter-N/fulfillment.md` is missing, then act on its verdict per step 7 (Fulfillment).
- `phase=create-pr` without the marker → dispatch either fulfillment or followups if its latest
artifact (`iter-N/fulfillment.md` or `iter-N/followups.md`) is missing, then act on their
verdicts per step 7 (Fulfillment).
- `phase=done` → the run is complete; report and stop.
- Otherwise, re-announce the stop being waited on and stop.

Expand Down Expand Up @@ -138,7 +140,13 @@ a comment the diff adds, edits, or moves must still be true of the code it now d
stale references, wrong claims, comments restating the obvious, and comments longer than the
code they describe are findings; also flag AI-slop — abnormal defensive try/catch (defensive
code at trust boundaries is fine), type-escape casts (`any` or equivalent), deep nesting that
should be early returns, and other patterns inconsistent with the surrounding file.
should be early returns, and other patterns inconsistent with the surrounding file. Also require
these three checks: a conditional branch or guard the diff adds must be test-exercised on both
sides, and a rewritten path must be exercised against the input classes the old path handled —
an untested new arm is a finding; a behavior delta versus design or base that the design leaves
unstated is a finding, including a changed helper whose default/no-arg semantics silently invert;
and whatever the diff names, places, or exports must follow the repo's stated conventions doc,
with a new module importing no heavier layer than its role needs.

| role | reads | do NOT read | writes | format |
|------|-------|-------------|--------|--------|
Expand All @@ -147,22 +155,23 @@ should be early returns, and other patterns inconsistent with the surrounding fi
| `architect` | `_user_request.md`, `1-triage.md`, `_request_fact_check.md`, `_codebase_map.md` if present, `_design_feedback.md` if present (settled human decisions — constraints, not suggestions), codebase; on a revision pass also its previous `2-design.md` | `3-success-criteria.md` | `2-design.md` | the design template in step 3 (Design) |
| `success_criteria` | pasted content of the "What we're solving" and "How it will work" sections of `2-design.md`, plus `_user_request.md`, `1-triage.md`, and `_request_fact_check.md` (verified facts — real paths, real coverage gaps — so criteria reference reality instead of guessing; it contains no solution) — nothing else | the rest of `2-design.md` (the solution), `claim.md` | `3-success-criteria.md` | numbered, testable criteria — each verifiable by a command or an observable behavior; no solution details |
| `implementer` | `2-design.md`, `3-success-criteria.md`, `_request_fact_check.md`, `_codebase_map.md` if present, all prior `iter-*/review-*.md` + `final-review-*.md` + `fulfillment.md` | — | source edits + `iter-N/claim.md` | what done · every finding fixed, none skipped or deferred · for a behavior change, add a regression test — ideally shown red before the fix and green after, with the red→green noted in `claim.md` — never weaken/delete tests |
| `reviewer` | pasted content of `2-design.md`, `3-success-criteria.md`, `iter-N/diff.patch`, `iter-N/test-results.txt`, plus the repository itself (working tree, git history, read-only commands) — no other `.shepherd/` files | `claim.md`, peer reviewers' output | `iter-N/review-<use>.md` | first line `VERDICT: PASS\|FAIL` (PASS = zero findings), then findings tagged `blocker\|major\|minor\|nit` |
| `reviewer` | pasted content of `2-design.md`, `3-success-criteria.md`, `iter-N/diff.patch`, `iter-N/test-results.txt`, plus the repository itself (working tree, git history, read-only commands) — no other `.shepherd/` files | `claim.md`, peer reviewers' output | `iter-N/review-<use>.md` | first line `VERDICT: PASS\|FAIL` (PASS = zero findings, `pre-existing`-tagged ones excepted), then findings tagged `blocker\|major\|minor\|nit`; a defect in adjacent code that predates the diff carries the extra tag `pre-existing` — reported, never silenced, routed to step 7 (Fulfillment + create-PR confirm) |
| `final_reviewer` | same as reviewer, but judging the post-fix integrated state: interactions with unchanged code, consumer/contract impact, doc/AGENTS staleness — not a second pass over the patch | `claim.md`, peer reviewers' output | `iter-N/final-review-<use>.md` | same verdict format as reviewer |
| `fulfillment` | pasted content of `3-success-criteria.md`, `iter-N/diff.patch`, `iter-N/test-results.txt`, `iter-N/claim.md`, plus the working tree (may run the non-mutating check a criterion names) | `2-design.md` solution details, review files | `iter-N/fulfillment.md` | first line `VERDICT: PASS\|FAIL`, then each criterion `MET \| NOT MET` with evidence |
| `followups` | pasted content of the design's "Scope split" section and of every `iter-*/review-*.md` + `final-review-*.md` (all iterations) | `3-success-criteria.md`, `claim.md` | `iter-N/followups.md` | ledger: item · origin (`scope-split` \| review file) · proposed disposition `fix-here \| issue \| pr-note \| drop` · one-line why; never empty — "none" explicitly |

### Model tiering

`"auto"` (the shipped default) lets the orchestrator pick a model per role and triage tier; an
explicit name (`opus`, `sonnet`, `haiku`) is used verbatim. Resolve `"auto"` as: `implementer` →
`haiku` (`sonnet` for `medium`/`large` — a subtle change is not transcription); `verify`,
`explorer`, `success_criteria`, `fulfillment`, `reviewer` → `sonnet`; `architect` → `opus`
`explorer`, `success_criteria`, `fulfillment`, `followups`, `reviewer` → `sonnet`; `architect` → `opus`
(`sonnet` for a revision pass — it folds feedback into an existing design without re-exploring);
`final_reviewer` → `opus` (`sonnet` for `trivial`/`small`). `sonnet` is the floor for review —
never `haiku`. Pre-gate stages (verify, explorer, architect, success_criteria) resolve `"auto"`
at dispatch time from this table. At step 4 (Design gate), record all picks in
`_panel.json`: the pre-gate ones as the record of what ran, the post-gate ones (implementer,
reviewers, final reviewers, fulfillment) for the human to edit before approving.
reviewers, final reviewers, fulfillment, followups) for the human to edit before approving.

## Procedure

Expand Down Expand Up @@ -204,8 +213,11 @@ switch) — every later stage reads that checkout. Then set `state.phase="verify

### 2. Verify — `phase=verify`

Run the `verify` stage on every run — never skipped by tier. It builds the authoritative claim
ledger in `_request_fact_check.md`: every claim in the request tagged
Run the `verify` stage on every run — never skipped by tier. On a fresh run whose archived
predecessor targets the same repo and base commit, verify may run in delta mode: re-check only
claims whose subject changed (new decisions, moved code, upstream PR state), re-affirming the
rest against the archived ledger with a citation — narrowed, never skipped. It builds the
authoritative claim ledger in `_request_fact_check.md`: every claim in the request tagged
`VALID | STALE | LIKELY-FIXED | UNVERIFIABLE` with evidence (running an existing test to verify
a claim is fine — remove artifacts it leaves). **For a review-only run the claim source is the
PR/branch description** (fetch it, e.g. `gh pr view`): tag each thing the PR says it does against
Expand Down Expand Up @@ -237,6 +249,7 @@ Otherwise set `state.phase="design"`.
## Proposed solution (implementation approach)
## Alternatives + the call
## Major changes (key files/areas only — never an exhaustive file list)
## Scope split (This PR · Prerequisite refactor · Follow-ups)
## Risks
## Open questions (real decisions only — each: options + recommended answer; no filler)
## Decisions (from _design_feedback.md when it exists; otherwise starts empty)
Expand All @@ -245,6 +258,17 @@ Otherwise set `state.phase="design"`.
Facts verifiable in the repo or issue belong in the design body, not Open questions — ask as
many decisions as the design needs, no minimum or maximum.

Scope split partitions the work: This PR (what the diff will contain), Prerequisite refactor
(restructuring the change needs — lands first, as its own PR, never as a commit inside the
main PR), Follow-ups (adjacent debt or gaps found during exploration that this PR
deliberately leaves). Before declaring Prerequisite refactor empty, check the repo's
refactor-separation policy (CLAUDE.md / CONTRIBUTING): where the repo mandates
refactor-lands-first, any "refactor first, then the change" structure IS a non-empty
prerequisite — calling it internal commit sequencing is a design defect. A non-empty
Prerequisite refactor is an explicit gate decision: surface it to the human and proceed only
on their confirmed choice — deliver the prerequisite first, or (only on the human's explicit
pick, never as the default) fold it in.

For a review-only run, `2-design.md` is the review scope: what to check and which reviewers.
- Dispatch the `success_criteria` stage: paste it ONLY the two product sections of the design
(plus request, triage, and the fact-check) and have it write `.shepherd/3-success-criteria.md`. It defines
Expand All @@ -255,8 +279,10 @@ Otherwise set `state.phase="design"`.
**Iterate — the conversation is the orchestrator's; every rewrite is a subagent's.**
- Present the FULL `2-design.md` + `3-success-criteria.md` (see "Keep the human in the loop").
- Grill decisions one question at a time (wait for each answer): options + your recommended
answer; product questions first, implementation after. Look up facts yourself; only decisions
go to the human. Walk dependencies in order — if Open questions miss a real fork, ask it.
answer; product questions first, implementation after. Look up facts yourself — including the
repo's conventions doc for any naming/signature/parameter question; a convention that settles
the question is a fact, not a human decision. Only decisions go to the human. Walk
dependencies in order — if Open questions miss a real fork, ask it.
YAGNI — cut speculative scope.
- **Batch a round of answers**, then append them verbatim to `_design_feedback.md`
(append-only; the orchestrator writes only this file, never the design or criteria).
Expand All @@ -277,15 +303,19 @@ Do not edit source files until `.shepherd/_design.approved` exists. Set
Propose the per-run review panel from the configured roster: start from the triage tier, adjust
for the actual design scope, and pick in config order unless the design's risk calls for a
specific reviewer. Two or more reviewers must differ in lens (e.g. diff-correctness vs
adversarial vs live-probe vs contract/consumer). **Resolve every `"auto"` model to a concrete name** (see Model
adversarial vs live-probe vs contract/consumer). At every human gate, present the panel with a
one-line lens-fit assessment per reviewer stating whether the lens is live for this design or
structurally muted (e.g. a complexity/deletion lens on a behavior-preserving move that forbids
cuts), and invite roster/model changes; the orchestrator never edits the panel itself, and a panel
change folds into the gate, not a new stop. **Resolve every `"auto"` model to a concrete name** (see Model
tiering) at the settled tier — inline on each reviewer, and in a `models` map for the single
stages (only those whose config model is `"auto"`; an explicit model keeps its name). Write
`.shepherd/_panel.json`:

```json
{ "tier": "small", "reason": "localized low-risk change",
"models": { "verify": "sonnet", "architect": "opus", "implementer": "haiku",
"success_criteria": "sonnet", "fulfillment": "sonnet" },
"success_criteria": "sonnet", "fulfillment": "sonnet", "followups": "sonnet" },
"reviewers": [{ "use": "staff-review", "model": "sonnet" }],
"final_reviewers": [{ "use": "thermonuclear", "model": "sonnet" }],
"inner_iterations": 2, "final_review_rounds": 1 }
Expand Down Expand Up @@ -346,8 +376,10 @@ For each iteration `N`:
`3-success-criteria.md`, `diff.patch`, and `test-results.txt`, plus read access to the
repository. They stay blind to `claim.md` and peer reviews.
6. Converge when the oracle is green and baseline-consistent and every reviewer verdict is PASS
— every finding gets fixed, whatever its severity: nits too; the implementer
never skips or defers one. The lone exception is the human's: a finding fixable only by
— every finding gets fixed, whatever its severity: nits too (`pre-existing`-tagged findings
skip the loop and route to the followups ledger at step 7 (Fulfillment + create-PR confirm));
the implementer
never skips or defers one. The other exception is the human's: a finding fixable only by
changing the approved design or criteria (see Hard rules). Otherwise iterate until
`inner_iterations`; then stop and present a findings table (fixed / open), the oracle
status, and the options: extend the limit, accept with open findings recorded, or abandon.
Expand All @@ -370,13 +402,24 @@ step 5 (Inner loop) convergence rule, set `state.phase="create-pr"`.

On entering `phase="create-pr"`, dispatch the `fulfillment` stage: it judges the diff, tests,
and claim against `3-success-criteria.md` and writes `iter-N/fulfillment.md` with each criterion
`MET | NOT MET`.
`MET | NOT MET`. Also dispatch the `followups` stage: it compiles the design's Scope split
leftovers and every `pre-existing`-tagged finding into `iter-N/followups.md` with a proposed
disposition per item.

- Any `NOT MET` criterion reopens the inner loop like a blocker finding, within the same limits.
When limits are exhausted, or the human disputes a criterion itself, ask the human: accept
with the exception recorded, extend the limit, or abandon.
- When fulfillment passes: no plan mode. Summarize in chat — the fulfillment table, oracle
status, reviewer verdicts, fixed findings, `git diff --stat`. Ask **"commit & open PR?"** and
- When fulfillment passes: no plan mode. Summarize in chat — the fulfillment table, the
followups ledger verbatim, oracle status, reviewer verdicts, fixed findings, `git diff --stat`.
The human dispositions each ledger item: `fix-here` reopens the inner loop; `issue` is created
only now, on this approval; `pr-note` lands in the PR body; `drop` is recorded in
`_progress.md`. Never silent; never an issue without approval. When every fix-here item is
doc/comment/style-only with no behavior or signature change (combined ≤10 lines), propose —
in the same gate exchange, with each option's cost — converging that fix round via ONE
delta-focused panel reviewer plus a fulfillment-delta check instead of the full panel; the
human's reply picks the mode, and any finding, oracle delta, or out-of-scope change in a
light round escalates back to the full step 5 (Inner loop) convergence rule. Ask
**"commit & open PR?"** and
proceed only on a clear yes, which records `_create_pr.approved`. Headless runs use
`/shepherd-approve-create-pr`. This approves creating the PR, not merging it.

Expand All @@ -402,7 +445,10 @@ from step 5 (Inner loop).
message, never enumerate changes obvious from the diff; evidence (fulfillment, oracle,
reviews) is one short clause, not a transcript; run files stay ignored. When the run
completes a tracked issue, end the PR body with `Closes #N` (auto-close on merge); reference
parent/epic issues non-closingly (`Part of #M`).
parent/epic issues non-closingly (`Part of #M`). Approved `pr-note` items land as a short
Follow-ups list in the body. Every number or factual claim in the body (test counts,
referenced files/issues) must match the final oracle run and repo state — a
stale count or nonexistent reference is a defect.
3. If a writable remote exists, push and open a PR. Record the evidence summary, approval
timestamps, and PR URL in `_progress.md`, then set `state.phase="done"`.

Expand Down Expand Up @@ -432,4 +478,7 @@ from step 5 (Inner loop).
or the human explicitly accepts the exception.
- A finding fixable only by changing the approved `2-design.md` / `3-success-criteria.md` is the
human's call — surface it at the gate; never edit an approved artifact to silence a finding.
- A design or review scope may downgrade severity or route a finding to follow-up; it
never instructs reviewers not to report a class of findings — adjacent pre-existing defects
are tagged, surfaced at the create-PR gate, and issues for them are created only on human approval.
- Commit/PR text: plain, PR-template-following, no obvious-from-the-diff narration (step 9, Finish).
3 changes: 2 additions & 1 deletion .claude/skills/shepherd/config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"required": ["stages"],
"properties": {
"stages": {
"description": "Engine and model assignments for each shepherd stage. Single stages (verify, architect, implementer, success_criteria, fulfillment) are optional: when absent, the built-in role table drives the stage without an engine.",
"description": "Engine and model assignments for each shepherd stage. Single stages (verify, architect, implementer, success_criteria, fulfillment, followups) are optional: when absent, the built-in role table drives the stage without an engine.",
"type": "object",
"additionalProperties": false,
"required": ["reviewers", "final_reviewers"],
Expand All @@ -17,6 +17,7 @@
"implementer": { "$ref": "#/$defs/singleStageValue" },
"success_criteria": { "$ref": "#/$defs/singleStageValue" },
"fulfillment": { "$ref": "#/$defs/singleStageValue" },
"followups": { "$ref": "#/$defs/singleStageValue" },
"reviewers": { "description": "Roster for inner-loop reviewers. The design gate selects a per-run subset.", "type": "array", "items": { "$ref": "#/$defs/stageValue" }, "minItems": 1 },
"final_reviewers": { "description": "Roster for post-convergence reviewers. May be empty.", "type": "array", "items": { "$ref": "#/$defs/stageValue" }, "minItems": 0 }
}
Expand Down
Loading
Loading