@cloverleaf/reference-impl 0.12.0 → 0.13.1
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/.claude-plugin/plugin.json +1 -1
- package/README.md +101 -37
- package/VERSION +1 -1
- package/config/council.json +10 -2
- package/dist/cli.mjs +29 -10
- package/dist/council.mjs +285 -64
- package/dist/events.mjs +3 -8
- package/dist/ids.mjs +7 -0
- package/dist/qa-rules.mjs +19 -3
- package/dist/task.mjs +6 -25
- package/dist/work-item.mjs +2 -3
- package/lib/cli.ts +30 -10
- package/lib/council-config.ts +1 -0
- package/lib/council.ts +343 -67
- package/lib/events.ts +4 -8
- package/lib/ids.ts +7 -0
- package/lib/qa-rules.ts +24 -3
- package/lib/task.ts +7 -33
- package/lib/work-item.ts +2 -4
- package/package.json +5 -3
- package/prompts/documenter.md +1 -1
- package/prompts/implementer.md +8 -2
- package/prompts/qa.md +6 -9
- package/prompts/reviewer.md +4 -2
- package/prompts/ui-reviewer.md +83 -11
- package/skills/cloverleaf-approve-baselines/SKILL.md +18 -26
- package/skills/cloverleaf-discover/SKILL.md +7 -1
- package/skills/cloverleaf-document/SKILL.md +5 -6
- package/skills/cloverleaf-implement/SKILL.md +24 -30
- package/skills/cloverleaf-merge/SKILL.md +14 -23
- package/skills/cloverleaf-new-task/SKILL.md +23 -4
- package/skills/cloverleaf-qa/SKILL.md +25 -24
- package/skills/cloverleaf-review/SKILL.md +24 -18
- package/skills/cloverleaf-run/SKILL.md +45 -106
- package/skills/cloverleaf-run-plan/SKILL.md +19 -26
- package/skills/cloverleaf-security-review/SKILL.md +22 -17
- package/skills/cloverleaf-ui-review/SKILL.md +59 -35
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-run
|
|
3
|
-
description: End-to-end orchestrator.
|
|
3
|
+
description: End-to-end orchestrator. Drives every task through one universal delivery council — implement → documenting → council → final-gate/implementing/escalated. The lane is a risk_class profile selector (delivery-fast / delivery-full); security, UI, and QA are council members. Usage — /cloverleaf-run <TASK-ID>.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cloverleaf — run (orchestrator)
|
|
@@ -11,128 +11,71 @@ description: End-to-end orchestrator. Reads task.risk_class to dispatch fast lan
|
|
|
11
11
|
|
|
12
12
|
Do NOT `git checkout main` from a walker worktree — main is held by the primary repo. To compare against main, use `git diff main..HEAD` or `git show main:<path>`. Sub-skills run from the worktree's current branch and stay on it; the walker (in the primary repo) does the final merge to main itself after all tasks reach final-gate.
|
|
13
13
|
|
|
14
|
-
##
|
|
14
|
+
## Bounce budget
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
MAX_REVIEWER_BOUNCES = 3
|
|
18
|
-
MAX_UI_REVIEWER_BOUNCES = 3
|
|
19
|
-
MAX_QA_BOUNCES = 3
|
|
20
|
-
MAX_SECURITY_BOUNCES = 3
|
|
21
|
-
```
|
|
16
|
+
The delivery council owns the loop. `council_bounces` (max 3) counts council bounces back to the Implementer; `plan_review_bounces` (max 3) counts decisive plan-review bounces. On either cap, escalate (section 6). Security, UI, and QA are **council members**, not separate gates — there is no per-agent counter.
|
|
22
17
|
|
|
23
18
|
These counters live in-session (not persisted). Rerunning `/cloverleaf-run` resets.
|
|
24
19
|
|
|
25
|
-
## Security gate (both lanes)
|
|
26
|
-
|
|
27
|
-
Run this immediately after the task reaches `automated-gates` (Reviewer passed) and BEFORE the lane's next move (fast lane: merge; full pipeline: detect-ui-paths). Initialize `security_bounces = 0` at orchestrator start (alongside the other bounce counters).
|
|
28
|
-
|
|
29
|
-
```bash
|
|
30
|
-
cloverleaf-cli classify-security <repo_root> <TASK-ID> --branch cloverleaf/<TASK-ID>
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Parse the JSON. If `classify-security` exits non-zero or emits unparseable output, do NOT silently skip security review (fail-open is unsafe for a security gate). Warn to the user and treat the task as `effective: "high"` — i.e. proceed into security-review anyway (fail toward more scrutiny). If `/cloverleaf-security-review` then cannot run either (e.g. branch/tooling broken), surface the failure and stop rather than merging unreviewed.
|
|
34
|
-
|
|
35
|
-
If `effective == "low"` → skip the gate, proceed with the lane.
|
|
36
|
-
|
|
37
|
-
If `effective == "high"`:
|
|
38
|
-
- If `declared == "low"` (under-classification: `diff_detected` true), you may proactively run `classify-security` to confirm, but the writeback to `security_class: "high"` is now mechanical — the CLI handles it automatically when `advance-status` moves the task to `security-review`. No manual scripting of the writeback is required.
|
|
39
|
-
- `cloverleaf-cli advance-status <repo_root> <TASK-ID> security-review agent`; commit.
|
|
40
|
-
- Inline `/cloverleaf-security-review <TASK-ID>` steps. Reload the task:
|
|
41
|
-
- `status == "automated-gates"` → security review passed; proceed with the lane.
|
|
42
|
-
- `status == "implementing"` → bounced. `security_bounces += 1`. If `security_bounces >= MAX_SECURITY_BOUNCES`, escalate (section 6). Else re-enter the implement→review loop (fast lane section 4 / full pipeline section 5.1), which re-runs the security gate on its next pass.
|
|
43
|
-
- `status == "escalated"` → the security reviewer found a blocker; stop and surface to the user (a human must review `.cloverleaf/feedback/`). This is the security reviewer's own escalation, distinct from a bounce-budget exhaustion.
|
|
44
|
-
|
|
45
|
-
### Refusal and recover
|
|
46
|
-
|
|
47
|
-
In v0.8.1, `advance-status` from `automated-gates` to any post-gate state (`ui-review`, `qa`, `merged`) may exit with **exit code 2** when the task is high-security and has no pass verdict recorded (`security_review_verdict` is absent or not `"pass"`). This is a **security-gate refusal** — the CLI is enforcing that high-security tasks must pass security review before proceeding.
|
|
48
|
-
|
|
49
|
-
Recovery sequence:
|
|
50
|
-
1. Advance the task to `security-review` first: `cloverleaf-cli advance-status <repo_root> <TASK-ID> security-review agent`; commit.
|
|
51
|
-
2. Run `/cloverleaf-security-review <TASK-ID>` to execute the security review.
|
|
52
|
-
3. Retry the original `advance-status` call. If the review passed, the CLI will now allow the transition.
|
|
53
|
-
|
|
54
20
|
## Steps
|
|
55
21
|
|
|
56
|
-
1. Capture TASK-ID.
|
|
57
|
-
|
|
58
|
-
2. Load task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. Verify `status === "pending"`. If not, report and stop.
|
|
59
|
-
|
|
60
|
-
3. **Council gate detection (opt-in).** Run `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.review` and parse the JSON plan. If `plan.source === "consumer"` **and** `plan.profile !== null`, the project has opted into a configured review council — drive the review phase via **section 7 (Council review path)** instead of the hardcoded reviewer/security/ui/qa steps in sections 4/5. Otherwise (`source: "default"`, or no `task.review` binding) proceed exactly as today:
|
|
61
|
-
- `task.risk_class === "low"` → section 4 (Fast Lane)
|
|
62
|
-
- `task.risk_class === "high"` → section 5 (Full Pipeline)
|
|
63
|
-
|
|
64
|
-
When the council path is active it still uses the Implementer (and, for the full pipeline, the Documenter) to produce the branch; only the review→merge portion is council-driven.
|
|
65
|
-
|
|
66
|
-
### 4. Fast Lane
|
|
67
|
-
|
|
68
|
-
Initialize `reviewer_bounces = 0`, `security_bounces = 0`.
|
|
22
|
+
1. Capture TASK-ID. Initialize `council_bounces = 0`, `plan_review_bounces = 0`.
|
|
69
23
|
|
|
70
|
-
|
|
71
|
-
a. Inline `/cloverleaf-implement <TASK-ID>` steps.
|
|
72
|
-
b. Inline `/cloverleaf-review <TASK-ID>` steps.
|
|
73
|
-
c. Reload task. If `status === "automated-gates"`: pass! Break loop.
|
|
74
|
-
d. If `status === "implementing"`: Reviewer bounced. `reviewer_bounces += 1`. If `reviewer_bounces >= MAX_REVIEWER_BOUNCES`, escalate (section 6). Else continue loop.
|
|
75
|
-
e. Else: unexpected state. Report and stop.
|
|
24
|
+
2. Load task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. Verify `status === "pending"`. If not, report and stop. **Preflight:** `load-task` does not schema-validate. Before dispatching any agent, confirm the task document is schema-valid: `context.rfc` is present, and `risk_class` / `security_class` are `low` or `high`. An invalid task otherwise clears every precondition and fails at its first real transition — after the Implementer has already produced a branch and commits.
|
|
76
25
|
|
|
77
|
-
|
|
26
|
+
If any `advance-status` later fails with `orphan event written to … but task save failed`, the event file it names records a transition that did not happen: delete that file before retrying, or the retry will number the next event around it.
|
|
78
27
|
|
|
79
|
-
|
|
28
|
+
3. **Tactical plan (+ optional decisive plan-review).**
|
|
29
|
+
a. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.plan_review`. **A decisive `task.plan_review` is not currently wired — do not bind one.** `/cloverleaf-implement <TASK-ID>` always completes both advances (`pending → tactical-plan → implementing`) in a single dispatch and stops at `implementing`; there is no point at which a plan-review verdict can be applied. If a consumer's `.cloverleaf/config/council.json` bound `plan.mode === "decisive"` for this gate anyway, §3b's `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.plan_review '<verdict>'` would fail — it requires the task to still be at `tactical-plan`, and by the time `/cloverleaf-implement` returns it is already at `implementing`. The shipped default binds no profile to `task.plan_review` (`plan.profile` is always `null` here), so this limitation does not affect the packaged pipeline; it is tracked as a follow-up, not built in this fix. Otherwise (no decisive plan-review bound — the shipped default) simply inline `/cloverleaf-implement <TASK-ID>`, which walks `pending → tactical-plan → implementing` and stops at `implementing`.
|
|
30
|
+
b. **Reserved — not reachable today.** Applying a decisive `task.plan_review` verdict requires the task to still be at `tactical-plan`, and 3a never leaves it there under the current `/cloverleaf-implement`, so skip 3b unconditionally and continue to 3c. The bullets below record the intended reload logic for when a real stop-at-`tactical-plan` mode exists:
|
|
31
|
+
- `implementing` (pass) → continue to 3c.
|
|
32
|
+
- `pending` (bounce) → `plan_review_bounces += 1`; if `>= 3` escalate (section 6); else return to 3a.
|
|
33
|
+
- `escalated` → stop and surface.
|
|
34
|
+
c. Finish the Implementer (task at `implementing`), then reach `documenting` for **every** `risk_class`:
|
|
35
|
+
- `risk_class: "high"` → run `/cloverleaf-document <TASK-ID>` (the Documenter adds doc commits and advances `implementing → documenting`).
|
|
36
|
+
- `risk_class: "low"` (no docs) → the **runner** advances the state itself: `cloverleaf-cli advance-status <repo_root> <TASK-ID> documenting agent`, then commit (`git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> → documenting")`).
|
|
80
37
|
|
|
81
|
-
|
|
38
|
+
Either way the task reaches `documenting` before §4a advances `documenting → council`.
|
|
82
39
|
|
|
83
|
-
|
|
40
|
+
4. **Delivery council.**
|
|
41
|
+
a. Enter the phase: `cloverleaf-cli advance-status <repo_root> <TASK-ID> council agent`. Commit. (Council entry classifies security — a sensitive diff upgrades `security_class` to `high` so the blocking security member runs.)
|
|
42
|
+
b. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.review`. The plan always carries a profile: the shipped default binds `task.review` to `delivery-fast` (`risk_class: low`) / `delivery-full` (`risk_class: high`); a consumer `.cloverleaf/config/council.json` overrides.
|
|
43
|
+
c. Run the council members (section 7.2), reach the verdict (7.3 chair / 7.4 deterministic), and — **before** applying it — run the **baselines-hold check (section 4.1)**. Then, once cleared, `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.review '<verdict>'`. Commit the remainder: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> council review (<verdict>)")`.
|
|
84
44
|
|
|
85
|
-
|
|
86
|
-
a. Inline `/cloverleaf-implement <TASK-ID>` steps.
|
|
87
|
-
b. Inline `/cloverleaf-document <TASK-ID>` steps.
|
|
88
|
-
c. Inline `/cloverleaf-review <TASK-ID>` steps.
|
|
89
|
-
d. Reload task. If `status === "automated-gates"`: pass! Exit this loop.
|
|
90
|
-
e. If `status === "implementing"`: Reviewer bounced. `reviewer_bounces += 1`. If `reviewer_bounces >= MAX_REVIEWER_BOUNCES`, escalate. Else continue loop.
|
|
91
|
-
f. Else: unexpected. Report and stop.
|
|
45
|
+
### 4.1 Baselines hold (before applying a council pass)
|
|
92
46
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
5.2. **UI-path detection and conditional UI Review:**
|
|
47
|
+
The collapse removed the old `ui-review → qa` hold that `baselines_pending` guarded; the hold moves to **council pass**. After the members run (the `ui` member captures baselines and, on new/resized baselines, sets `baselines_pending=true` via `write-ui-review-state` — that mechanism is unchanged), and **before** applying a council `pass` that would advance `council → final-gate`, read the ui-review state:
|
|
96
48
|
|
|
97
49
|
```bash
|
|
98
|
-
cloverleaf-cli
|
|
50
|
+
cloverleaf-cli read-ui-review-state <repo_root> <TASK-ID>
|
|
99
51
|
```
|
|
100
52
|
|
|
101
|
-
If
|
|
102
|
-
|
|
103
|
-
- UI-review loop:
|
|
104
|
-
a. Inline `/cloverleaf-ui-review <TASK-ID>` steps.
|
|
105
|
-
b. Reload task. If `status === "qa"`: pass! Exit UI-review loop.
|
|
106
|
-
c. If `status === "implementing"`: UI Reviewer bounced. `ui_reviewer_bounces += 1`. If `>= MAX_UI_REVIEWER_BOUNCES`, escalate. Else return to section 5.1 (Implementer re-runs, which then re-documents, re-reviews).
|
|
107
|
-
d. Else: unexpected. Report and stop.
|
|
108
|
-
|
|
109
|
-
If output is `false`: skip UI review. Advance: `cloverleaf-cli advance-status <repo_root> <TASK-ID> qa agent --path=full_pipeline`. Commit.
|
|
110
|
-
|
|
111
|
-
5.3. **QA loop:**
|
|
53
|
+
- If the council verdict is `pass` **and** `baselines_pending` is `true`: do **NOT** apply the verdict. Surface to the human: "⏸ `<TASK-ID>` — new visual baselines need approval. Inspect the captured baseline images, then run `/cloverleaf-approve-baselines <TASK-ID>` (which clears `baselines_pending`) and re-run `/cloverleaf-run <TASK-ID>` — the `ui` member now passes and the council pass applies." Stop here (leave the task at `council`); the re-run re-dispatches the council with `baselines_pending=false`.
|
|
54
|
+
- Otherwise (`baselines_pending` is `false`, or the verdict is `bounce` / `escalate`): proceed to apply the verdict (step 4c). This is a runner **convention** — no FSM change, exactly as the old `ui-review → qa` hold was a convention. `/cloverleaf-approve-baselines` and the `write-baseline` guard are unchanged.
|
|
112
55
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
d. Else: unexpected. Report and stop.
|
|
118
|
-
|
|
119
|
-
5.4. **Final merge:** First run the **Advisory `final_gate` council** (§7.6) if a consumer has bound `task.final_gate`. Inline `/cloverleaf-merge <TASK-ID>` steps (branches to full-pipeline gate per state).
|
|
56
|
+
5. **Branch on the task's new status** (reload with `load-task`):
|
|
57
|
+
- `final-gate` (pass) → run the advisory `final_gate` council (section 7.6) if bound, then inline `/cloverleaf-merge <TASK-ID>`.
|
|
58
|
+
- `implementing` (bounce) → `council_bounces += 1`. If `>= 3`, escalate (section 6). Else return to 3c (re-implement; the batched council feedback is in `.cloverleaf/feedback/`).
|
|
59
|
+
- `escalated` → stop and surface (`.cloverleaf/feedback/` + `.cloverleaf/runs/<TASK-ID>/council/task.review.json`).
|
|
120
60
|
|
|
121
61
|
### 6. Escalation
|
|
122
62
|
|
|
123
63
|
- `cloverleaf-cli advance-status <repo_root> <TASK-ID> escalated agent`
|
|
124
64
|
- Commit: `git add .cloverleaf/ && git commit -m "cloverleaf: <TASK-ID> escalated (bounce budget exhausted)"`.
|
|
125
|
-
- Report: "✗ Escalated `<TASK-ID>`. Review `.cloverleaf/feedback/` and either refine the task or take over manually. Counters:
|
|
65
|
+
- Report: "✗ Escalated `<TASK-ID>`. Review `.cloverleaf/feedback/` and either refine the task or take over manually. Counters: council_bounces=<N>, plan_review_bounces=<N>."
|
|
126
66
|
|
|
127
|
-
|
|
67
|
+
## 7. Delivery council mechanics
|
|
128
68
|
|
|
129
|
-
|
|
69
|
+
The council member-dispatch, verdict, and apply steps referenced by steps 3b / 4c / 5.
|
|
130
70
|
|
|
131
|
-
7.
|
|
71
|
+
7.2 **Run the council members (verdict-only).** Re-run `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.review` to get `plan.rounds`, `plan.aggregation`, `plan.on_round_bounce`, and (for a chair profile) `plan.chair`. For each round **in order**: dispatch **all active members in the round concurrently** — issue their Task-tool calls **in a single message** so the harness runs them in parallel — and capture each member's `{verdict, summary, findings}` envelope. Do **not** advance state (the task stays at `council` until you apply the verdict at step 4c). Rounds still run in sequence; only members *within* a round are concurrent. (Built-in members resolve to the shipped `reviewer`/`security-reviewer`/`ui-reviewer`/`qa` prompts by their `promptPath`; a custom role resolves to `.cloverleaf/prompts/<file>.md`.)
|
|
132
72
|
|
|
133
|
-
|
|
73
|
+
**Dispatch conventions:** invoke the Task tool in foreground (default — never `run_in_background`); do not poll with foreground `sleep`. Substitute the five base tokens, plus every entry in that member's `substitutions` map from the plan:
|
|
74
|
+
- `{{task}}`, `{{branch}}` (`cloverleaf/<TASK-ID>`), `{{base_branch}}` (`main`), `{{repo_root}}`, `{{diff}}` (`git diff main..cloverleaf/<TASK-ID> -- ':(exclude).cloverleaf/'`) — the five base tokens, always present.
|
|
75
|
+
- `{{<key>}}` for every key in `substitutions`: `council-plan` resolves each member's extra tokens beyond the five base ones (e.g. `test_rules` for `reviewer`, `qa_rules` for `qa`, `affected_routes` / `ui_review_config` / `taskId` for `ui`; `security`'s map is empty — its prompt needs no extra tokens).
|
|
76
|
+
- **`{{preview_port}}` — the one exception.** `ui-reviewer.md` declares it, but it is deliberately NOT in the plan's `substitutions`: planning must stay side-effect free and cannot allocate a port without one. When dispatching the `ui` member, the runner must allocate a free port itself and substitute `{{preview_port}}` before dispatch — the same way the standalone `cloverleaf-ui-review` skill does: `PREVIEW_PORT=$(node -e "const net=require('net');const s=net.createServer();s.listen(0,()=>{console.log(s.address().port);s.close()})")`.
|
|
134
77
|
|
|
135
|
-
|
|
78
|
+
Never dispatch a member with an unresolved `{{…}}` token. The three bullets above are the complete set of substitution sources: the five base tokens, every key in that member's `substitutions`, and — for `ui` only — `{{preview_port}}`. Apply all three, then scan the filled prompt text; if any `{{…}}` remains, stop and report rather than letting the member improvise. (Nothing should: `tests/council.test.ts` pins every built-in prompt's declared tokens against exactly those three sources, so a leftover means the prompt and `MEMBER_TOKENS` have drifted.)
|
|
136
79
|
|
|
137
80
|
Persist each member's envelope: `echo '<envelope>' > /tmp/clv-council-<member>.json && cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/clv-council-<member>.json --prefix=<prefix>`, where `<prefix>` is `r`/`s`/`u`/`q` for the built-ins and the **member id** for a custom role. Collect a members array `[{ "member": "<id>", "verdict": "<pass|bounce|escalate>", "blocking": <plan member blocking>, "weight": <plan member weight> }]`.
|
|
138
81
|
|
|
@@ -145,28 +88,24 @@ Initialize `council_bounces = 0`.
|
|
|
145
88
|
- Otherwise (a blocking member bounced; no member escalated) **dispatch the chair.** Build enriched inputs `[{ "member", "verdict", "blocking", "weight", "envelope": <the member's /tmp/clv-council-<member>.json object> }]`; run `context=$(cloverleaf-cli chair-context '<enriched-inputs-json>')`. Dispatch the chair prompt at `plan.chair.promptPath` as a **read-only** foreground subagent, substituting `{{task}}`, `{{repo_root}}`, and `{{member_verdicts}}` = `$context`; capture its `{verdict, rationale, forward}` output. Then run `cloverleaf-cli chair-verdict '<chair-raw-json>' '<members-json>'` and capture the council verdict JSON.
|
|
146
89
|
- **Else (deterministic):** map `plan.aggregation` to the CLI rule (a string passes through; `{ "quorum": k }` → `quorum:k`) and run `cloverleaf-cli aggregate-verdicts '<members-json>' <rule>`; capture the council verdict JSON.
|
|
147
90
|
|
|
148
|
-
7.4 **Apply.**
|
|
149
|
-
|
|
150
|
-
7.5 **Branch on the task's new status (reload with `load-task`):**
|
|
151
|
-
- `automated-gates` (fast lane pass) or `final-gate` (full pipeline pass) → proceed to the merge: inline `/cloverleaf-merge <TASK-ID>`.
|
|
152
|
-
- `implementing` (bounce) → `council_bounces += 1`. If `council_bounces >= 3`, escalate (section 6). Else return to 7.1.
|
|
153
|
-
- `escalated` → stop and surface to the user (review `.cloverleaf/feedback/` and `.cloverleaf/runs/<TASK-ID>/council/task.review.json`).
|
|
91
|
+
7.4 **Apply.** After the baselines-hold check (section 4.1) clears, run `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.review '<council-verdict-json>'`. The FSM walk may self-commit some transitions (e.g. `security_class → high`, the rework verdict-reset), so the wrap-up commit can find nothing staged — that is expected. Commit the remainder: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> council review (<verdict>)")`. The verdict drives the FSM: `pass` → `council → final-gate`; `bounce` → `council → implementing`; `escalate` → `council → escalated` (branch per step 5).
|
|
154
92
|
|
|
155
93
|
On a chair **bounce**, the result artifact's `forward` array names the members whose feedback the Implementer should prioritize; the chair `rationale` frames them. The council result artifact at `.cloverleaf/runs/<TASK-ID>/council/task.review.json` records per-member verdicts, the aggregate (or chair) verdict, `forward` (for a chair bounce), and the security basis (incl. an omitted or out-voted `security` member). On any member-dispatch failure or unparseable envelope, stop and report — never treat a failed member as a pass.
|
|
156
94
|
|
|
157
|
-
### 7.6 Advisory `final_gate` council (opt-in
|
|
95
|
+
### 7.6 Advisory `final_gate` council (opt-in)
|
|
158
96
|
|
|
159
|
-
`final-gate` is
|
|
97
|
+
`final-gate` is the human merge pause. Before inlining `/cloverleaf-merge <TASK-ID>` at the final gate (step 5), check for an advisory council:
|
|
160
98
|
|
|
161
99
|
1. `cloverleaf-cli council-plan <repo_root> <TASK-ID> task.final_gate`.
|
|
162
100
|
2. If `plan.source !== "consumer"` or `plan.profile === null`, skip — proceed to the plain human merge (today's behavior).
|
|
163
101
|
3. Otherwise dispatch `plan.rounds` per §7.2 (parallel within a round), reviewing `{{diff}}` = `git diff main..cloverleaf/<TASK-ID> -- ':(exclude).cloverleaf/'`, and reach a verdict per §7.3 (chair) or §7.4-style `aggregate-verdicts` (deterministic). Then `cloverleaf-cli apply-council-verdict <repo_root> <TASK-ID> task.final_gate '<council-verdict-json>'`. This **posts** the advisory result to `.cloverleaf/runs/<TASK-ID>/council/task.final_gate.json` + a feedback envelope and **drives no transition** (the task stays at `final-gate`). Commit: `git add .cloverleaf/ && (git diff --cached --quiet || git commit -m "cloverleaf: <TASK-ID> advisory final_gate council (<verdict>)")`.
|
|
164
102
|
4. Surface the council verdict + rationale to the human at the merge confirmation. The human still drives `/cloverleaf-merge` (merge) or reject; the advisory council never merges.
|
|
165
103
|
|
|
166
|
-
|
|
104
|
+
`task.plan_review` (decisive, at `tactical-plan`) is **not currently wired** (see §3a/§3b); `task.final_gate` is advisory-only and post-only.
|
|
167
105
|
|
|
168
106
|
## Rules
|
|
169
107
|
|
|
170
|
-
-
|
|
171
|
-
- On any sub-skill error or escalation, orchestrator stops with clear message.
|
|
108
|
+
- The delivery council owns the bounce loop: `council_bounces` (max 3) and `plan_review_bounces` (max 3). There is no per-agent counter — security, UI, and QA are members.
|
|
109
|
+
- On any sub-skill error or escalation, the orchestrator stops with a clear message.
|
|
172
110
|
- Human merge gate is NOT skipped; confirmation is still required at merge time.
|
|
111
|
+
- The baselines-hold is a convention: a council `pass` is held at `baselines_pending` until `/cloverleaf-approve-baselines <TASK-ID>` clears it and the council is re-run.
|
|
@@ -162,7 +162,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
162
162
|
|
|
163
163
|
- **`tool_decision_required`** → let the walker policy decide (auto-approve per rules, defer to user for anything not covered).
|
|
164
164
|
|
|
165
|
-
- **`turn_completed [DONE]`** → the session has finished its current turn with a `[DONE]` terminal token. If the on-disk task status is `final-gate
|
|
165
|
+
- **`turn_completed [DONE]`** → the session has finished its current turn with a `[DONE]` terminal token. If the on-disk task status is `final-gate`, push onto the final-gate queue. Otherwise continue monitoring.
|
|
166
166
|
|
|
167
167
|
- **`turn_completed [NEEDS-INPUT]`** → the session is paused waiting for a user reply. Surface the assistant's last message to the driver and send the user's response via `mcp__claw-drive__send_turn`.
|
|
168
168
|
|
|
@@ -179,7 +179,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
179
179
|
```
|
|
180
180
|
This covers transient API errors (e.g. HTTP 503, `API Error: 503`) and the `temporarily unavailable` service message without requiring a Session A nudge from the human.
|
|
181
181
|
|
|
182
|
-
e. **Drain the final-gate queue serially and merge on main.** Session B does NOT invoke `/cloverleaf-merge` — it stops at
|
|
182
|
+
e. **Drain the final-gate queue serially and merge on main.** Session B does NOT invoke `/cloverleaf-merge` — it stops at final-gate and reports. The walker performs the merge on main in the primary repo. For each queued task:
|
|
183
183
|
|
|
184
184
|
**Scope check (BEFORE the y/N prompt).** Run `cloverleaf-cli check-scope` and capture its output and exit code:
|
|
185
185
|
|
|
@@ -204,10 +204,10 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
204
204
|
|
|
205
205
|
1. Print a full summary to the driver:
|
|
206
206
|
```
|
|
207
|
-
⏵ <TASK-ID> ready to merge
|
|
207
|
+
⏵ <TASK-ID> ready to merge
|
|
208
208
|
Reviewer: <summary>
|
|
209
209
|
UI Reviewer: <summary or "skipped">
|
|
210
|
-
QA: <summary or "
|
|
210
|
+
QA: <summary or "skipped">
|
|
211
211
|
Session <session_id>, worktree <worktree_path>
|
|
212
212
|
|
|
213
213
|
Confirm merge? (y/N, or ask a question)
|
|
@@ -224,7 +224,7 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
224
224
|
echo "$CHANGED_FILES" | xargs grep -l -E '^(<{7}|={7}|>{7})' 2>/dev/null
|
|
225
225
|
# Do NOT proceed; mark task escalated and surface to user
|
|
226
226
|
else
|
|
227
|
-
git -C <repo_root> merge --no-ff cloverleaf/<TASK-ID> -m "cloverleaf: <TASK-ID> merged
|
|
227
|
+
git -C <repo_root> merge --no-ff cloverleaf/<TASK-ID> -m "cloverleaf: <TASK-ID> merged"
|
|
228
228
|
fi
|
|
229
229
|
```
|
|
230
230
|
|
|
@@ -232,12 +232,8 @@ description: Autonomous DAG walker for Cloverleaf Plans. Given a PLAN-ID in stat
|
|
|
232
232
|
|
|
233
233
|
After a **successful** `git merge --no-ff`, advance state and commit:
|
|
234
234
|
```bash
|
|
235
|
-
# Fast lane:
|
|
236
|
-
cloverleaf-cli emit-gate-decision <repo_root> <TASK-ID> human_merge approve human
|
|
237
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human human_merge fast_lane
|
|
238
|
-
# Full pipeline (task is already at final-gate):
|
|
239
235
|
cloverleaf-cli emit-gate-decision <repo_root> <TASK-ID> final_approval_gate approve human
|
|
240
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human final_approval_gate
|
|
236
|
+
cloverleaf-cli advance-status <repo_root> <TASK-ID> merged human final_approval_gate
|
|
241
237
|
```
|
|
242
238
|
```bash
|
|
243
239
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> merged"
|
|
@@ -350,32 +346,29 @@ stay on the worktree's current branch (`cloverleaf/<TASK-ID>`).
|
|
|
350
346
|
|
|
351
347
|
Plan: invoke `/cloverleaf-run <TASK-ID>`.
|
|
352
348
|
|
|
353
|
-
**DO NOT invoke `/cloverleaf-merge`**.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
real `git merge --no-ff` itself after human approval — the worktree's main
|
|
358
|
-
branch can't be checked out concurrently, which is why the walker owns the
|
|
359
|
-
merge. If `/cloverleaf-run` would normally invoke `/cloverleaf-merge`
|
|
360
|
-
internally (fast-lane orchestrator), interrupt before that step and exit.
|
|
361
|
-
|
|
362
|
-
All four v0.5.2+v0.5.3+v0.5.4+v0.5.5 dogfood fixes are in place:
|
|
363
|
-
- /cloverleaf-merge actor: human final_approval_gate full_pipeline.
|
|
349
|
+
**DO NOT invoke `/cloverleaf-merge`**. Delivery lands the task at `final-gate`; do NOT invoke `/cloverleaf-merge`; report status + summaries at that point and exit cleanly. The walker runs in the primary repo on `main` and performs the real `git merge --no-ff` itself after human approval — the worktree's main branch can't be checked out concurrently, which is why the walker owns the merge.
|
|
350
|
+
|
|
351
|
+
All v0.5.2+v0.5.3+v0.5.4+v0.5.5 dogfood fixes are in place:
|
|
352
|
+
- /cloverleaf-merge actor: human final_approval_gate.
|
|
364
353
|
- cloverleaf-cli prep-worktree is idempotent.
|
|
365
354
|
- Documenter runs `git status --porcelain` and stages every modified doc.
|
|
366
355
|
- cloverleaf-ui-review uses /cloverleaf-approve-baselines (fully-qualified).
|
|
367
356
|
|
|
368
|
-
Expected: zero interventions until you reach
|
|
369
|
-
then exit.
|
|
357
|
+
Expected: zero interventions until you reach final-gate, then exit.
|
|
370
358
|
|
|
371
359
|
Do not push. Do not publish. Report merge + state commit SHAs on completion.
|
|
372
360
|
```
|
|
373
361
|
|
|
374
362
|
## Walker policy
|
|
375
363
|
|
|
376
|
-
The walker spawns each Session B with a conservative
|
|
364
|
+
The walker spawns each Session B with a conservative policy resolving every tool call to one of four outcomes:
|
|
365
|
+
|
|
366
|
+
- **auto-approve** — Read/Glob/Grep, git reads (including `git -C <path> …`), `npm`/`npx`, `node <script>`, `cloverleaf-cli` anywhere in a compound script, and the usual `set -e` / `cd` / `export` / `source` prefixes.
|
|
367
|
+
- **auto-defer** — pauses for a human: `sudo`/`su`, and anything that runs code the command regex cannot inspect (`node -e`/`-p`, `python -c`, `perl -e`, `sh -c`, `eval`), plus `chmod -R 777`, `chown -R`, `truncate`, `systemctl stop`.
|
|
368
|
+
- **auto-reject** — recursive `rm`, `git push`, `git reset --hard`, `npm publish`, `curl … | bash`, disk-destructive ops (`dd if=`, `mkfs`, `shred`, `fdisk`), writes to real block devices, and writes to claw-drive's own policy file or `.claw-drive/` runtime state.
|
|
369
|
+
- **escalate** — everything else goes to the walker for human-in-the-loop handling.
|
|
377
370
|
|
|
378
|
-
The concrete policy
|
|
371
|
+
The concrete policy is `.cloverleaf/claw-drive-policy.json` in this repo — a starting template, not a guarantee; tune it for your own project. It tracks claw-drive's shipped starter with a few deliberate divergences, each recorded in the file's own `_comment`. After editing it, run `node .cloverleaf/policy-check.mjs`, which asserts the decision for every command in `.cloverleaf/policy-probes.tsv` and exits non-zero on a regression.
|
|
379
372
|
|
|
380
373
|
## Rules
|
|
381
374
|
|
|
@@ -395,4 +388,4 @@ The concrete policy JSON is the same one used during the CLV-16..CLV-20 dogfood
|
|
|
395
388
|
|
|
396
389
|
**RFC-direct task participation in RFC auto-advance.** Tasks with no `parent` field but with `context.rfc` set (created via `/cloverleaf-new-task --rfc=<RFC-ID>`) are *first-class* participants in the `can_auto_advance_rfc` check. They block the advance when in-flight; they count toward delivery when merged. See `cloverleaf-cli rfc-tasks <repo_root> <RFC-ID>` for the categorized view this dispatch reads from, or `reference-impl/README.md` § "Plans vs RFC-direct tasks" for the user-facing pattern docs.
|
|
397
390
|
|
|
398
|
-
**Security-review escalations.** When a task's effective `security_class` is high, `/cloverleaf-run` routes it through `security-review`
|
|
391
|
+
**Security-review escalations.** When a task's effective `security_class` is high, `/cloverleaf-run` routes it through `security-review` as a council member. A `blocker` finding (e.g. a leaked credential) advances the task to `escalated`, which surfaces through the walker's existing escalation path — expect and surface these like any other escalation; do not auto-retry a security blocker.
|
|
@@ -1,9 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cloverleaf-security-review
|
|
3
|
-
description: Run the Security Reviewer
|
|
3
|
+
description: Run the Security Reviewer council member on a task's feature branch as a standalone one-off. Hybrid two-pass (deterministic secret scan + LLM vulnerability judgment). Emit-only — it records the `security_review_verdict`, writes a feedback envelope, and reports the verdict (pass/bounce/escalate) for the delivery council or a human to apply. It does NOT advance the task FSM. Usage — /cloverleaf-security-review <TASK-ID>.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Cloverleaf — security review
|
|
6
|
+
# Cloverleaf — security review (emit-only council member)
|
|
7
|
+
|
|
8
|
+
The delivery states `security-review`/`automated-gates` no longer exist — the `@cloverleaf/standard` task FSM
|
|
9
|
+
collapsed them into a single `council` phase (Council Slice 4). The Security Reviewer is now a **council member**
|
|
10
|
+
that the runner (`/cloverleaf-run`) dispatches; its blocking verdict gates the aggregated council result. A single
|
|
11
|
+
member cannot drive the multi-member council to merge, so this standalone skill is **emit-only**: it runs the two
|
|
12
|
+
passes against the task's branch, records the `security_review_verdict`, emits the feedback envelope, and reports
|
|
13
|
+
the verdict. **It does not advance the FSM** — the council or a human applies the aggregated verdict via
|
|
14
|
+
`apply-council-verdict` (which is what advances `council → final-gate`/`implementing`/`escalated` and records the
|
|
15
|
+
authoritative security backstop for high-security tasks).
|
|
7
16
|
|
|
8
17
|
## Steps
|
|
9
18
|
|
|
@@ -14,7 +23,7 @@ description: Run the Security Reviewer agent on a task in the `security-review`
|
|
|
14
23
|
|
|
15
24
|
1. Capture the TASK-ID argument.
|
|
16
25
|
|
|
17
|
-
2. Load the task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`.
|
|
26
|
+
2. Load the task: `cloverleaf-cli load-task <repo_root> <TASK-ID>`. Light guard only: confirm the task exists and is not terminal (`merged`/`rejected`/`escalated`). Do NOT hard-require any particular state — this skill reviews the branch, not a specific FSM state. If the task is terminal, report the current status and stop.
|
|
18
27
|
|
|
19
28
|
3. Confirm the branch `cloverleaf/<TASK-ID>` exists: `git rev-parse --verify cloverleaf/<TASK-ID>`. If missing, report the discrepancy and stop. Compute the diff for the subagent (do NOT check out): `git diff main..cloverleaf/<TASK-ID>`.
|
|
20
29
|
|
|
@@ -38,43 +47,39 @@ description: Run the Security Reviewer agent on a task in the `security-review`
|
|
|
38
47
|
- else any `error` or `warning` → `verdict: "bounce"`
|
|
39
48
|
- else (only `info`, or none) → `verdict: "pass"`
|
|
40
49
|
|
|
41
|
-
7. **
|
|
50
|
+
7. **Emit the verdict + envelope (no FSM advance).**
|
|
51
|
+
|
|
52
|
+
Record the member's `security_review_verdict` on the task (a live field the council's `council → final-gate` backstop reads for high-security tasks), then emit the merged feedback envelope. **Never call `advance-status`** — the council/human applies the aggregated verdict.
|
|
42
53
|
|
|
43
54
|
**Pass:**
|
|
44
55
|
```bash
|
|
45
56
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict pass
|
|
46
57
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → pass"
|
|
47
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> automated-gates agent
|
|
48
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review passed → automated-gates"
|
|
49
58
|
```
|
|
50
|
-
Report: "✓ Security
|
|
59
|
+
Report: "✓ Security Reviewer verdict: **pass**. Recorded `security_review_verdict=pass`. This is one council member's verdict — the delivery council (`/cloverleaf-run <TASK-ID>`) or a human applies the aggregated verdict (`apply-council-verdict`); this skill does not advance the FSM."
|
|
51
60
|
|
|
52
61
|
**Bounce:**
|
|
53
62
|
```bash
|
|
54
63
|
echo '<merged-envelope-json>' > /tmp/cloverleaf-fb-s.json
|
|
55
|
-
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json
|
|
64
|
+
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json --prefix=s
|
|
56
65
|
git -C <repo_root> add .cloverleaf/feedback/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review feedback"
|
|
57
66
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict bounce
|
|
58
67
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → bounce"
|
|
59
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> implementing agent
|
|
60
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review bounced → implementing"
|
|
61
68
|
```
|
|
62
|
-
Report: "✗ Security
|
|
69
|
+
Report: "✗ Security Reviewer verdict: **bounce**. Findings: <summarize by severity>. Feedback emitted to `.cloverleaf/feedback/<TASK-ID>-s<N>.json`. The delivery council or a human applies the verdict (a council bounce loops the task back to `implementing`); this skill does not advance the FSM."
|
|
63
70
|
|
|
64
71
|
**Escalate (blocker found):**
|
|
65
72
|
```bash
|
|
66
73
|
echo '<merged-envelope-json>' > /tmp/cloverleaf-fb-s.json
|
|
67
|
-
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json
|
|
74
|
+
cloverleaf-cli write-feedback <repo_root> <TASK-ID> /tmp/cloverleaf-fb-s.json --prefix=s
|
|
68
75
|
git -C <repo_root> add .cloverleaf/feedback/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review feedback"
|
|
69
76
|
cloverleaf-cli set-task-field <repo_root> <TASK-ID> security_review_verdict escalate
|
|
70
77
|
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security_review_verdict → escalate"
|
|
71
|
-
cloverleaf-cli advance-status <repo_root> <TASK-ID> escalated agent
|
|
72
|
-
git -C <repo_root> add .cloverleaf/ && git -C <repo_root> commit -m "cloverleaf: <TASK-ID> security review escalated (blocker finding)"
|
|
73
78
|
```
|
|
74
|
-
Report: "⚠ Security
|
|
79
|
+
Report: "⚠ Security Reviewer verdict: **escalate** — a BLOCKER was found. Recorded `security_review_verdict=escalate` and emitted feedback to `.cloverleaf/feedback/<TASK-ID>-s<N>.json`. A human MUST review `.cloverleaf/feedback/` before this can proceed. The council or a human applies the verdict (a council escalate is un-lowerable → `escalated`); this skill does not advance the FSM."
|
|
75
80
|
|
|
76
81
|
## Rules
|
|
77
82
|
|
|
78
83
|
- Never push. Read-only on source — the security reviewer does not modify code.
|
|
79
|
-
- A `blocker` (e.g. a leaked credential) ALWAYS
|
|
80
|
-
-
|
|
84
|
+
- A `blocker` (e.g. a leaked credential) ALWAYS yields an `escalate` verdict; never let a bounce loop silently "fix" it. The council/human enforces the terminal escalation.
|
|
85
|
+
- Emit-only: never call `advance-status`. This is one council member's verdict; the council/human applies it.
|