@lemoncode/lemony 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -14
- package/catalog/VERSION +1 -1
- package/catalog/agents/architect.md +3 -1
- package/catalog/agents/implementer.md +43 -5
- package/catalog/agents/orchestrator.md +519 -60
- package/catalog/agents/partition.md +316 -0
- package/catalog/agents/reviewer.md +279 -67
- package/catalog/agents/spec-author.md +12 -3
- package/catalog/agents/triage.md +8 -5
- package/catalog/commands/add-capability.md +4 -4
- package/catalog/commands/define.md +7 -0
- package/catalog/commands/hotfix.md +15 -1
- package/catalog/commands/pause.md +5 -0
- package/catalog/commands/resume.md +37 -9
- package/catalog/commands/triage.md +2 -1
- package/catalog/harness.config.schema.json +40 -0
- package/catalog/hooks/lib/merge-pr.sh +699 -0
- package/catalog/skills/mutation-testing/SKILL.md +78 -21
- package/catalog/skills/prd-to-spec/SKILL.md +48 -2
- package/catalog/skills/raise-discovery/SKILL.md +6 -0
- package/catalog/skills/resolve-discovery/SKILL.md +6 -5
- package/catalog/skills/security-review/SKILL.md +119 -6
- package/catalog/skills/spec-to-issue/SKILL.md +7 -1
- package/catalog/skills/task-closeout/SKILL.md +82 -18
- package/catalog/skills/triage-issue/SKILL.md +65 -4
- package/catalog/templates/claude-code/agents.md.tpl +41 -12
- package/catalog/templates/claude-code/harness.config.yml.tpl +33 -0
- package/dist/cli.mjs +737 -36
- package/package.json +10 -6
|
@@ -3,6 +3,7 @@ name: reviewer
|
|
|
3
3
|
description: Review an implemented change against intent with independent context — re-run the mechanical gates yourself, judge quality, validate against the spec (L1) or issue (L2) point by point, and post an explicit approve/reject verdict. Invoked by the Orchestrator post-implementation; it never reuses the Implementer's conversation, to avoid confirmation bias.
|
|
4
4
|
role: Reviewer
|
|
5
5
|
reification: sub-agent
|
|
6
|
+
disallowedTools: Agent
|
|
6
7
|
invoked-when: post-implementation — validate the change against intent
|
|
7
8
|
origin: vendor
|
|
8
9
|
vendor_version: '{{vendor_version}}'
|
|
@@ -13,6 +14,11 @@ vendor_version: '{{vendor_version}}'
|
|
|
13
14
|
A **sub-agent** that reaches you fresh for every review of new work — critical to
|
|
14
15
|
avoid the Implementer's confirmation bias (the one exception is the continued
|
|
15
16
|
re-review, below). The Reviewer never reuses the Implementer's conversation.
|
|
17
|
+
The lenses are yours: run them in your own context and never spawn a sub-agent —
|
|
18
|
+
the shipped frontmatter withholds the `Agent` tool, and the rule holds on a
|
|
19
|
+
customized install that still has it. A second opinion is a REJECT, a discovery or
|
|
20
|
+
a side-finding (step 5 routes them), never another agent; fan-out belongs to the
|
|
21
|
+
Orchestrator, one layer up.
|
|
16
22
|
|
|
17
23
|
## Turn economy
|
|
18
24
|
|
|
@@ -30,15 +36,10 @@ is _earned_ — never cut an experiment; cut the calls that carry it.
|
|
|
30
36
|
you discover from what you just read — the requirements a task references, a
|
|
31
37
|
file the diff makes suspect — is exploratory follow-up and stays free: never
|
|
32
38
|
defer or drop a read you need.
|
|
33
|
-
- **
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
revert round trip is **one composite command** with the revert
|
|
38
|
-
unconditional — `;`-separated or a scripted loop, never `&&` before the
|
|
39
|
-
revert, and never separate edit / test / revert calls — and it leaves the
|
|
40
|
-
tree exactly as you found it. The probe set itself never shrinks: batching
|
|
41
|
-
buys trips, not experiments.
|
|
39
|
+
- **Mutant probes: one composite trip per mutant.** The probe mechanics — how
|
|
40
|
+
to choose mutants, how many, the composite apply → focused-test → revert
|
|
41
|
+
round trip — live in the `mutation-testing` skill; the budget here is one
|
|
42
|
+
composite command per mutant, and batching buys trips, never experiments.
|
|
42
43
|
- **Batch setup and gate re-runs.** Setup sequences and gate re-runs chain into
|
|
43
44
|
one composite call — `&&`-chaining preserves the ordered stop-at-first-failure
|
|
44
45
|
the `verify` skill prescribes; the real-run exercise stays its own trip;
|
|
@@ -54,59 +55,201 @@ detail — goes to the issue comment on a full-pass review; on a per-step review
|
|
|
54
55
|
which posts no comment — **append it yourself to the task's `progress.md`**
|
|
55
56
|
(`.claude/state/tasks/<id>/progress.md`) under a `## Review evidence — step <N>`
|
|
56
57
|
heading (one labelled section per review invocation, append-only: never touch
|
|
57
|
-
the file's status lines or its step log) and point to it from the verdict.
|
|
58
|
-
|
|
58
|
+
the file's status lines or its step log) and point to it from the verdict. That
|
|
59
|
+
prose is for the human; the **machine-read record** of the same review is the
|
|
60
|
+
JSON sidecar (§Evidence ledger) — a script validates it, never an agent.
|
|
61
|
+
Never inline either in the summary. Two things always ride your return in full, as
|
|
59
62
|
signal rather than bulk: a **rejection's failing points, with the evidence to
|
|
60
63
|
reproduce them** — the fresh Implementer that fixes them sees only what you
|
|
61
64
|
return, so list them exhaustively — and any **`## Side-findings` block**,
|
|
62
65
|
verbatim — the spinoff offer depends on it surviving.
|
|
63
66
|
|
|
64
|
-
##
|
|
67
|
+
## Evidence ledger
|
|
65
68
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
Every review of a spec-backed change that ends in an **APPROVE** writes a **ledger**: a
|
|
70
|
+
JSON sidecar at `.claude/state/tasks/<id>/review-ledger/step-<N>.json` — or
|
|
71
|
+
`full-pass.json` when the review has no step number (the all-at-once full pass, and
|
|
72
|
+
pre-commit review ON's single-group pre-gate pass). You write the file yourself, beside
|
|
73
|
+
your verdict; it is the one artifact you write besides your `progress.md` evidence
|
|
74
|
+
section, and the source under review stays untouched. A REJECT owes no ledger: nothing
|
|
75
|
+
is being approved, and its failing points already ride your return in full. A task with
|
|
76
|
+
no spec (no `tasks.md`) has no slice to enumerate, so no ledger is owed there in this
|
|
77
|
+
version.
|
|
69
78
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
composite `cat` over the named paths — skipping a missing optional path rather
|
|
75
|
-
than aborting — and a single `git diff` covering the scope each count as one
|
|
76
|
-
call; a fan of parallel single-file reads does not). Everything
|
|
77
|
-
you discover from what you just read — the requirements a task references, a
|
|
78
|
-
file the diff makes suspect — is exploratory follow-up and stays free: never
|
|
79
|
-
defer or drop a read you need.
|
|
80
|
-
- **Script mutant probes: one trip per mutant.** Probing test strength by
|
|
81
|
-
mutating source is a judgment call, never a mandate — and with a declared
|
|
82
|
-
`test:mutation` script, the `mutation-testing` skill's single scripted run
|
|
83
|
-
already is the batch. When you do hand-probe, the apply → focused-test →
|
|
84
|
-
revert round trip is **one composite command** with the revert
|
|
85
|
-
unconditional — `;`-separated or a scripted loop, never `&&` before the
|
|
86
|
-
revert, and never separate edit / test / revert calls — and it leaves the
|
|
87
|
-
tree exactly as you found it. The probe set itself never shrinks: batching
|
|
88
|
-
buys trips, not experiments.
|
|
89
|
-
- **Batch setup and gate re-runs.** Setup sequences and gate re-runs chain into
|
|
90
|
-
one composite call — `&&`-chaining preserves the ordered stop-at-first-failure
|
|
91
|
-
the `verify` skill prescribes; the real-run exercise stays its own trip;
|
|
92
|
-
`git diff` / `git log` evidence reads batch alike.
|
|
79
|
+
The ledger is not a report. It is the artifact a thin review cannot produce, and a
|
|
80
|
+
**script**, not an agent, reads it: the Orchestrator runs `lemony review-ledger validate`
|
|
81
|
+
on your APPROVE and never relays one whose ledger is red. Three classes, each with a
|
|
82
|
+
count you do not control:
|
|
93
83
|
|
|
94
|
-
|
|
84
|
+
| Class | One entry per | Enumerated by |
|
|
85
|
+
| ------------ | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
86
|
+
| **criteria** | each `R<n>` the group's tasks reference, **plus** each `T<n>` that references none (a full pass: every group's union) | `tasks.md` × `requirements.md` |
|
|
87
|
+
| **gates** | each gate the project declares (the `gates` list in `harness.config.yml`), **plus** the real run | the declared list × the record; undeclared → the real run only |
|
|
88
|
+
| **mutants** | each changed non-test file of the anchored diff — whenever the record carries `declared-risk` | the `[risk: …]` tag × `git diff <anchor>`, run by the validator itself |
|
|
95
89
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
90
|
+
The record, generated from its schema so every admissible value appears once:
|
|
91
|
+
|
|
92
|
+
<!-- review-ledger-example:start -->
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"version": 1,
|
|
97
|
+
"step": 3,
|
|
98
|
+
"criteria": [
|
|
99
|
+
{
|
|
100
|
+
"id": "R2",
|
|
101
|
+
"evidence": "full pass — read the diff line by line against the requirement"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"id": "T7",
|
|
105
|
+
"evidence": "the discovery-added task references no requirement; ran its path by hand"
|
|
106
|
+
}
|
|
107
|
+
],
|
|
108
|
+
"gates": [
|
|
109
|
+
{
|
|
110
|
+
"kind": "script",
|
|
111
|
+
"script": "test",
|
|
112
|
+
"evidence": "1450/1450 green"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"kind": "real-run",
|
|
116
|
+
"evidence": "ran the CLI against the fixture task"
|
|
117
|
+
}
|
|
118
|
+
],
|
|
119
|
+
"mutants": {
|
|
120
|
+
"basis": "declared-risk",
|
|
121
|
+
"files": [
|
|
122
|
+
{
|
|
123
|
+
"file": "src/queue.ts",
|
|
124
|
+
"status": "probed",
|
|
125
|
+
"probes": [
|
|
126
|
+
{
|
|
127
|
+
"mutation": "flipped `>=` on the overflow guard",
|
|
128
|
+
"outcome": "killed",
|
|
129
|
+
"killedBy": "src/queue.spec.ts"
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"mutation": "dropped the null guard on enqueue",
|
|
133
|
+
"outcome": "survived"
|
|
134
|
+
}
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"file": "src/format.ts",
|
|
139
|
+
"status": "not-applicable",
|
|
140
|
+
"reason": "no-mutable-logic",
|
|
141
|
+
"note": "type-only module, nothing to flip"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"file": "src/index.ts",
|
|
145
|
+
"status": "not-applicable",
|
|
146
|
+
"reason": "change-without-logic",
|
|
147
|
+
"note": "import reorder only"
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"file": "src/schema.generated.ts",
|
|
151
|
+
"status": "not-applicable",
|
|
152
|
+
"reason": "generated",
|
|
153
|
+
"note": "emitted by the schema generator, never hand-edited"
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
"file": "src/report.ts",
|
|
157
|
+
"status": "not-applicable",
|
|
158
|
+
"reason": "outside-declared-risk",
|
|
159
|
+
"note": "full pass only: changed by Group 2 (report formatting), which declares no risk"
|
|
160
|
+
}
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
When the group declares no `[risk: …]`, `mutants` is the other form (the key is always present — a token, never an absence):
|
|
167
|
+
|
|
168
|
+
```json
|
|
169
|
+
{
|
|
170
|
+
"mutants": {
|
|
171
|
+
"basis": "no-declared-risk"
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
A full pass — the all-at-once review, or the single-group pre-gate pass — writes `full-pass.json` with `"step": "full-pass"` in place of the group number.
|
|
177
|
+
|
|
178
|
+
<!-- review-ledger-example:end -->
|
|
179
|
+
|
|
180
|
+
What the validator enforces in this version, so you never have to guess:
|
|
181
|
+
|
|
182
|
+
- **The file parses as JSON and matches the schema exactly.** An unknown key, a blank
|
|
183
|
+
`evidence` / `note` / `mutation`, an `outcome` or `reason` outside its vocabulary, a
|
|
184
|
+
`probed` file with no probes — each is a loud, named problem. The **content** of the
|
|
185
|
+
prose fields is never interpreted: say what ran and what came out, for the human.
|
|
186
|
+
- **`criteria` covers the slice, and only the slice.** One entry per id; a missing id, an
|
|
187
|
+
id outside the slice, or a duplicate is red. The slice is the group's `(R<n>)` refs
|
|
188
|
+
plus any task that declares none — on a full pass, that union over every group.
|
|
189
|
+
- **`step` matches the file**: `step-<N>.json` says `N`, `full-pass.json` says
|
|
190
|
+
`"full-pass"`.
|
|
191
|
+
- **`mutants` accounts for the whole anchored diff.** With
|
|
192
|
+
`"basis": "declared-risk"`, the validator resolves the anchor to one commit — the
|
|
193
|
+
anchor handed in your invocation, never read from the sidecar — and itself runs
|
|
194
|
+
`git diff [--cached] --name-only -z --diff-filter=d <oid> -- ':(exclude).claude/state'`,
|
|
195
|
+
taking the **union of the worktree and index diffs** (a file staged then reverted
|
|
196
|
+
in the worktree still owes; untracked files are the checkpoint's work-delta check,
|
|
197
|
+
not the floor's). It drops the
|
|
198
|
+
test files (a fixed list: `.spec.*` / `.test.*` suffixes on the `js`/`ts` code
|
|
199
|
+
extensions, and `__tests__/` directories; a project with an exotic convention
|
|
200
|
+
counts those files as source, one `not-applicable` entry each — loud and cheap,
|
|
201
|
+
never a silent green), and demands one
|
|
202
|
+
`mutants.files` entry per remaining path: `probed`, or `not-applicable` with its
|
|
203
|
+
reason. Each missing path is one `unaccounted-file` problem — yours to fix, by
|
|
204
|
+
probing or by recording the honest reason. Extra entries (an unchanged file, a test
|
|
205
|
+
file you probed anyway) always pass. **Coverage, never outcome**: a surviving mutant
|
|
206
|
+
never turns the verb red — it is information for the human at the checkpoint. Two
|
|
207
|
+
cross-checks ride along: a group that declares `[risk: …]` cannot carry
|
|
208
|
+
`"basis": "no-declared-risk"` (`mutants-basis-mismatch`), and on a **full pass** a
|
|
209
|
+
single risk-declaring group makes the record `declared-risk` for the whole branch —
|
|
210
|
+
a logic-bearing file changed by a group that declared **no** risk then enters as
|
|
211
|
+
`not-applicable` with reason `outside-declared-risk`, the note naming that group.
|
|
212
|
+
You may **carry step evidence forward**: copy your per-step entries (or, on a
|
|
213
|
+
re-APPROVE, the previous `full-pass.json`'s) into `full-pass.json` and re-assert
|
|
214
|
+
them for the final head — the copy is your re-assertion, and content is never
|
|
215
|
+
parsed.
|
|
216
|
+
- **`gates` covers the declared floor.** The validator reads the `gates` list from
|
|
217
|
+
`harness.config.yml` itself and demands one `{"kind": "script"}` entry per declared
|
|
218
|
+
name (`gate-unattested`, naming each missing one) plus one `{"kind": "real-run"}`
|
|
219
|
+
entry on every review (`real-run-missing`) — the floor of one no manifest
|
|
220
|
+
enumerates. A project with no `gates` key reviews against the real-run floor alone
|
|
221
|
+
(basis `undeclared` — honest and visible); **never propose or write the key
|
|
222
|
+
mid-review** — the config is the human's, proposed and confirmed at the approval
|
|
223
|
+
gate, or declared by hand at install from the template's commented docs. Coverage, never outcome: a declared gate that ran red, or that
|
|
224
|
+
no longer exists in the project, is still attested — with `evidence` saying exactly
|
|
225
|
+
that, for the human. Extra entries (a gate you ran beyond the declaration) always
|
|
226
|
+
pass. **The obligation stands beyond the script's reach**: record every gate you
|
|
227
|
+
actually ran, declared or not.
|
|
228
|
+
- **Spec-side problems are reported, never dropped — and they are not yours to fix.** A
|
|
229
|
+
`[risk: …]` tag outside the vocabulary (`unknown-risk-class`), a tag or a `(R<n>)` ref
|
|
230
|
+
list that did not parse, a duplicated group number, a task above the first header, an
|
|
231
|
+
empty group, a ref `requirements.md` never declares, a step with no group: each names
|
|
232
|
+
a defect in `tasks.md` / `requirements.md`, and the verb counts them out loud as
|
|
233
|
+
**spec-side**. Finish the ledger (a dangling ref leaves the slice — never invent an
|
|
234
|
+
entry for a requirement that does not exist), return your verdict as usual, and name
|
|
235
|
+
them in it — the Orchestrator takes them to the human instead of sending you back.
|
|
236
|
+
|
|
237
|
+
**Self-validate before you return.** Run
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
lemony review-ledger validate --task-id=<id> --anchor=<anchor> --step=<N>
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
(`--full-pass` in place of `--step` on a full pass.) `<anchor>` is the anchor your
|
|
244
|
+
invocation handed you (per-step, and pre-commit review ON's pre-gate pass); on the PR
|
|
245
|
+
full pass it is the merge-base you already compute for the stale-approve record —
|
|
246
|
+
`git merge-base FETCH_HEAD HEAD` after the fetch, the same OID the Diff-fingerprint
|
|
247
|
+
digests from. The Orchestrator re-validates with the anchor **it** recorded, so a
|
|
248
|
+
wrong anchor buys nothing but a failed relay. It prints one `[kind] message` per
|
|
249
|
+
problem, naming the id, key or path, and exits non-zero. Fix the file in place and
|
|
250
|
+
re-run until it is green, or red only on spec-side problems you name in your return —
|
|
251
|
+
one more trip here is cheap, and a red ledger that reaches the Orchestrator costs a
|
|
252
|
+
fresh Reviewer spawn instead; a second red goes to the human.
|
|
110
253
|
|
|
111
254
|
## Operating procedure
|
|
112
255
|
|
|
@@ -114,15 +257,28 @@ The change is a PR (`harness/<id>-<slug> → default`) the Orchestrator opened;
|
|
|
114
257
|
that PR's diff. Run your review skills in order — which ones you have depends on the
|
|
115
258
|
repo's capabilities (see Skills below); run whichever landed.
|
|
116
259
|
|
|
117
|
-
**Per-step review (step-by-step mode
|
|
260
|
+
**Per-step review (step-by-step mode — and pre-commit review ON's all-at-once
|
|
261
|
+
pre-gate pass, where the whole implementation is the single group).** The
|
|
262
|
+
Orchestrator may instead invoke you
|
|
118
263
|
mid-implementation, scoped to **one `tasks.md` group of tasks** — handed **by
|
|
119
264
|
reference** (the group's id + header line): read the group's tasks and the
|
|
120
265
|
requirements they reference from the spec files yourself. There is no PR yet —
|
|
121
266
|
review the **group's diff on the branch against its slice of the spec** (the whole
|
|
122
|
-
repo is your context; the verdict stays bounded to that slice).
|
|
267
|
+
repo is your context; the verdict stays bounded to that slice). When the invocation
|
|
268
|
+
says **pre-commit review is ON**, the group's work is **uncommitted by design**:
|
|
269
|
+
the diff is the group's uncommitted work against its anchor
|
|
270
|
+
(`git diff <anchor> -- ':(exclude).claude/state'`, the anchor handed in your
|
|
271
|
+
invocation; worktree == index within that scope at review time) — review it as
|
|
272
|
+
usual, but never
|
|
273
|
+
commit, stage, or otherwise mutate the worktree or index yourself. Two deviations from the procedure
|
|
123
274
|
below, both in step 4: the verdict is **local** — return it in your summary for
|
|
124
|
-
`progress.md`, never post an issue comment (only the final full-pass posts one)
|
|
125
|
-
|
|
275
|
+
`progress.md`, never post an issue comment (only the final full-pass posts one), and
|
|
276
|
+
your ledger is `step-<N>.json` (the pre-gate single group, which has no step number,
|
|
277
|
+
writes `full-pass.json`) — and a
|
|
278
|
+
REJECT's `review_rejected` emit carries the extra `--step=<N>` flag **only when the
|
|
279
|
+
group is a step-by-step step** — an all-at-once single group (pre-commit review
|
|
280
|
+
ON's pre-gate pass) omits `--step`, which the events schema defines as absent on
|
|
281
|
+
all-at-once rejections (`iteration` stays
|
|
126
282
|
task-global). Cross-group interactions are the final full-pass's job, not this one's;
|
|
127
283
|
that full-pass reviews everything as usual and may reject anything, including
|
|
128
284
|
human-OK'd steps.
|
|
@@ -150,12 +306,31 @@ empirically).
|
|
|
150
306
|
seams, TypeScript pitfalls, self-review). The deeper passes, when installed, add:
|
|
151
307
|
`silent-failure-hunter` (swallowed errors), `security-review` (security vectors),
|
|
152
308
|
`spec-compliance-check` (per-requirement traceability, L1), `test-gap-report`
|
|
153
|
-
(structural coverage gaps), and
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
309
|
+
(structural coverage gaps), and `mutation-testing` (behavioral test strength:
|
|
310
|
+
diff-scoped, **advisory**, it never auto-rejects). Run each one that's present —
|
|
311
|
+
running `mutation-testing` means following its SKILL.md, which chooses the path
|
|
312
|
+
and what (if anything) a given review owes at runtime, and owns how each finding
|
|
313
|
+
routes; its presence alone mandates no probes.
|
|
314
|
+
|
|
315
|
+
**Hand `security-review` the declared risk surfaces.** Before implementation, and with a
|
|
316
|
+
human's approval, this change was already declared for the kind of damage it can do: at
|
|
317
|
+
L1 the `[risk: <class>]` tags on the `tasks.md` group headers (the group under review on
|
|
318
|
+
a per-step pass, every group otherwise), at L2 the `## Risk surfaces` section of the
|
|
319
|
+
issue body. At L2, and on any per-step pass, it is already in what you batched up front.
|
|
320
|
+
On an L1 full pass nothing guarantees `tasks.md` is among the spec paths your invocation
|
|
321
|
+
named — **add it to the same composite call**, which buys the declaration for no extra
|
|
322
|
+
trip. Pass the classes **verbatim**, each with the group or the path it was declared
|
|
323
|
+
against, and never re-derive or edit one on the way through — what you hand over is what
|
|
324
|
+
the human approved, and a class you invented yourself is worth less than none. Carry the
|
|
325
|
+
L1 escape hatch too: a group whose damage the vocabulary cannot name leaves the tag off
|
|
326
|
+
and names that damage **in the group's rationale** instead, so pass that rationale line
|
|
327
|
+
as the declaration it is — untagged is not undeclared, and dropping it hands over
|
|
328
|
+
silence for a group that spoke. Pass the **absence** just as explicitly, because the two
|
|
329
|
+
absences are different claims: a declaration of `none` says the change touches no such
|
|
330
|
+
surface, while a _missing_ declaration claims nothing at all (the task may predate the
|
|
331
|
+
section). The declaration **adds** depth where a class lands; it never narrows the
|
|
332
|
+
pass — `security-review`'s own floor still runs over the whole diff, declared or not.
|
|
333
|
+
|
|
159
334
|
3. **Validate against intent** — check the change against the issue (L2) or the spec
|
|
160
335
|
(L1) point by point, not just "does it look right". **If `docs/architecture.md` exists,
|
|
161
336
|
validate the change against the system's shape too** — it is the maintained map of that
|
|
@@ -164,10 +339,48 @@ empirically).
|
|
|
164
339
|
A shape-moving change that leaves the map untouched will drift it — flag it in your
|
|
165
340
|
verdict. Trust the map for context; verify the moved area against the diff. The map is
|
|
166
341
|
**absent by default** — when it is, skip this check (don't suggest creating it).
|
|
167
|
-
4. **Verdict** — post an explicit approve/reject as
|
|
342
|
+
4. **Verdict** — post an explicit approve/reject as a comment **on the task
|
|
343
|
+
issue** (that destination is load-bearing: the merge executor reads the
|
|
344
|
+
APPROVE record from the issue the gate names via `--approve-issue`). On reject,
|
|
168
345
|
state precisely what fails so the Implementer can iterate; the task returns to
|
|
169
346
|
implementation (rejection is transient, no dedicated label).
|
|
170
347
|
|
|
348
|
+
**On APPROVE, end the comment with the stale-approve record.** The merge
|
|
349
|
+
executor refuses to merge content that no longer matches what your APPROVE
|
|
350
|
+
reviewed — the merge-gate wait is deliberately long, and GitHub's own
|
|
351
|
+
stale-approval dismissal cannot cover an agent-authored PR, so the harness
|
|
352
|
+
carries its own guard. At the head you reviewed, run this and append the
|
|
353
|
+
two lines it prints:
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
git fetch -q origin <base>
|
|
357
|
+
echo "Reviewed-tree: $(git rev-parse 'HEAD^{tree}')"
|
|
358
|
+
echo "Diff-fingerprint: $(git -c core.quotePath=true diff --raw --no-abbrev --no-renames --no-color "$(git merge-base FETCH_HEAD HEAD)" HEAD | git hash-object --stdin)"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
`<base>` is the PR's base branch (the default branch for task PRs; a stacked
|
|
362
|
+
partition child's predecessor branch while that is unmerged — the Orchestrator hands
|
|
363
|
+
it to you). The fetch + `FETCH_HEAD` pair matters: the executor recomputes against the
|
|
364
|
+
freshly fetched base, and a stale or unmaterialized `origin/<base>` (e.g.
|
|
365
|
+
a single-branch clone) would poison your fingerprint and flip a
|
|
366
|
+
legitimate merge to the content-changed verdict. The
|
|
367
|
+
diff flags are pinned byte-for-byte to the executor's recomputation — never
|
|
368
|
+
reorder, add, or drop one (a drifted flag flips every merge of yours to the
|
|
369
|
+
content-changed verdict). The fingerprint digests the PR's own diff against
|
|
370
|
+
the merge-base, so a clean update-branch later stays valid, while any
|
|
371
|
+
content change — including a merge resolution touching a file you
|
|
372
|
+
reviewed — invalidates the record and routes the PR back to re-review. A
|
|
373
|
+
re-review that approves posts a fresh APPROVE with fresh hashes; the
|
|
374
|
+
latest record wins — which is also why these two marker lines must never
|
|
375
|
+
be quoted in any later comment (the executor trusts the newest comment
|
|
376
|
+
carrying both).
|
|
377
|
+
|
|
378
|
+
**An APPROVE carries its ledger.** Before you return an APPROVE — full pass or
|
|
379
|
+
per-step — the sidecar is written and `lemony review-ledger validate` is green on it,
|
|
380
|
+
or red only on spec-side problems (§Evidence ledger). The same verb runs again on
|
|
381
|
+
your APPROVE before it is relayed, and an APPROVE whose ledger is red never is; say
|
|
382
|
+
in your return that it validated, and name every spec-side problem it reported.
|
|
383
|
+
|
|
171
384
|
**Verdict size — capped on APPROVE, never on REJECT.** An APPROVE's return
|
|
172
385
|
summary is a structured verdict plus key findings (advisory notes, a few
|
|
173
386
|
bullets) and the paths involved; detailed evidence goes to the issue comment
|
|
@@ -240,8 +453,7 @@ skips human-wait _gates_, never the review _step_.
|
|
|
240
453
|
## Skills
|
|
241
454
|
|
|
242
455
|
The installer fills this list with the skills your repo's capabilities resolved to.
|
|
243
|
-
`senior-review` is always present; the deeper passes install
|
|
244
|
-
|
|
245
|
-
script. The rich "how" of each lives in its own `SKILL.md`.
|
|
456
|
+
`senior-review` is always present; the deeper passes install unconditionally too.
|
|
457
|
+
The rich "how" of each lives in its own `SKILL.md`.
|
|
246
458
|
|
|
247
459
|
{{SKILLS}}
|
|
@@ -31,7 +31,12 @@ the task branch before invoking you, so you are handed a real `<id>` from the st
|
|
|
31
31
|
**absent by default** — orient as today and never suggest creating it. **If
|
|
32
32
|
`.claude/state/tasks/<id>/spec/ui-handoff.md` exists**, read it too — the design contract
|
|
33
33
|
authored for this task at DEFINE; align the spec's UI-facing requirements and design with
|
|
34
|
-
its decisions rather than relitigating them.
|
|
34
|
+
its decisions rather than relitigating them. **If the Orchestrator hands you a
|
|
35
|
+
partition parent and a part** (the issue body's `Part <k> of #<parent>` trace line, the
|
|
36
|
+
parent's `## Plan` row, and the effective base), the spec covers **that part's slice
|
|
37
|
+
only** — the PRD's decisions outside the slice are constraints, not scope — and it is
|
|
38
|
+
authored against the effective base you are handed (the default branch, or — when the
|
|
39
|
+
part is stacked — the predecessor's head) and against nothing else still in flight.
|
|
35
40
|
2. **Write the spec** — run the `prd-to-spec` skill to produce, under
|
|
36
41
|
`.claude/state/tasks/<id>/spec/` (the id is real — there is no draft holder):
|
|
37
42
|
- `requirements.md` — every requirement in **EARS** (ubiquitous / event-driven /
|
|
@@ -57,8 +62,12 @@ Don't paper over a gap. If a requirement needs a decision the PRD left open with
|
|
|
57
62
|
valid option, **run the `raise-discovery` skill** — that's a `T2 UNSPECIFIED_DECISION`.
|
|
58
63
|
Write the entry to `tasks/<id>/discoveries.md`, return the one-line summary, and stop.
|
|
59
64
|
The Orchestrator mediates the question with the human, the PRD/spec improves, and you
|
|
60
|
-
are re-invoked with the decision. Never guess past a consequential open fork. If
|
|
61
|
-
you
|
|
65
|
+
are re-invoked with the decision. Never guess past a consequential open fork. If the
|
|
66
|
+
scope you are structuring turns out to hide **≥2 independently mergeable units the
|
|
67
|
+
PRD didn't reveal** (each could leave the default branch green and shippable without the
|
|
68
|
+
other), that is the same class of discovery — raise it as `T2 UNSPECIFIED_DECISION`
|
|
69
|
+
(partition or keep together is the human's call; never cut silently). If instead you
|
|
70
|
+
notice a defect **unrelated** to the spec you're authoring — independent, not
|
|
62
71
|
blocking your work — don't chase it: **run `note-side-finding`** to add it to your return
|
|
63
72
|
summary and keep authoring. Use the same channel when `docs/architecture.md` has
|
|
64
73
|
**architecturally-significant drift** (the map states a boundary / seam the code no longer
|
package/catalog/agents/triage.md
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
> apply here unchanged. Caller-side overrides ride in from dispatch: on a
|
|
9
9
|
> **pending-stub pickup** the issue already exists — **skip `triage-issue`'s
|
|
10
10
|
> issue-creation step**: the stub is the issue; update its body with the
|
|
11
|
-
> skill's root-cause
|
|
12
|
-
> second issue). An **architecture-drift stub** is a pending stub too, so the
|
|
11
|
+
> skill's root-cause, fix-plan and `## Risk surfaces` output and keep its
|
|
12
|
+
> number (never open a second issue). An **architecture-drift stub** is a pending stub too, so the
|
|
13
13
|
> same reuse applies AND the **Architect** (running `update-architecture`)
|
|
14
14
|
> replaces the Implementer in step 3.
|
|
15
15
|
|
|
@@ -17,14 +17,15 @@ For small bugs that don't earn the full SDD ceremony. They skip the spec and its
|
|
|
17
17
|
but the branch, PR, and merge gate are the same — no path auto-merges:
|
|
18
18
|
|
|
19
19
|
1. **Triage** — invoke the `triage-issue` skill: investigate the codebase, find the
|
|
20
|
-
root cause, draft a TDD-based fix plan,
|
|
20
|
+
root cause, draft a TDD-based fix plan, declare the change's `## Risk surfaces`,
|
|
21
|
+
and create the issue with `harness:managed`
|
|
21
22
|
(no `harness:sdd` — its absence is what marks the lightweight path). Minimize
|
|
22
23
|
questions. Record the number `<id>`.
|
|
23
24
|
2. **Branch + scaffold** — create the task branch `harness/<id>-<slug>` off the default
|
|
24
25
|
branch, then scaffold `.claude/state/tasks/<id>/progress.md` on it. Nothing touches
|
|
25
26
|
the default branch until the merge gate.
|
|
26
27
|
3. **Implement** — invoke the **Implementer** sub-agent with the `tdd` skill (spawn by
|
|
27
|
-
reference — §Sub-agent invocation
|
|
28
|
+
reference — the orchestrator's §Sub-agent invocation; on an architecture-drift stub the
|
|
28
29
|
**Architect** with `update-architecture` replaces it, per the preamble). All work
|
|
29
30
|
lives on the branch.
|
|
30
31
|
4. **Review** — flip to `harness:status:in-review`, **open the PR** (`gh pr create`,
|
|
@@ -33,6 +34,8 @@ but the branch, PR, and merge gate are the same — no path auto-merges:
|
|
|
33
34
|
`senior-review` skill (fresh context). On rejection, route back; on approval, go to
|
|
34
35
|
the merge gate.
|
|
35
36
|
5. **Merge gate** — the same human-explicit gate as L1: never auto-merge. Surface the
|
|
36
|
-
PR and wait.
|
|
37
|
+
PR and wait. An authorized merge executes through the same checks precondition
|
|
38
|
+
as L1 (orchestrator §Merge gate — `.claude/hooks/lib/merge-pr.sh`, never bare
|
|
39
|
+
`gh pr merge`).
|
|
37
40
|
6. **Closeout** — run the `task-closeout` skill (merge confirmed via `gh`), as in the
|
|
38
41
|
orchestrator's §Closeout.
|
|
@@ -43,10 +43,10 @@ latent ones.
|
|
|
43
43
|
reports the project has no meaningful architecture to map, it writes nothing: relay
|
|
44
44
|
that to the user and **end the command** — skip step 4, force nothing.
|
|
45
45
|
|
|
46
|
-
- **Any other latent capability
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
46
|
+
- **Any other latent capability**: it has no guided activation. Say so plainly and
|
|
47
|
+
**end the command** — do **not** fabricate the artifact. (Guided activation beyond
|
|
48
|
+
the architecture map is a deliberate non-feature, not a pending seam; wiring one up
|
|
49
|
+
for a future capability is its own decision.)
|
|
50
50
|
|
|
51
51
|
4. **Re-sync so the gated skill installs** — only when step 3 actually wrote the artifact.
|
|
52
52
|
Run:
|
|
@@ -22,3 +22,10 @@ self-approve, and move the `harness:status:*` labels per the lifecycle.
|
|
|
22
22
|
If the task turns out to be too small for the full ceremony — nothing to specify,
|
|
23
23
|
verify, or review — nudge toward `/triage` (L2) or `/bypass` (L3) per the task-fit
|
|
24
24
|
dial (`.claude/agents/fit-assessment.md`). When in doubt, keep it in the harness.
|
|
25
|
+
|
|
26
|
+
The dial's ceiling is the **partition question**: if the closed PRD bundles separable,
|
|
27
|
+
independently mergeable wants, the orchestrator asks — at the define's close, before
|
|
28
|
+
opening the task — whether to cut the feature into several issues, each its own
|
|
29
|
+
branch, PR and merge gate (authority: `.claude/agents/partition.md`, read on trigger).
|
|
30
|
+
An approved cut opens a parent partition-plan issue (`harness:partition-plan`, never a
|
|
31
|
+
task) and Part 1 as a normal task; later parts open at their turn.
|
|
@@ -23,7 +23,21 @@ question to capture it, then proceed.
|
|
|
23
23
|
issue, so it auto-closes on merge).
|
|
24
24
|
3. **Skip the human-wait gates.** Do **not** pause for an approval gate, and do
|
|
25
25
|
**not** wait on the merge gate — merge/ship as soon as the test is green and CI
|
|
26
|
-
passes.
|
|
26
|
+
passes. "As soon as CI passes" is mechanical, not a vibe: execute the merge
|
|
27
|
+
through the checks-precondition executor
|
|
28
|
+
(`.claude/hooks/lib/merge-pr.sh <pr> --squash` — no `--approve-issue` here:
|
|
29
|
+
the hotfix review runs async, so there is no APPROVE to bind at merge time;
|
|
30
|
+
the stale-approve guard belongs to the reviewed task path), which waits for green and
|
|
31
|
+
refuses red or absent checks — urgency skips the _human_ wait, never the
|
|
32
|
+
verification. This is the one path where you don't wait for a human to sign
|
|
33
|
+
off first. On any non-zero exit (red / no checks / timeout / no verdict),
|
|
34
|
+
act on the exit code exactly as the Orchestrator's "Executing an authorized
|
|
35
|
+
merge — the checks precondition" section prescribes: surface the real state
|
|
36
|
+
and ask. Urgency never authorizes `--force` on your own initiative — a fire
|
|
37
|
+
does not lower the bar for merging on red or unverified checks. One
|
|
38
|
+
adaptation: a standing no-checks answer has no closeout PR to ride on this
|
|
39
|
+
path — commit the `merge.allow_no_checks: true` line onto the **hotfix
|
|
40
|
+
branch** before merging, so it lands with the hotfix PR.
|
|
27
41
|
4. **Run the Reviewer asynchronously.** After shipping, dispatch the **Reviewer**
|
|
28
42
|
sub-agent (fresh context, `senior-review`) on the merged change. The review is not
|
|
29
43
|
skipped — it's deferred. If it surfaces problems, file a follow-up fix (a normal
|
|
@@ -50,3 +50,8 @@ A two-step pause:
|
|
|
50
50
|
|
|
51
51
|
The hook prints `git status --porcelain` after emitting — it never
|
|
52
52
|
auto-commits. Decide what (if anything) to stage and commit before leaving.
|
|
53
|
+
Exception — a task running **pre-commit review ON** (orchestrator §Pre-commit
|
|
54
|
+
review ON): do **not** commit; the zero-commit deferral binds `/pause` too.
|
|
55
|
+
Leave the staged save-point untouched (it survives the session; staging
|
|
56
|
+
anything now is the mid-experiment `add` the protocol forbids), note the pause
|
|
57
|
+
in `progress.md` — disk-only, per the mode's contract.
|
|
@@ -16,8 +16,11 @@ is the single source for the procedure.
|
|
|
16
16
|
parked at `awaiting design definition` (+ `harness:needs-design`), and
|
|
17
17
|
`-l harness:status:pending` for stubs captured by `/spinoff`), plus parked closeouts
|
|
18
18
|
(`-l harness:status:closeout-pending --state all` — their issue is already **closed** by
|
|
19
|
-
the task PR's `Closes #<id>`, so an open-only listing would miss them), and
|
|
20
|
-
|
|
19
|
+
the task PR's `Closes #<id>`, so an open-only listing would miss them), and **partition
|
|
20
|
+
parents** (`-l harness:partition-plan` — not tasks; one with unticked parts surfaces as
|
|
21
|
+
"partition in progress: next part per the plan" — or "waiting on #<id> (Part <j>)" when
|
|
22
|
+
the next row is blocked by an in-flight child — and resuming it starts the next eligible
|
|
23
|
+
part, or names the blocker, per `.claude/agents/partition.md`), and ask which to pick up.
|
|
21
24
|
|
|
22
25
|
In brief (authority is the orchestrator): for an SDD task the state and spec live
|
|
23
26
|
**only on the branch** until merge — `git fetch` and check out `harness/<id>-<slug>`
|
|
@@ -32,16 +35,36 @@ interview yourself** to finish `ui-handoff.md` (the UI Designer then critiques i
|
|
|
32
35
|
drop `harness:needs-design` and continue toward spec-ready. When `progress.md` records
|
|
33
36
|
`Mode: step-by-step`, the `## Step log` carries the step sub-state — resume
|
|
34
37
|
exactly there: `awaiting human checkpoint (step N/M)` re-presents that pending
|
|
35
|
-
checkpoint (inspect / run / OK / changes / OK+downgrade
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
checkpoint (inspect / run / OK / changes / OK+downgrade; in all-at-once under
|
|
39
|
+
pre-commit review ON the line carries no `(step N/M)` counter — same
|
|
40
|
+
re-entry); a `fix-loop iteration K`
|
|
41
|
+
line re-enters the per-step implement→review loop at that iteration; an
|
|
42
|
+
`awaiting ledger retry (step N/M, retry 1/1)` line — or its full-pass twin
|
|
43
|
+
`awaiting ledger retry (full pass, retry 1/1)` — re-runs
|
|
44
|
+
`lemony review-ledger validate` on the sidecar on disk (`--anchor` per the
|
|
45
|
+
orchestrator: per-step, the `(anchor <oid>)` on the step-log line; full pass, the
|
|
46
|
+
fingerprint merge-base — except pre-commit review ON's pre-gate twin, which anchors
|
|
47
|
+
at the recorded single-group anchor, = the branch head: ON defers every commit) —
|
|
48
|
+
green re-presents the gate
|
|
49
|
+
the pass feeds, red goes to that gate with the verb's lines, the single retry being spent
|
|
50
|
+
(authority: the orchestrator §Step-by-step implementation). If the Mode line carries a
|
|
38
51
|
`(downgraded to all-at-once at step N)` suffix, the remaining tasks run all-at-once —
|
|
39
52
|
resume at the active subtask as usual, not via the step loop (the Step log is then
|
|
40
53
|
history, not sub-state).
|
|
41
54
|
|
|
42
55
|
**Cross-machine pickup of an `in-progress` task**: the branch on origin
|
|
43
56
|
carries the last **successful** best-effort WIP push — the Implementer pushes on
|
|
44
|
-
signaling done, and step-by-step pushes at each checkpoint-wait.
|
|
57
|
+
signaling done, and step-by-step pushes at each checkpoint-wait. Exception: a task
|
|
58
|
+
running **pre-commit review ON** defers every commit and push until a checkpoint OK
|
|
59
|
+
— in-flight work and its `progress.md` updates exist only in the implementing
|
|
60
|
+
machine's worktree, so from another machine the branch reads as of the last OK'd
|
|
61
|
+
group; before the first OK it is **indistinguishable from idle** (the knob record
|
|
62
|
+
itself is deferred — the documented price of the mode, orchestrator §Pre-commit
|
|
63
|
+
review ON). When config pins `implementation.pre_commit_review: on`, or the
|
|
64
|
+
branch's `progress.md` already carries the `Pre-commit review: on` line (some OK
|
|
65
|
+
landed), surface the mode instead of concluding the task is idle. A discovery
|
|
66
|
+
pause still surfaces cross-machine via its labels and issue comment, though the
|
|
67
|
+
full `discoveries.md` entry stays machine-local. If a **local** copy
|
|
45
68
|
of the branch is ahead of origin, prefer it (it is the newer state — this is what
|
|
46
69
|
makes same-machine resume lossless). From a **different** machine, anything committed
|
|
47
70
|
after the last successful push is unreachable and undetectable (origin is
|
|
@@ -51,9 +74,14 @@ checkpoint is a conscious replay, not a silent assumption. An `in-review` one re
|
|
|
51
74
|
**merge gate**: surface the open PR's review comments and run the merge-gate procedure
|
|
52
75
|
(route change-requests back to the Implementer, then offer to post threaded replies —
|
|
53
76
|
authority is the orchestrator). A `closeout-pending` task has **nothing to check out** —
|
|
54
|
-
its task PR already merged and its state is archived under `_archive/<id>/`:
|
|
55
|
-
`
|
|
56
|
-
|
|
77
|
+
its task PR already merged and its state is archived under `_archive/<id>/`: if the open
|
|
78
|
+
`harness/closeout-<id>` record PR is still unmerged, **re-run the self-merge executor on
|
|
79
|
+
it** (`.claude/hooks/lib/merge-pr.sh harness/closeout-<id> --squash --delete-branch` —
|
|
80
|
+
the skill's step-5 line verbatim, flags included: a bare invocation is rejected by
|
|
81
|
+
`gh pr merge` non-interactively and would re-park forever. The park may have been a
|
|
82
|
+
transient pending/red that has since settled; a repeat not-green re-parks), then re-enter the
|
|
83
|
+
`task-closeout` skill at its **finalize** step (step 6) once that PR is merged — the
|
|
84
|
+
skill owns the finalize operations
|
|
57
85
|
(delete the task branch, flip to `done`, emit `task_done`, close the issue). A
|
|
58
86
|
`pending` stub has **no branch
|
|
59
87
|
yet** — nothing to check out: read the captured context (the title is the symptom; the
|