@lemoncode/lemony 0.1.2 → 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 +13 -4
- package/catalog/agents/implementer.md +87 -8
- package/catalog/agents/orchestrator.md +643 -386
- package/catalog/agents/partition.md +316 -0
- package/catalog/agents/reviewer.md +356 -21
- package/catalog/agents/spec-author.md +16 -4
- package/catalog/agents/spinoff.md +100 -0
- package/catalog/agents/triage.md +41 -0
- package/catalog/agents/ui-design.md +147 -0
- package/catalog/agents/ui-designer.md +3 -2
- 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 +38 -10
- package/catalog/commands/triage.md +4 -3
- package/catalog/harness.config.schema.json +40 -0
- package/catalog/hooks/lib/merge-pr.sh +699 -0
- package/catalog/schemas/tier2-events-history.md +17 -0
- package/catalog/schemas/tier2-events.md +10 -10
- package/catalog/skills/mutation-testing/SKILL.md +80 -19
- package/catalog/skills/prd-to-spec/SKILL.md +74 -2
- package/catalog/skills/raise-discovery/SKILL.md +6 -0
- package/catalog/skills/resolve-discovery/SKILL.md +12 -7
- package/catalog/skills/security-review/SKILL.md +119 -6
- package/catalog/skills/spec-compliance-check/SKILL.md +8 -4
- package/catalog/skills/spec-to-issue/SKILL.md +7 -1
- package/catalog/skills/task-closeout/SKILL.md +85 -20
- package/catalog/skills/test-gap-report/SKILL.md +4 -0
- package/catalog/skills/triage-issue/SKILL.md +65 -4
- package/catalog/skills/verify/SKILL.md +3 -0
- package/catalog/templates/claude-code/agents.md.tpl +50 -16
- package/catalog/templates/claude-code/harness.config.yml.tpl +33 -0
- package/dist/cli.mjs +744 -37
- package/package.json +10 -6
|
@@ -27,7 +27,8 @@ Three moves, in this order:
|
|
|
27
27
|
`_archive/<id>/`; drop only `progress.md` (true scratch). The high-value memory stays
|
|
28
28
|
live and grep-able.
|
|
29
29
|
3. **Land via a PR** — the `history.md` append, the archival move, and any new ADR ride a
|
|
30
|
-
dedicated `harness/closeout-<id>` PR
|
|
30
|
+
dedicated `harness/closeout-<id>` PR that self-merges **only on green checks**
|
|
31
|
+
(through `.claude/hooks/lib/merge-pr.sh`). No direct push to the base.
|
|
31
32
|
|
|
32
33
|
Run this only when the **Reviewer has approved** and the task PR is merged. The merge is a
|
|
33
34
|
human decision (the merge gate) — closeout never merges the task; it **confirms** the
|
|
@@ -87,8 +88,9 @@ The three differ in **who decides** — and the asymmetry is deliberate:
|
|
|
87
88
|
|
|
88
89
|
- **`update-architecture` — automatic dispatch, no pre-offer.** Only when
|
|
89
90
|
`docs/architecture.md` exists (the skill installs solely then). Dispatch the
|
|
90
|
-
**Architect** (`update-architecture`, fresh context) with the task's **
|
|
91
|
-
(`gh pr diff <pr>`) plus the task's `spec/design.md`
|
|
91
|
+
**Architect** (`update-architecture`, fresh context) with the task's **PR number**
|
|
92
|
+
(it runs `gh pr diff <pr>` itself) plus the **path** of the task's `spec/design.md`
|
|
93
|
+
(still live here — archival is
|
|
92
94
|
step 4 below). The Architect reads the change, makes
|
|
93
95
|
the smallest true edit if the system's **shape** moved (referencing any ADR just
|
|
94
96
|
written — `see ADR-NNNN`), or reports **no-op** when nothing architectural changed.
|
|
@@ -157,34 +159,74 @@ working scratch are gone. A UI task's **`ui-handoff.md`** is a sibling **inside*
|
|
|
157
159
|
`spec/`, so the single `git mv` of `spec/` archives it with the rest — no special
|
|
158
160
|
handling.
|
|
159
161
|
|
|
160
|
-
### 5. Open the closeout PR and
|
|
162
|
+
### 5. Open the closeout PR and self-merge on green
|
|
161
163
|
|
|
162
|
-
Commit the record, push the branch, open a PR, and
|
|
164
|
+
Commit the record, push the branch, open a PR, and self-merge it **through the
|
|
165
|
+
checks-precondition executor** — never a bare `gh pr merge`. There is no standing human
|
|
166
|
+
authorization on this path, so the precondition stands alone: **the executor merges
|
|
167
|
+
only on green; every other outcome takes one of the exits below** (some end in a
|
|
168
|
+
human's informed decision — what never happens is an autonomous merge on not-green).
|
|
169
|
+
The executor verifies the check status the platform reports for
|
|
170
|
+
the PR, waiting — bounded (`merge.checks_timeout_secs`, default ~10 min) — for pending
|
|
171
|
+
checks:
|
|
163
172
|
|
|
164
173
|
```bash
|
|
165
174
|
git commit -m "closeout(<id>): archive task state, record in history.md"
|
|
166
175
|
git push -u origin harness/closeout-<id>
|
|
167
176
|
gh pr create --base <default> --head harness/closeout-<id> \
|
|
168
177
|
--title "closeout(<id>): <topic>" --body "Closeout record for #<id>."
|
|
169
|
-
|
|
178
|
+
.claude/hooks/lib/merge-pr.sh harness/closeout-<id> --squash --delete-branch
|
|
170
179
|
```
|
|
171
180
|
|
|
181
|
+
(If the human recorded a standing merge answer at this task's merge gate — a
|
|
182
|
+
`merge.allow_no_checks: true` line sitting uncommitted in `harness.config.yml` —
|
|
183
|
+
stage it into the record commit above: the answer rides the closeout PR to the base.)
|
|
184
|
+
|
|
172
185
|
The closeout PR **must not** carry `Closes #<id>` — the task PR already auto-closed the
|
|
173
186
|
issue on merge; closeout only flips the label and finalizes.
|
|
174
187
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
- **
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
188
|
+
Act on the executor's exit code:
|
|
189
|
+
|
|
190
|
+
- **0 — merged.** Continue to step 6 (finalize).
|
|
191
|
+
- **10 — checks red.** Red does **not** automatically mean the base is broken — look at
|
|
192
|
+
what failed (`gh run view` / the check's output), then take one of three exits:
|
|
193
|
+
1. **Failure in the closeout's own files** (format/lint on the moved docs): fixable
|
|
194
|
+
by you alone — run the formatter, commit, push, re-run the executor; green ⇒
|
|
195
|
+
self-merge normally. No human interruption; fixing format on your own docs-only PR
|
|
196
|
+
is harmless and autonomous.
|
|
197
|
+
2. **Failure in the base** (main was already broken): **park** and surface with the
|
|
198
|
+
diagnosis — the human's informed merge-on-red decision is legitimate precisely
|
|
199
|
+
here, since the red isn't this PR's (on their explicit yes, re-run with
|
|
200
|
+
`--force`). Free side effect: every closeout is a broken-main detector.
|
|
201
|
+
3. **Can't tell:** **park** and surface what you saw — in doubt, the human.
|
|
202
|
+
|
|
203
|
+
The uniform rule stands: **never merge on red alone** — no "it's only docs"
|
|
204
|
+
exception (automatic exceptions are how the bug comes back).
|
|
205
|
+
|
|
206
|
+
- **20 — no checks reported (after the grace window).** Never merge alone, whatever the
|
|
207
|
+
cause — don't auto-classify (no CI, CI dead, path filters all look identical). The
|
|
208
|
+
once-per-repo memory is the **standing answer only**: if `merge.allow_no_checks: true`
|
|
209
|
+
is recorded (or sits uncommitted on this branch, staged per step 5), the executor
|
|
210
|
+
applies it itself — you won't see exit 20. A **one-shot** yes given at an earlier
|
|
211
|
+
merge (including this task's merge gate) authorized **that merge only** and does
|
|
212
|
+
**not** carry over — never re-apply it here on your own. Seeing exit 20 means no
|
|
213
|
+
standing answer exists, so ask: "I saw no checks on the closeout PR — merge?". A
|
|
214
|
+
standing answer ("this repo has no CI — merge without checks") is recorded as
|
|
215
|
+
`merge.allow_no_checks: true` in `harness.config.yml` — add the line on this very
|
|
216
|
+
closeout branch, push, and re-run the executor (it reads the working tree, and the
|
|
217
|
+
answer lands on the base with the record). A one-shot yes ⇒ re-run with `--force`.
|
|
218
|
+
No human available ⇒ **park**.
|
|
219
|
+
- **30 — checks still pending past the bound.** **No merge**: **park**. The closeout is
|
|
220
|
+
docs-only archival — leaving it pending blocks nothing already merged.
|
|
221
|
+
- **1 (or any other non-zero) — no verdict.** Read the executor's stderr: either the
|
|
222
|
+
check status could not be read (`gh`/auth/network — the precondition is
|
|
223
|
+
unverifiable), or the merge attempt itself was rejected (branch protection requires
|
|
224
|
+
human approval, a conflict). Both ⇒ **park**, surfacing that stderr — a
|
|
225
|
+
protection-parked record PR is merged by the human by hand.
|
|
185
226
|
|
|
186
227
|
**Park:** flip the issue to `harness:status:closeout-pending`, tell the human the closeout
|
|
187
|
-
PR is open
|
|
228
|
+
PR is open, why it did not merge (the executor's output — failing checks, no checks,
|
|
229
|
+
pending past the bound, or protection), and stop. The task issue is **already closed** (the
|
|
188
230
|
task PR's `Closes #<id>` fired on its merge), so `/resume` finds the parked closeout only
|
|
189
231
|
by listing closed issues too (`--state all`) — a default open-only queue would miss it. A
|
|
190
232
|
later `/resume` picks up at step 6 once the PR is merged. (Authority for the RESUME entry:
|
|
@@ -192,7 +234,10 @@ the Orchestrator.)
|
|
|
192
234
|
|
|
193
235
|
### 6. Finalize (once the closeout PR is merged)
|
|
194
236
|
|
|
195
|
-
|
|
237
|
+
On a `/resume` that finds the record PR **still open**, first re-run the executor on it
|
|
238
|
+
(step 5's `merge-pr.sh` line, verbatim): a park on pending or red checks is transient
|
|
239
|
+
and may have settled green — a repeat not-green outcome just re-parks. Then confirm the
|
|
240
|
+
closeout PR merged (`gh pr view <pr> --json state,mergedAt` → `MERGED`; on a
|
|
196
241
|
`/resume`, pass the deterministic branch `harness/closeout-<id>` as `<pr>` — the
|
|
197
242
|
merge-confirm accepts a branch name in place of a PR number), land the merged base
|
|
198
243
|
(`git checkout <default> && git pull`), then:
|
|
@@ -208,11 +253,31 @@ single emit point for either path). You compute the envelope (cycle time, review
|
|
|
208
253
|
rejections, level) as the Orchestrator running this skill; the fields and the `emit`
|
|
209
254
|
command line are in `orchestrator.md` §Closeout. `events.jsonl` is local-only/gitignored, so the emit never dirties the base.
|
|
210
255
|
|
|
256
|
+
**If the task is a part of a partitioned feature** — its issue body (read it with
|
|
257
|
+
`gh issue view <id> --json body`; the issue is closed by now) carries a
|
|
258
|
+
`Part <k> of #<parent>` trace line — update the parent **partition-plan** issue here, in
|
|
259
|
+
the same finalize, **read-modify-write**: read the parent body immediately before
|
|
260
|
+
editing (`gh issue view <parent> --json body`), tick only your row and set it to
|
|
261
|
+
`- [x] Part <k> — <slice> → #<id> merged`, write it back with
|
|
262
|
+
`gh issue edit <parent> --body-file`, then re-read to confirm the tick is present — if another row moved
|
|
263
|
+
underneath you (a sibling closing out elsewhere), redo it **once** on the fresh body
|
|
264
|
+
(match rows tolerant of a trailing `\r`: a body edited on the web may carry CRLF); still
|
|
265
|
+
absent → leave the tick to the human and say so. Idempotent on a retried finalize: an
|
|
266
|
+
already-ticked row is left alone, and the all-ticked check still runs. When that
|
|
267
|
+
leaves **every** row ticked (merged or dropped), close the parent with a summary comment
|
|
268
|
+
(`gh issue close <parent> --comment "<what shipped, part by part>"`) — mechanical, no
|
|
269
|
+
human prompt: each part's merge already passed the human gate; a parent the human already
|
|
270
|
+
closed takes the tick and the close is a no-op. A parent with unticked rows stays open;
|
|
271
|
+
`/resume` surfaces its next part. The contract is the Orchestrator's companion
|
|
272
|
+
`.claude/agents/partition.md`.
|
|
273
|
+
|
|
211
274
|
### 7. Report
|
|
212
275
|
|
|
213
276
|
Return a one-line summary: the task id, the `history.md` entry, the archive path
|
|
214
|
-
(`_archive/<id>/`), any ADR raised,
|
|
215
|
-
closeout is parked at `closeout-pending` awaiting the record PR's merge)
|
|
277
|
+
(`_archive/<id>/`), any ADR raised, confirmation that the issue is closed (or that
|
|
278
|
+
closeout is parked at `closeout-pending` awaiting the record PR's merge), and — for a
|
|
279
|
+
partition part — that the parent row was ticked (and the parent closed, on the last
|
|
280
|
+
part).
|
|
216
281
|
|
|
217
282
|
## Scope note
|
|
218
283
|
|
|
@@ -52,6 +52,10 @@ For each file in the "always" set:
|
|
|
52
52
|
|
|
53
53
|
### 3. Report
|
|
54
54
|
|
|
55
|
+
Destination: the full-pass **issue comment**. In your return summary — and always on
|
|
56
|
+
a per-step review, which posts no comment — carry only the counts + the gaps, per
|
|
57
|
+
the Reviewer's verdict-size rule (a REJECT lifts the cap entirely).
|
|
58
|
+
|
|
55
59
|
```
|
|
56
60
|
## Test Gap Report — <task name>
|
|
57
61
|
|
|
@@ -44,7 +44,7 @@ Look at:
|
|
|
44
44
|
Determine:
|
|
45
45
|
|
|
46
46
|
- The minimal change needed to fix the root cause
|
|
47
|
-
- Which modules/interfaces are affected
|
|
47
|
+
- Which modules/interfaces are affected, and **which files the fix will change**
|
|
48
48
|
- What behaviors need to be verified via tests
|
|
49
49
|
- Whether this is a regression, missing feature, or design flaw
|
|
50
50
|
|
|
@@ -65,12 +65,70 @@ Rules:
|
|
|
65
65
|
For TDD philosophy → see the **tdd** skill. For test recipes → see your project's
|
|
66
66
|
testing playbook.
|
|
67
67
|
|
|
68
|
-
### 5.
|
|
68
|
+
### 5. Declare the risk surfaces
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
This is the L2 counterpart of the `[risk: …]` tag a spec's group header carries at L1:
|
|
71
|
+
the declaration of **what kind of damage this change can do**, made at the structuring
|
|
72
|
+
moment, outside the Reviewer, and visible to the human before execution.
|
|
73
|
+
|
|
74
|
+
One line per surface — a class paired with **one concrete file the fix changes**, never
|
|
75
|
+
a module in the abstract — using the same vocabulary as `prd-to-spec`; each class names
|
|
76
|
+
what kind of damage the surface can do:
|
|
77
|
+
|
|
78
|
+
<!-- risk-vocabulary:start -->
|
|
79
|
+
|
|
80
|
+
| Class | Surface |
|
|
81
|
+
| ----------------- | ---------------------------------------------------------------- |
|
|
82
|
+
| `auth` | authentication, authorization, session or token handling |
|
|
83
|
+
| `payments` | money movement, billing, pricing |
|
|
84
|
+
| `shell-process` | shell invocation, subprocess spawning, argument construction |
|
|
85
|
+
| `data-loss` | writes, deletes, migrations, anything that can destroy user data |
|
|
86
|
+
| `secrets` | credentials, keys, tokens — at rest or in transit |
|
|
87
|
+
| `executable-mode` | file permissions, exec bits, anything that changes what can run |
|
|
88
|
+
|
|
89
|
+
<!-- risk-vocabulary:end -->
|
|
90
|
+
|
|
91
|
+
A fix that carries one class into three files declares three lines:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
## Risk surfaces
|
|
95
|
+
- data-loss: src/storage/sync.ts
|
|
96
|
+
- shell-process: src/hooks/run-hook.ts
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
A fix that touches no such surface carries the section with a single line — `- none` —
|
|
100
|
+
never an omitted section: the absence of a declaration and a declaration of absence are
|
|
101
|
+
different claims, and only the second is auditable. `- none` is a claim about the change,
|
|
102
|
+
so make it only when it is true.
|
|
103
|
+
|
|
104
|
+
Declare it **now**, before the fix is written: a surface named afterwards describes what
|
|
105
|
+
happened, it does not declare what could. The human reviews it with the rest of the draft
|
|
106
|
+
in the next step and edits it in the issue like any other section — that review is the
|
|
107
|
+
first thing the section buys. The second comes at review time: the Reviewer hands the
|
|
108
|
+
declared surfaces to `security-review`, which presses hardest where they point. Nothing
|
|
109
|
+
checks it automatically.
|
|
110
|
+
|
|
111
|
+
If a surface has no home in the vocabulary, declare it as `unclassified` and say what it
|
|
112
|
+
can do:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
- unclassified: src/queue/drain.ts — replays messages, can double-deliver
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Never fold it into `- none`.** `- none` claims no such surface exists, and that claim
|
|
119
|
+
would be false — an unnameable surface is the one most worth seeing. Do not invent a
|
|
120
|
+
one-off class either, and do not edit the table here: it is vendor-owned — generated into
|
|
121
|
+
this skill and `prd-to-spec` from one source, so the two always agree — and a local edit
|
|
122
|
+
is discarded on the next update. Say in the next step that the vocabulary came up short,
|
|
123
|
+
so the human can decide whether it grows.
|
|
124
|
+
|
|
125
|
+
### 6. Confirm with the user
|
|
126
|
+
|
|
127
|
+
Present the issue draft: problem summary, root cause analysis, TDD fix plan, and the
|
|
128
|
+
declared risk surfaces.
|
|
71
129
|
Ask: "Does this look right? Should I create the issue?"
|
|
72
130
|
|
|
73
|
-
###
|
|
131
|
+
### 7. Create the GitHub issue
|
|
74
132
|
|
|
75
133
|
After confirmation, create with `gh issue create` and the `harness:managed` label.
|
|
76
134
|
Use a structure like:
|
|
@@ -86,6 +144,9 @@ Use a structure like:
|
|
|
86
144
|
- [ ] RED: <test capturing behavior 1> → GREEN: <minimal change>
|
|
87
145
|
- [ ] RED: <test capturing behavior 2> → GREEN: <minimal change>
|
|
88
146
|
|
|
147
|
+
## Risk surfaces
|
|
148
|
+
- <class>: <path the fix writes to>
|
|
149
|
+
|
|
89
150
|
## Affected
|
|
90
151
|
<modules / interfaces touched>
|
|
91
152
|
```
|
|
@@ -84,6 +84,9 @@ and the error output (unexpected warnings/errors even when the happy path worked
|
|
|
84
84
|
**Verdict**: works / does not work — <one-line reason>
|
|
85
85
|
```
|
|
86
86
|
|
|
87
|
+
This block is your working record; a capped return summary condenses it to the
|
|
88
|
+
verdict line (plus any ❌ detail — failures are signal, never trimmed).
|
|
89
|
+
|
|
87
90
|
On a failure, read the **full** error, find the origin (not where it surfaced), fix
|
|
88
91
|
the root cause, and re-run from the failed gate. If a failure reveals the spec itself
|
|
89
92
|
is wrong or silent, that's a **discovery** — run `raise-discovery`, don't paper over
|
|
@@ -27,7 +27,9 @@ surface the menu.
|
|
|
27
27
|
- **DEFINE** — the L1 full-SDD round-trip (see below).
|
|
28
28
|
- **RESUME** — for an SDD task, `git fetch` and check out `harness/<id>-<slug>` first
|
|
29
29
|
(the task state and spec live only on the branch until merge), then reload
|
|
30
|
-
`.claude/state/tasks/<id>/` and continue from `progress.md`.
|
|
30
|
+
`.claude/state/tasks/<id>/` and continue from `progress.md`. An issue carrying
|
|
31
|
+
`harness:partition-plan` is a partition parent, not a task — start its next part per
|
|
32
|
+
`.claude/agents/partition.md`.
|
|
31
33
|
- **TRIAGE** — the L2 lightweight path (see below). Invoke the `triage-issue` skill.
|
|
32
34
|
- **ORIENT** — an intentless entry (greeting / "what should I pick up?" / nothing).
|
|
33
35
|
Render the **dispatch menu**: the parked queue (the same listing `/resume` runs with
|
|
@@ -52,12 +54,17 @@ A task deserves the harness if it is **specifiable**, **verifiable**, or
|
|
|
52
54
|
## L1 round-trip (DEFINE)
|
|
53
55
|
|
|
54
56
|
1. **Grill** — `grill-with-docs`: interview the idea into a PRD at
|
|
55
|
-
`docs/prds/<topic>-<date>.md`.
|
|
57
|
+
`docs/prds/<topic>-<date>.md`. If the closed PRD bundles separable, independently
|
|
58
|
+
mergeable wants, ask the **partition question** before opening the task (authority:
|
|
59
|
+
`.claude/agents/partition.md`, read on trigger): an approved cut opens a parent
|
|
60
|
+
partition-plan issue (`harness:partition-plan`, never a task) and Part 1 as a normal
|
|
61
|
+
task; later parts open at their turn.
|
|
56
62
|
2. **Open the task** — create the issue (skeleton body + `harness:managed` +
|
|
57
63
|
`harness:sdd` + `harness:status:spec-in-progress`) and the branch
|
|
58
64
|
`harness/<id>-<slug>`. `<id>` is the GitHub issue number in this build; spec and code
|
|
59
65
|
both live on that branch — nothing touches the default branch until the merge gate.
|
|
60
|
-
3. **UI design (if it touches UI)** — **UI design gate** (
|
|
66
|
+
3. **UI design (if it touches UI)** — **UI design gate** (canonical: the orchestrator's
|
|
67
|
+
L1 step 3, evaluated core-only — read `.claude/agents/ui-design.md` only when it fires):
|
|
61
68
|
if the repo has a frontend AND the task touches UI, put `harness:needs-design`, offer the
|
|
62
69
|
design-stop, and on "continue" **run `grill-ui` yourself** (the interactive design
|
|
63
70
|
interview) to author `ui-handoff.md` under `tasks/<id>/spec/`, then dispatch the **UI
|
|
@@ -67,31 +74,55 @@ A task deserves the harness if it is **specifiable**, **verifiable**, or
|
|
|
67
74
|
under `tasks/<id>/spec/`) then `spec-to-issue` (fills the issue body — it creates nothing
|
|
68
75
|
and moves no labels).
|
|
69
76
|
5. **Spec-ready + handoff** — remove `harness:needs-design` once `ui-handoff.md` is
|
|
70
|
-
complete (a spec-ready task never carries
|
|
77
|
+
complete (a spec-ready task never carries the label), flip to `harness:status:spec-ready`,
|
|
71
78
|
commit and push the task state to the branch. DEFINE can stop here: the spec-ready
|
|
72
79
|
queue (`gh issue list -l harness:status:spec-ready`) is the handoff. Ask: implement
|
|
73
80
|
now or hand off?
|
|
74
81
|
6. **Approval gate** — run by whoever implements (a RESUME of a spec-ready issue runs
|
|
75
82
|
it). Present the spec; the human approves (or asks for changes → Spec Author
|
|
76
83
|
revises). On approval, flip to `harness:status:in-progress`. The spec, not the code,
|
|
77
|
-
is the source of intent — never self-approve.
|
|
84
|
+
is the source of intent — never self-approve. If `harness.config.yml` declares no
|
|
85
|
+
`gates` list, propose one here (from the manifest + CI; hand-edited on
|
|
86
|
+
confirmation) — never mid-review (orchestrator §Approval gate).
|
|
78
87
|
7. **Implement** — Implementer sub-agent, `tdd` skill, on the branch, keeping
|
|
79
|
-
`.claude/state/tasks/<id>/progress.md` live.
|
|
88
|
+
`.claude/state/tasks/<id>/progress.md` live. The gate interaction settles two
|
|
89
|
+
knobs, both recorded in `progress.md`: the **implementation mode** (all-at-once,
|
|
90
|
+
or step-by-step with per-group human checkpoints) and **pre-commit review**
|
|
91
|
+
(config `implementation.pre_commit_review`; ON = the human reviews the work
|
|
92
|
+
**uncommitted** — zero commits until each checkpoint OK). Authority:
|
|
93
|
+
orchestrator §Implementation mode / §Pre-commit review ON.
|
|
80
94
|
8. **Review** — flip to `harness:status:in-review`, open the PR (`gh pr create`,
|
|
81
95
|
branch → default), Reviewer sub-agent reviews it (`senior-review`, fresh context). If
|
|
82
96
|
the task touched UI, the **UI Designer** reviews as a distinct design + a11y lens too
|
|
83
|
-
— either lens rejecting routes back to the Implementer.
|
|
97
|
+
— either lens rejecting routes back to the Implementer. Every APPROVE carries an
|
|
98
|
+
**evidence ledger** — a JSON sidecar under the task's state that a script validates
|
|
99
|
+
(`lemony review-ledger validate`), never an agent: a red ledger sends a fresh Reviewer
|
|
100
|
+
back once, then the human; it never routes to the Implementer and is never relayed as
|
|
101
|
+
an APPROVE.
|
|
84
102
|
9. **Merge gate** — never auto-merge. Surface the approved PR; the human merges (or
|
|
85
|
-
authorizes you to
|
|
86
|
-
|
|
87
|
-
|
|
103
|
+
authorizes you to — a conditional yes: the agent's merge runs through the
|
|
104
|
+
checks precondition (`.claude/hooks/lib/merge-pr.sh --approve-issue <issue>`)
|
|
105
|
+
and never lands on red, absent, or still-pending checks without asking — nor
|
|
106
|
+
content that no longer matches what the Reviewer's APPROVE reviewed (the
|
|
107
|
+
stale-approve guard; a clean update-branch stays valid, any content change
|
|
108
|
+
routes back to re-review). The task stays at `in-review`
|
|
109
|
+
until merged.
|
|
110
|
+
10. **Closeout** — `task-closeout`: confirm the merge via `gh`, run the three Architect
|
|
111
|
+
activations (`write-adr` — HITL offer per resolved discovery; `update-architecture` —
|
|
112
|
+
automatic when `docs/architecture.md` exists; `playbook-iterate` — HITL offer once
|
|
113
|
+
per task), archive the spec + discoveries to `_archive/<id>/` (drop
|
|
88
114
|
`progress.md`), and land `history.md` + the archival via a dedicated
|
|
89
|
-
`harness/closeout-<id>` PR
|
|
90
|
-
|
|
91
|
-
|
|
115
|
+
`harness/closeout-<id>` PR that self-merges **only on green checks**
|
|
116
|
+
(`.claude/hooks/lib/merge-pr.sh`) — never a direct push to the base.
|
|
117
|
+
A red on its own files (format/lint) it fixes and retries autonomously; any
|
|
118
|
+
other not-green outcome or protection needing approval parks the PR at
|
|
119
|
+
`closeout-pending`, and `/resume` finalizes. Then close the issue and delete
|
|
120
|
+
the branch.
|
|
92
121
|
|
|
93
122
|
## L2 round-trip (TRIAGE)
|
|
94
123
|
|
|
124
|
+
Authority for the steps: `.claude/agents/triage.md` (the Orchestrator's lazy companion).
|
|
125
|
+
|
|
95
126
|
1. **Triage** — `triage-issue`: investigate, find root cause, draft a TDD-based fix
|
|
96
127
|
plan, and create the issue with `harness:managed` (no `harness:sdd` — its absence
|
|
97
128
|
marks the lightweight path).
|
|
@@ -100,11 +131,14 @@ A task deserves the harness if it is **specifiable**, **verifiable**, or
|
|
|
100
131
|
3. **Implement** — Implementer sub-agent, `tdd` skill.
|
|
101
132
|
4. **Review** — flip to `harness:status:in-review`, open the PR, Reviewer sub-agent
|
|
102
133
|
(`senior-review`, fresh context).
|
|
103
|
-
5. **Merge gate** — the same human-explicit gate as L1: never auto-merge
|
|
134
|
+
5. **Merge gate** — the same human-explicit gate as L1: never auto-merge, and an
|
|
135
|
+
authorized merge runs the same checks precondition and stale-approve guard.
|
|
104
136
|
6. **Closeout** — `task-closeout`: confirm the merge, archive the spec + discoveries to
|
|
105
137
|
`_archive/<id>/`, and land `history.md` + the archival via a dedicated
|
|
106
|
-
`harness/closeout-<id>` PR
|
|
107
|
-
|
|
138
|
+
`harness/closeout-<id>` PR that self-merges only on green checks (own-file
|
|
139
|
+
format reds are self-fixed and retried); park at `closeout-pending` if checks
|
|
140
|
+
stay not-green or it needs approval. Then close the issue and delete the
|
|
141
|
+
branch. Same as L1.
|
|
108
142
|
|
|
109
143
|
## Discovery interrupts
|
|
110
144
|
|
|
@@ -46,6 +46,39 @@ rollback:
|
|
|
46
46
|
# telemetry:
|
|
47
47
|
# enabled: false
|
|
48
48
|
|
|
49
|
+
# Agent-executed merges. Before the agent runs any `gh pr merge` (an authorized
|
|
50
|
+
# task-PR merge, or the closeout record PR), the shared executor
|
|
51
|
+
# `.claude/hooks/lib/merge-pr.sh` verifies the check status the platform reports
|
|
52
|
+
# for the PR and only merges on green — red, absent, or still-pending checks are
|
|
53
|
+
# surfaced to a human instead. Defaults shown — declare only overrides.
|
|
54
|
+
# merge:
|
|
55
|
+
# # Max seconds to wait for pending checks before surfacing instead of merging.
|
|
56
|
+
# checks_timeout_secs: 600
|
|
57
|
+
# # Standing answer for a repo with no CI: `true` lets the executor merge when
|
|
58
|
+
# # the platform reports no checks at all (otherwise it asks, every time).
|
|
59
|
+
# allow_no_checks: false
|
|
60
|
+
|
|
61
|
+
# Implementation-phase knobs the Orchestrator reads at the L1 approval gate.
|
|
62
|
+
# pre_commit_review — human review of the UNCOMMITTED work before anything is
|
|
63
|
+
# committed (zero-commit mode): `human` (default) asks at the gate, in the same
|
|
64
|
+
# interaction as the all-at-once / step-by-step choice, suggesting OFF (today's
|
|
65
|
+
# commit-as-you-go flow); `on` / `off` pin the answer and skip the question
|
|
66
|
+
# (bench/headless runs pin `off`). Bare on/off are strings here (YAML 1.2).
|
|
67
|
+
# implementation:
|
|
68
|
+
# pre_commit_review: human
|
|
69
|
+
|
|
70
|
+
# Review gates. The mechanical gates a Reviewer must attest in its evidence
|
|
71
|
+
# ledger, one entry per name, beyond the always-required real run — a flat list of
|
|
72
|
+
# this project's script names (`package.json` scripts, or your CI's equivalents).
|
|
73
|
+
# Declare every gate your CI enforces, drift checks included: an undeclared project
|
|
74
|
+
# reviews against a floor of the real run only (honest, but thin). The agent may
|
|
75
|
+
# propose this list from your manifest at the approval gate — confirmed by a human
|
|
76
|
+
# and added by hand (this block is the shape); no tool writes it for you.
|
|
77
|
+
# gates:
|
|
78
|
+
# - lint
|
|
79
|
+
# - test
|
|
80
|
+
# - build
|
|
81
|
+
|
|
49
82
|
# Design tokens (`design-tokens validate`). The anti-hardcode scan inspects a built-in
|
|
50
83
|
# set of UI/style extensions (.css/.scss/.ts/.tsx/.vue/.svelte/.astro/.js/.mdx/.html/…).
|
|
51
84
|
# Add extra suffixes here for a stack the built-ins don't cover — additive, never a
|