brainclaw 1.26.1 → 1.27.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 +41 -12
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli/register-coordination.js +65 -1
- package/dist/commands/attempt-authority.js +80 -0
- package/dist/commands/harvest.js +140 -61
- package/dist/commands/loop.js +34 -0
- package/dist/commands/loops-handlers.js +87 -14
- package/dist/commands/mcp-catalog.js +42 -18
- package/dist/commands/mcp-schemas.generated.js +44 -0
- package/dist/commands/mcp-write-claims.js +128 -1
- package/dist/commands/mcp-write-coordination.js +146 -76
- package/dist/core/agent-capability.js +1 -1
- package/dist/core/agent-files.js +21 -21
- package/dist/core/agentrun-reconciler.js +148 -22
- package/dist/core/agentruns.js +254 -29
- package/dist/core/assignment-request-schema.js +7 -0
- package/dist/core/assignment-sweeper.js +5 -3
- package/dist/core/assignments.js +131 -33
- package/dist/core/claim-request-schema.js +7 -0
- package/dist/core/claims.js +53 -2
- package/dist/core/dispatch-status.js +16 -6
- package/dist/core/dispatcher.js +51 -51
- package/dist/core/entity-operations.js +20 -0
- package/dist/core/events.js +4 -0
- package/dist/core/execution-adapters.js +160 -14
- package/dist/core/execution-contract.js +345 -0
- package/dist/core/execution.js +130 -16
- package/dist/core/harness-adapters/base.js +150 -0
- package/dist/core/harness-adapters/claude.js +39 -0
- package/dist/core/harness-adapters/codex.js +57 -0
- package/dist/core/harness-adapters/harvest.js +109 -0
- package/dist/core/harness-adapters/index.js +8 -0
- package/dist/core/harness-adapters/prompt-only.js +13 -0
- package/dist/core/harness-adapters/registry.js +48 -0
- package/dist/core/harness-adapters/result.js +33 -0
- package/dist/core/harness-adapters/types.js +2 -0
- package/dist/core/ideation-loop-close.js +25 -2
- package/dist/core/instruction-templates.js +3 -2
- package/dist/core/loop-turn-dispatch.js +207 -0
- package/dist/core/loops/artifact-contract.js +11 -0
- package/dist/core/loops/attempt-authority.js +476 -0
- package/dist/core/loops/attempt-generations.js +509 -0
- package/dist/core/loops/attempt-reservation.js +197 -35
- package/dist/core/loops/attempt-rollout.js +404 -0
- package/dist/core/loops/attempt-takeover.js +155 -0
- package/dist/core/loops/bootstrap-acquire.js +7 -3
- package/dist/core/loops/evidence.js +187 -0
- package/dist/core/loops/facade-schema.js +41 -10
- package/dist/core/loops/gate-policy.js +485 -0
- package/dist/core/loops/impl-bind.js +37 -79
- package/dist/core/loops/index.js +9 -0
- package/dist/core/loops/iteration-engine.js +31 -19
- package/dist/core/loops/kind-policies.js +90 -0
- package/dist/core/loops/lock.js +71 -13
- package/dist/core/loops/reconcile-turn.js +235 -18
- package/dist/core/loops/result-reducers.js +99 -10
- package/dist/core/loops/store.js +30 -3
- package/dist/core/loops/turn-execution.js +480 -0
- package/dist/core/loops/types.js +113 -2
- package/dist/core/loops/verbs.js +332 -99
- package/dist/core/loops/verify-command.js +31 -8
- package/dist/core/loops/workspace-digest.js +54 -0
- package/dist/core/protocol-tool-policy.js +44 -0
- package/dist/core/review-loop-close.js +25 -3
- package/dist/core/review-loop-turn-dispatch.js +210 -161
- package/dist/core/runtime-signals.js +62 -25
- package/dist/core/schema.js +35 -0
- package/dist/core/spawn-check.js +3 -2
- package/dist/core/upgrades/backup.js +27 -4
- package/dist/facts.js +9 -8
- package/dist/facts.json +8 -7
- package/docs/PROTOCOL.md +6 -4
- package/docs/cli.md +49 -1
- package/docs/concepts/attempt-authority.md +407 -0
- package/docs/concepts/evidence-attestations.md +135 -0
- package/docs/concepts/execution-contract.md +166 -0
- package/docs/concepts/harness-adapters.md +166 -0
- package/docs/concepts/ideation-loop.md +5 -4
- package/docs/concepts/loop-engine.md +348 -133
- package/docs/index.md +4 -1
- package/docs/integrations/codex.md +3 -3
- package/docs/integrations/hermes.md +42 -3
- package/docs/integrations/mcp.md +75 -9
- package/docs/loops/debug.md +144 -0
- package/docs/loops/ideation.md +158 -0
- package/docs/loops/implementation.md +154 -0
- package/docs/loops/research.md +136 -0
- package/docs/loops/review.md +200 -0
- package/docs/mcp-schema-changelog.md +14 -5
- package/docs/product/agent-first-model.md +33 -33
- package/package.json +1 -1
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# Implementation loop
|
|
2
|
+
|
|
3
|
+
> Loop kind: `implementation`. One of five equal protocols driven by the shared
|
|
4
|
+
> [Loop Engine](../concepts/loop-engine.md). Identity, dispatch decisions and
|
|
5
|
+
> spawn authority belong to [`AttemptAuthority`](../concepts/attempt-authority.md);
|
|
6
|
+
> nothing on this page overrides them.
|
|
7
|
+
|
|
8
|
+
The `execute` worker returns `artifact_type: "execute_report"`. Because this
|
|
9
|
+
phase edits its worktree, report-only harvest does not settle the turn or
|
|
10
|
+
release its claim; convergence happens after `harvest --integrate`.
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
An `implementation` loop drives a bound plan+sequence to a green
|
|
15
|
+
verification command. It ADDS to the dispatch pipeline what that pipeline
|
|
16
|
+
lacked: a deterministic `command_green` gate, a bounded `execute ↔ verify`
|
|
17
|
+
cycle, and per-phase context sculpting. `bind` is an engine-only action: it
|
|
18
|
+
validates the plan/sequence link and advances to `execute`. It never launches
|
|
19
|
+
a worker. `execute ↔ verify` iterates until the verify command is green or
|
|
20
|
+
the cycle cap is hit.
|
|
21
|
+
|
|
22
|
+
## Default protocol
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
bind → execute ↔ verify → handoff_ready
|
|
26
|
+
└── iterate (≤3) ───┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
| Phase | Purpose | Artifact | Context filter |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `bind` | Validate the linked plan + sequence; advance to `execute` | link already stored on the loop | `plans`, `decisions`, `constraints`, `project_vision` |
|
|
32
|
+
| `execute` | Apply the sequence's steps in the worktree | edits + `execute_report` | `decisions`, `constraints`, `traps`, `runtime_notes` |
|
|
33
|
+
| `verify` | Run the declared verify command | `verify_report` | `traps`, `runtime_notes` |
|
|
34
|
+
| `handoff_ready` | Produce the handoff for downstream review | `handoff` | `handoffs`, `plans` |
|
|
35
|
+
|
|
36
|
+
**Iteration.** `execute ↔ verify` cycles up to `max_iterations: 3`.
|
|
37
|
+
`exit_when: 'command_green'` exits early on a passing `verify_report` in the
|
|
38
|
+
current iteration. `advance_when: 'all'` on each phase means every
|
|
39
|
+
participating slot must produce its expected artifact before advance fires.
|
|
40
|
+
|
|
41
|
+
## Entry points
|
|
42
|
+
|
|
43
|
+
- **Direct open (typical).**
|
|
44
|
+
`bclaw_loop(intent='open', kind='implementation', slots=[…], linked={plan_ids:[…], sequence_ids:[…]}, allow_orphan=true)`
|
|
45
|
+
followed by `bind`. `allow_orphan=true` acknowledges that the caller will
|
|
46
|
+
drive worker turns.
|
|
47
|
+
- **Via bind.** `bclaw_loop(intent='bind', loop_id=…)` validates the linked
|
|
48
|
+
sequence and advances `bind → execute`. Historical launch options
|
|
49
|
+
(`lanes`, `auto_execute`, `model`, `max_assignments`) remain accepted
|
|
50
|
+
during rollout but are ignored; the response carries a migration warning.
|
|
51
|
+
- **Explicit worker turn.** In `execute`, trusted
|
|
52
|
+
`bclaw_loop(intent='turn', loop_id=…, slot_id=…, dispatch=true)` is the only
|
|
53
|
+
worker launch path and uses the common AttemptAuthority fence. Independent
|
|
54
|
+
slots may be dispatched concurrently. Without `dispatch=true`, `turn` is
|
|
55
|
+
state-only and never starts a process.
|
|
56
|
+
|
|
57
|
+
## Advance gates
|
|
58
|
+
|
|
59
|
+
`verify` carries an `advance_gate`:
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
{ kind: 'min_artifacts_by_type', type: 'verify_report', n: 1, scope: 'phase' }
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Advance cannot leave `verify` without a `verify_report` artifact **this
|
|
66
|
+
iteration** — this guards the narrated-verify anti-pattern where a slot
|
|
67
|
+
claims it verified without actually running the command. `command_green` in
|
|
68
|
+
the iteration engine reads the reports produced against this gate.
|
|
69
|
+
|
|
70
|
+
## Stop condition
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
{ kind: 'any', conditions: [
|
|
74
|
+
{ kind: 'artifact_produced', phase: 'handoff_ready', type: 'handoff' },
|
|
75
|
+
{ kind: 'max_iterations', n: 3 },
|
|
76
|
+
] }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
- **Handoff produced** → close `completed`. The handoff is the downstream
|
|
80
|
+
consumer's entry point.
|
|
81
|
+
- **Cycle cap** → close `blocked`; the last red `verify_report` is
|
|
82
|
+
attached so a human or a `debug` loop can pick up.
|
|
83
|
+
|
|
84
|
+
## Artifacts
|
|
85
|
+
|
|
86
|
+
| Type | Phase | Body |
|
|
87
|
+
|---|---|---|
|
|
88
|
+
| `execute_report` | `execute` | inline text ≤ 4 KB, or ref-based when large |
|
|
89
|
+
| `verify_report` | `verify` | inline JSON: `{ command, exit_code, passed, duration_ms?, stdout_tail?, stderr_tail? }` |
|
|
90
|
+
| `file_diff` | any phase | ref-based body (`{ref, byte_count, sha256}`) |
|
|
91
|
+
| `handoff` | `handoff_ready` | `ref` to a `handoff` primitive |
|
|
92
|
+
|
|
93
|
+
## Routing
|
|
94
|
+
|
|
95
|
+
`implementation` is claim-routed: each worker `slot.claim_id` points at the
|
|
96
|
+
scope claim created by `turn(dispatch=true)`, and the common driver runs in
|
|
97
|
+
the worktree bound to that claim. `bind` creates neither claim nor assignment.
|
|
98
|
+
`session_id` is observability-only.
|
|
99
|
+
[Attempt authority](../concepts/attempt-authority.md#ordered-dispatch)
|
|
100
|
+
mints a deterministic `turn_id` from `(loop_id, slot_id, iteration)` on
|
|
101
|
+
every dispatch, so a concurrent re-dispatch hits `reservation_exists` and
|
|
102
|
+
adopts the existing attempt. If a reusable slot has already spent that legacy
|
|
103
|
+
identity in another worker phase of the same iteration, the common resolver
|
|
104
|
+
uses `(loop_id, slot_id, phase, iteration)` for a versioned successor logical
|
|
105
|
+
turn. This is a Loop Engine rule shared by every kind, not implementation-loop
|
|
106
|
+
special handling.
|
|
107
|
+
|
|
108
|
+
## Recovery
|
|
109
|
+
|
|
110
|
+
- **Execute worker crashed mid-iteration.** Launch grant lease expires;
|
|
111
|
+
`sweepExpiredLaunchGrants` revokes it; a re-dispatch arms a new
|
|
112
|
+
generation at a strictly greater epoch. Because `execute_report` and
|
|
113
|
+
`verify_report` are per-iteration, a prior-iteration report never
|
|
114
|
+
satisfies the current iteration's gate.
|
|
115
|
+
- **`verify_report` red at cap.** Loop closes `blocked`; the last red
|
|
116
|
+
`verify_report` and the accumulated `execute_report`s stay on the loop
|
|
117
|
+
as evidence.
|
|
118
|
+
- **Command-green mid-cycle.** `exit_when: 'command_green'` short-circuits
|
|
119
|
+
the cycle; the driver advances to `handoff_ready` on the next `advance`.
|
|
120
|
+
- **Stale worker LANE-RESULT resurfaces after a cycle bump.**
|
|
121
|
+
`evidenceMatchesAttempt` rejects it — the current-generation nonce no
|
|
122
|
+
longer matches the stale token.
|
|
123
|
+
|
|
124
|
+
## When NOT to use
|
|
125
|
+
|
|
126
|
+
- **Debugging an already-broken build.** Use [`debug`](./debug.md) — its
|
|
127
|
+
`reproduce` phase gives you a repro artifact the fix rides on, and its
|
|
128
|
+
`command_green` gate is the same shape.
|
|
129
|
+
- **Validating a change that already exists.** Use
|
|
130
|
+
[`review`](./review.md).
|
|
131
|
+
- **Choosing between architectural options.** Use
|
|
132
|
+
[`ideation`](./ideation.md) — an implementation loop with no plan is
|
|
133
|
+
empty.
|
|
134
|
+
- **Open-ended discovery.** Use [`research`](./research.md).
|
|
135
|
+
|
|
136
|
+
## Reference implementation
|
|
137
|
+
|
|
138
|
+
| Component | File |
|
|
139
|
+
|---|---|
|
|
140
|
+
| Default protocol | [`src/core/loops/types.ts`](../../src/core/loops/types.ts) (`DEFAULT_PROTOCOLS.implementation`) |
|
|
141
|
+
| Bind action | [`src/core/loops/impl-bind.ts`](../../src/core/loops/impl-bind.ts) (`runImplBind`) |
|
|
142
|
+
| Common worker driver | [`src/core/loop-turn-dispatch.ts`](../../src/core/loop-turn-dispatch.ts) (`dispatchLoopTurn`) |
|
|
143
|
+
| Iteration FSM (command_green) | [`src/core/loops/iteration-engine.ts`](../../src/core/loops/iteration-engine.ts) |
|
|
144
|
+
| Attempt authority | [`src/core/loops/attempt-authority.ts`](../../src/core/loops/attempt-authority.ts) |
|
|
145
|
+
| Turn execution policy | [`src/core/loops/kind-policies.ts`](../../src/core/loops/kind-policies.ts), [`src/core/loops/turn-execution.ts`](../../src/core/loops/turn-execution.ts) |
|
|
146
|
+
| Result reducer | [`src/core/loops/result-reducers.ts`](../../src/core/loops/result-reducers.ts) |
|
|
147
|
+
| Tests | [`tests/unit/loops-impl-bind.test.ts`](../../tests/unit/loops-impl-bind.test.ts), [`tests/unit/loops-impl-protocol.test.ts`](../../tests/unit/loops-impl-protocol.test.ts), [`tests/unit/loops-gate-content-integrity.test.ts`](../../tests/unit/loops-gate-content-integrity.test.ts) |
|
|
148
|
+
|
|
149
|
+
## Related
|
|
150
|
+
|
|
151
|
+
- [Loop Engine](../concepts/loop-engine.md)
|
|
152
|
+
- [Attempt authority](../concepts/attempt-authority.md)
|
|
153
|
+
- [plans-and-claims.md](../concepts/plans-and-claims.md)
|
|
154
|
+
- [dispatch-lifecycle.md](../concepts/dispatch-lifecycle.md)
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# Research loop
|
|
2
|
+
|
|
3
|
+
> Loop kind: `research`. One of five equal protocols driven by the shared
|
|
4
|
+
> [Loop Engine](../concepts/loop-engine.md). Identity, dispatch decisions and
|
|
5
|
+
> spawn authority belong to [`AttemptAuthority`](../concepts/attempt-authority.md);
|
|
6
|
+
> nothing on this page overrides them.
|
|
7
|
+
|
|
8
|
+
Worker results are explicit: `finding` for `investigate` and `synthesis` for
|
|
9
|
+
`synthesize`. Both are read-only results and may converge during report harvest.
|
|
10
|
+
|
|
11
|
+
## Purpose
|
|
12
|
+
|
|
13
|
+
A `research` loop converges an open-ended question into a synthesised
|
|
14
|
+
answer. It runs findings-then-synthesis rounds until the synthesiser
|
|
15
|
+
declares the question sufficiently answered. Unlike
|
|
16
|
+
[`implementation`](./implementation.md) or [`debug`](./debug.md), `research`
|
|
17
|
+
has no "green command" — the exit is an explicit sufficiency signal from
|
|
18
|
+
the synthesiser, and there is no `blocked` outcome: every research loop
|
|
19
|
+
lands in `conclude`.
|
|
20
|
+
|
|
21
|
+
## Default protocol
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
investigate ↔ synthesize → conclude
|
|
25
|
+
└── iterate (≤3) ──┘
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Phase | Purpose | Artifact | Context filter |
|
|
29
|
+
|---|---|---|---|
|
|
30
|
+
| `investigate` | Gather findings against the question | `finding` (repeatable) | `plans`, `decisions`, `constraints`, `project_vision`, `candidates`, `runtime_notes`, `traps` |
|
|
31
|
+
| `synthesize` | Fold findings; assess sufficiency | `synthesis`, optional `critic_signal` | `*` |
|
|
32
|
+
| `conclude` | Publish the final synthesis | `synthesis` | `*` |
|
|
33
|
+
|
|
34
|
+
**Iteration.** `investigate ↔ synthesize` cycles up to
|
|
35
|
+
`max_iterations: 3`. `exit_when: 'critic_signal'` — the synthesiser opts an
|
|
36
|
+
explicit early exit by emitting a `critic_signal` artifact when it judges
|
|
37
|
+
the question answered. Explicit sufficiency beats saturation-by-absence for
|
|
38
|
+
open-ended research.
|
|
39
|
+
|
|
40
|
+
## Entry points
|
|
41
|
+
|
|
42
|
+
- **Direct open.**
|
|
43
|
+
`bclaw_loop(intent='open', kind='research', title=…, goal=…, allow_orphan=true)`
|
|
44
|
+
followed by `turn`/`advance`. There is no coordinator shortcut for
|
|
45
|
+
`research` today; the caller drives each round. Plain `turn` is state-only;
|
|
46
|
+
trusted `turn(dispatch=true)` launches an investigator or synthesiser
|
|
47
|
+
through the common AttemptAuthority path.
|
|
48
|
+
- **Custom stop_condition** — override the default artifact-produced stop
|
|
49
|
+
with any [`StopCondition`](../../src/core/loops/types.ts) — e.g.
|
|
50
|
+
`min_artifacts_by_type { type: 'finding', n: 5, scope: 'loop' }` for a
|
|
51
|
+
"harvest at least five findings" pattern.
|
|
52
|
+
|
|
53
|
+
## Advance gates
|
|
54
|
+
|
|
55
|
+
`investigate` carries an `advance_gate`:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
{ kind: 'min_artifacts_by_type', type: 'finding', n: 1, scope: 'phase' }
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
Advance cannot leave `investigate` without at least one `finding` produced
|
|
62
|
+
in the current iteration window. This prevents synthesising an empty round.
|
|
63
|
+
|
|
64
|
+
## Stop condition
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
{ kind: 'artifact_produced', phase: 'conclude', type: 'synthesis' }
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
The loop closes `completed` on the first `synthesis` artifact in `conclude`.
|
|
71
|
+
There is **no `max_iterations` in the stop condition** — research always
|
|
72
|
+
lands in `conclude` and produces a synthesis, even if the cycle cap was
|
|
73
|
+
reached earlier (the driver advances anyway).
|
|
74
|
+
|
|
75
|
+
## Artifacts
|
|
76
|
+
|
|
77
|
+
| Type | Phase | Body |
|
|
78
|
+
|---|---|---|
|
|
79
|
+
| `finding` | `investigate` | inline ≤ 4 KB; cites the source memory / files used |
|
|
80
|
+
| `synthesis` | `synthesize` / `conclude` | inline ≤ 4 KB, or ref-based when large |
|
|
81
|
+
| `critic_signal` | `synthesize` | inline signal that the question is answered |
|
|
82
|
+
|
|
83
|
+
Findings should cite the memory ids or file paths they draw from so the
|
|
84
|
+
final synthesis is auditable.
|
|
85
|
+
|
|
86
|
+
## Routing
|
|
87
|
+
|
|
88
|
+
`research` routes turns by `slot_id`; the caller assigns investigator and
|
|
89
|
+
synthesiser slots when opening the loop. Multiple investigator slots may
|
|
90
|
+
run in parallel per iteration when `advance_when: 'any'` is set on the
|
|
91
|
+
phase — otherwise the default `all` requires every investigator to turn
|
|
92
|
+
in before synthesise fires.
|
|
93
|
+
|
|
94
|
+
## Recovery
|
|
95
|
+
|
|
96
|
+
- **Investigator worker crashed mid-turn.** Launch grant lease expires;
|
|
97
|
+
`sweepExpiredLaunchGrants` revokes it; a re-dispatch arms a new
|
|
98
|
+
generation. Prior-iteration findings never satisfy the current
|
|
99
|
+
iteration's gate.
|
|
100
|
+
- **Synthesiser did not emit `critic_signal` by cap.** The cycle exits on
|
|
101
|
+
`max_iterations_reached` (system event) and the driver advances to
|
|
102
|
+
`conclude`; the last `synthesis` becomes the concluding artifact.
|
|
103
|
+
- **`finding` gate blocked with zero findings.** The
|
|
104
|
+
`phase_advance_blocked` system event records the structured reason.
|
|
105
|
+
Add a finding, or open a new loop with the gate overridden.
|
|
106
|
+
- **Stale prior-generation LANE-RESULT.** Rejected by
|
|
107
|
+
[`evidenceMatchesAttempt`](../concepts/attempt-authority.md#functional-api).
|
|
108
|
+
|
|
109
|
+
## When NOT to use
|
|
110
|
+
|
|
111
|
+
- **The question already has a candidate answer to validate.** Use
|
|
112
|
+
[`review`](./review.md).
|
|
113
|
+
- **The question is "how do we build X?" with an architectural choice
|
|
114
|
+
hidden inside.** Use [`ideation`](./ideation.md) — memory-driven
|
|
115
|
+
critique surfaces conflicts that generic research does not.
|
|
116
|
+
- **The question is "why is the build broken?"** Use
|
|
117
|
+
[`debug`](./debug.md) — its `reproduce` phase is exactly the
|
|
118
|
+
find-the-cause pattern.
|
|
119
|
+
- **Executing an already-planned change.** Use
|
|
120
|
+
[`implementation`](./implementation.md).
|
|
121
|
+
|
|
122
|
+
## Reference implementation
|
|
123
|
+
|
|
124
|
+
| Component | File |
|
|
125
|
+
|---|---|
|
|
126
|
+
| Default protocol | [`src/core/loops/types.ts`](../../src/core/loops/types.ts) (`DEFAULT_PROTOCOLS.research`) |
|
|
127
|
+
| Iteration FSM (`critic_signal`) | [`src/core/loops/iteration-engine.ts`](../../src/core/loops/iteration-engine.ts) |
|
|
128
|
+
| Gate evaluator | [`src/core/loops/verbs.ts`](../../src/core/loops/verbs.ts) (`evaluatePhaseAdvanceGate`) |
|
|
129
|
+
| Attempt + execution policy | [`src/core/loops/attempt-authority.ts`](../../src/core/loops/attempt-authority.ts), [`src/core/loops/kind-policies.ts`](../../src/core/loops/kind-policies.ts) |
|
|
130
|
+
| Result reducer | [`src/core/loops/result-reducers.ts`](../../src/core/loops/result-reducers.ts) |
|
|
131
|
+
| Tests | [`tests/unit/loops-iteration-engine.test.ts`](../../tests/unit/loops-iteration-engine.test.ts), [`tests/unit/loops-phase-advance-gate.test.ts`](../../tests/unit/loops-phase-advance-gate.test.ts) |
|
|
132
|
+
|
|
133
|
+
## Related
|
|
134
|
+
|
|
135
|
+
- [Loop Engine](../concepts/loop-engine.md)
|
|
136
|
+
- [Attempt authority](../concepts/attempt-authority.md)
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Review loop
|
|
2
|
+
|
|
3
|
+
> Loop kind: `review`. One of five equal protocols driven by the shared
|
|
4
|
+
> [Loop Engine](../concepts/loop-engine.md). Identity, dispatch decisions and
|
|
5
|
+
> spawn authority belong to [`AttemptAuthority`](../concepts/attempt-authority.md);
|
|
6
|
+
> nothing on this page overrides them.
|
|
7
|
+
|
|
8
|
+
Reviewer phases return the structured verdict fields; `author_response`
|
|
9
|
+
returns `artifact_type: "author_response"` with its evidence in `body`. Since
|
|
10
|
+
that phase changes the worktree, it converges only after `harvest --integrate`.
|
|
11
|
+
|
|
12
|
+
## Purpose
|
|
13
|
+
|
|
14
|
+
A `review` loop validates a change that already happened. The change lives on
|
|
15
|
+
a candidate, a handoff, a diff, or another primitive the caller passes in; the
|
|
16
|
+
loop drives a reviewer through evidence, findings, an author response, and a
|
|
17
|
+
verdict, until either the reviewer greenlights or an iteration cap forces the
|
|
18
|
+
loop to stop.
|
|
19
|
+
|
|
20
|
+
`review` is the workflow with the most automated coordinator shortcut, but it
|
|
21
|
+
runs on the same engine as `ideation`, `implementation`, `research`, and
|
|
22
|
+
`debug`: same phases model, same artifacts, same lifecycle verbs, same
|
|
23
|
+
authority record for each dispatched turn.
|
|
24
|
+
|
|
25
|
+
## Default protocol
|
|
26
|
+
|
|
27
|
+
```
|
|
28
|
+
change_summary → findings → author_response → followup_review → verdict
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
| Phase | Purpose | Typical artifact |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| `change_summary` | Recap the change under review; anchor the reviewer | inline `change_summary` |
|
|
34
|
+
| `findings` | Reviewer records issues against the change | `finding` (repeatable) |
|
|
35
|
+
| `author_response` | Author responds to each finding | `author_response` |
|
|
36
|
+
| `followup_review` | Reviewer re-inspects after fixes | `finding` or `verdict` |
|
|
37
|
+
| `verdict` | Convergence phase: `approve` or `request_changes` | `verdict` |
|
|
38
|
+
|
|
39
|
+
**Iteration.** `review` uses `max_iterations: 3` at the loop level rather than
|
|
40
|
+
a phase-local iteration block. The default `stop_condition` is
|
|
41
|
+
`any([reviewer_green, max_iterations n=3])`: an accepted verdict closes with
|
|
42
|
+
`completed`; three rounds without acceptance close with `blocked`.
|
|
43
|
+
|
|
44
|
+
## Entry points
|
|
45
|
+
|
|
46
|
+
- **Coordinator shortcut (recommended).**
|
|
47
|
+
`bclaw_coordinate(intent='review', open_loop=true, mode?='symmetric' | 'asymmetric')`
|
|
48
|
+
creates the candidate, opens a review loop with an `author` slot and a
|
|
49
|
+
`reviewer` slot, links the candidate as the `change_summary` artifact,
|
|
50
|
+
advances to `findings`, and dispatches the reviewer.
|
|
51
|
+
- **Dispatch shortcut.** `bclaw_dispatch(intent='review', openLoop=true, …)`
|
|
52
|
+
produces the same result on the dispatch code path.
|
|
53
|
+
- **Direct open.** `bclaw_loop(intent='open', kind='review', allow_orphan=true)`
|
|
54
|
+
followed by manual `turn`/`complete_turn`. Use only when neither shortcut
|
|
55
|
+
fits — `allow_orphan=true` is the explicit acknowledgement that you will
|
|
56
|
+
drive the loop yourself.
|
|
57
|
+
|
|
58
|
+
The default review mode is `asymmetric` (reviewer finds, author fixes).
|
|
59
|
+
`symmetric` mode collapses find + fix into one turn per side — see
|
|
60
|
+
[Symmetric review-and-fix](#symmetric-review-and-fix) below.
|
|
61
|
+
|
|
62
|
+
## Advance gates
|
|
63
|
+
|
|
64
|
+
`review` ships no `advance_gate` on any phase — advance is driven by the
|
|
65
|
+
`change_summary`, `finding`, `author_response`, and `verdict` artifacts and by
|
|
66
|
+
the shared `advance_when: 'all'` slot policy. The gate that matters lives on
|
|
67
|
+
the reducer: a `verdict` artifact converts to an `accepted…` body only when
|
|
68
|
+
the reviewer wrote `review_verdict: 'approve'`. `reviewer_green` in the stop
|
|
69
|
+
condition tests exactly that.
|
|
70
|
+
|
|
71
|
+
## Stop condition
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
{ kind: 'any', conditions: [{ kind: 'reviewer_green' }, { kind: 'max_iterations', n: 3 }] }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
- **`reviewer_green`** — closes the loop `completed` on the first `verdict`
|
|
78
|
+
artifact with an `accepted…` body.
|
|
79
|
+
- **`max_iterations n=3`** — closes the loop `blocked` after three rounds
|
|
80
|
+
without acceptance; a human takes over.
|
|
81
|
+
|
|
82
|
+
## Artifacts
|
|
83
|
+
|
|
84
|
+
| Type | Phase | Body |
|
|
85
|
+
|---|---|---|
|
|
86
|
+
| `change_summary` | `change_summary` | inline text ≤ 4 KB |
|
|
87
|
+
| `finding` | `findings` / `followup_review` | inline text ≤ 4 KB |
|
|
88
|
+
| `author_response` | `author_response` | inline text ≤ 4 KB |
|
|
89
|
+
| `verdict` | `verdict` | inline; `accepted…` for approve, otherwise `request_changes` |
|
|
90
|
+
| `changes_applied` | any phase (symmetric only) | inline turn summary; at most one per turn |
|
|
91
|
+
| `file_diff` | any phase | ref-based body (`{ref, byte_count, sha256}`) |
|
|
92
|
+
|
|
93
|
+
Artifacts either link a primitive (`ref`) or carry an inline `body` ≤ 4 KB;
|
|
94
|
+
larger content must move behind a `ref` — see the ref-based body shape in
|
|
95
|
+
[loop-engine.md](../concepts/loop-engine.md#artifact-body-shapes).
|
|
96
|
+
|
|
97
|
+
## How verdicts reach the loop
|
|
98
|
+
|
|
99
|
+
A turn-owned dispatched reviewer worker does **not** call `bclaw_loop`
|
|
100
|
+
directly. It writes its outcome to `LANE-RESULT.json` at the worktree root,
|
|
101
|
+
including `review_verdict: 'approve' | 'request_changes'` and
|
|
102
|
+
`review_summary`. `brainclaw harvest <assignment_id>` — both the report-only
|
|
103
|
+
path and `--integrate` — maps that lane onto its loop and calls
|
|
104
|
+
`reconcileTurn`, which:
|
|
105
|
+
|
|
106
|
+
1. Validates the LANE evidence against
|
|
107
|
+
[`evidenceMatchesAttempt`](../concepts/attempt-authority.md#functional-api)
|
|
108
|
+
(`turn_id`, `run_id`, current-generation nonce all match).
|
|
109
|
+
2. Runs the review reducer to record a `verdict` artifact on the reviewer
|
|
110
|
+
slot.
|
|
111
|
+
3. Calls `advance`, which auto-closes on `reviewer_green` when the verdict is
|
|
112
|
+
`approve`.
|
|
113
|
+
|
|
114
|
+
## Autonomous fix cycle
|
|
115
|
+
|
|
116
|
+
On a `request_changes` verdict, `harvest --integrate` may re-dispatch the
|
|
117
|
+
reviewer slot into the **same worktree** (symmetric mode) or the author slot
|
|
118
|
+
(asymmetric). The claim and the worktree stay alive, the round counter bumps,
|
|
119
|
+
and a fresh turn is prepared through the full
|
|
120
|
+
`reserve → commit → arm → consume` sequence — a new generation, so a stale
|
|
121
|
+
prior-generation LANE-RESULT can never terminate the new round. The cycle
|
|
122
|
+
repeats until `approve` (→ `reviewer_green` close) or the `max_iterations`
|
|
123
|
+
cap (→ `blocked`, handed to a human). The report-only harvest path never
|
|
124
|
+
cycles: it can neither re-dispatch nor retain the claim, so it defers
|
|
125
|
+
`request_changes` to `--integrate` and still closes on `approve`.
|
|
126
|
+
|
|
127
|
+
Set `BRAINCLAW_TURN_OWNED_LOOPS=off` to disable the common path, or `review`
|
|
128
|
+
to limit it to review. `BRAINCLAW_TURN_OWNED_REVIEW=0` (also
|
|
129
|
+
`false`/`off`/`no`) remains the backward-compatible kill switch.
|
|
130
|
+
|
|
131
|
+
## Symmetric review-and-fix
|
|
132
|
+
|
|
133
|
+
When both slots are coding agents with write access to the reviewed artifact
|
|
134
|
+
(the common case for spec, doc, and small refactor reviews),
|
|
135
|
+
`mode: 'symmetric'` collapses the two phases `findings` and `author_response`
|
|
136
|
+
into one behavior per turn: the reviewer reviews **and** applies whatever
|
|
137
|
+
fixes it can make directly, then hands back a `changes_applied` summary
|
|
138
|
+
alongside its remaining `finding` artifacts. The next slot picks up from that
|
|
139
|
+
committed state and does the same. Exit: a reviewer turn produces an
|
|
140
|
+
accepted `verdict` with no unapplied findings and no `changes_applied` in the
|
|
141
|
+
turn, or `max_iterations` fires.
|
|
142
|
+
|
|
143
|
+
The phase sequence is unchanged; `mode` is persisted on
|
|
144
|
+
`loop.protocol.review_mode` at `open` time so resume and turn handlers do not
|
|
145
|
+
depend on the original request envelope. A slot that lacks write authority
|
|
146
|
+
degrades gracefully to asymmetric behavior for that turn: findings/verdicts
|
|
147
|
+
are still allowed, `changes_applied` is omitted, and the loop continues.
|
|
148
|
+
|
|
149
|
+
## Routing and project resolution
|
|
150
|
+
|
|
151
|
+
`review` routes turns by `slot_id`, using the reviewer/author slot pointer;
|
|
152
|
+
`session_id` is observability-only. The shortcut path applies the
|
|
153
|
+
[project resolution gate](../concepts/loop-engine.md#project-resolution-gate)
|
|
154
|
+
before writing anything — a review loop cannot land in the wrong store.
|
|
155
|
+
|
|
156
|
+
## Recovery
|
|
157
|
+
|
|
158
|
+
- **Reviewer worker crashed before writing LANE-RESULT.** The launch grant
|
|
159
|
+
lease expires; `sweepExpiredLaunchGrants` revokes the grant
|
|
160
|
+
(`reserved_never_launched`). A subsequent dispatch arms a new generation
|
|
161
|
+
at a strictly greater epoch.
|
|
162
|
+
- **LANE-RESULT written, harvest not yet run.** Idempotent: any harvest
|
|
163
|
+
trigger — the wrapper completion signal, `brainclaw harvest`, session-end
|
|
164
|
+
— calls `reconcileTurn`, and its convergence body is idempotent under the
|
|
165
|
+
loop lock (a superseded turn no-ops; a terminal loop no-ops).
|
|
166
|
+
- **Completed lane + failed sentinel present.** `reconcileTurn` withholds
|
|
167
|
+
convergence (§13 R4), journals a `run_blocked` runtime event with
|
|
168
|
+
`status_reason: turn_evidence_contradiction`, and escalates to a human.
|
|
169
|
+
- **Iteration cap hit.** Loop closes to `blocked`; the coordinator claim
|
|
170
|
+
is released; the worktree becomes ordinary once the harvest pass runs.
|
|
171
|
+
|
|
172
|
+
Every one of these outcomes is a total function of the reservation record
|
|
173
|
+
plus the run status — never a decision on marker-file presence.
|
|
174
|
+
|
|
175
|
+
## When NOT to use
|
|
176
|
+
|
|
177
|
+
- **Ideation before a decision is made** — use [`ideation`](./ideation.md).
|
|
178
|
+
- **Adversarial pressure on a proposal that has no candidate yet** — use
|
|
179
|
+
[`ideation`](./ideation.md); a review loop with no `change_summary`
|
|
180
|
+
artifact is empty.
|
|
181
|
+
- **Running the failing repro of a bug** — use [`debug`](./debug.md).
|
|
182
|
+
- **Executing a bound plan** — use [`implementation`](./implementation.md).
|
|
183
|
+
- **Open-ended discovery** — use [`research`](./research.md).
|
|
184
|
+
|
|
185
|
+
## Reference implementation
|
|
186
|
+
|
|
187
|
+
| Component | File |
|
|
188
|
+
|---|---|
|
|
189
|
+
| Default protocol | [`src/core/loops/types.ts`](../../src/core/loops/types.ts) (`DEFAULT_PROTOCOLS.review`) |
|
|
190
|
+
| Coordinator dispatch | [`src/core/review-loop-turn-dispatch.ts`](../../src/core/review-loop-turn-dispatch.ts) |
|
|
191
|
+
| Common attempt + projections | [`src/core/loops/attempt-authority.ts`](../../src/core/loops/attempt-authority.ts), [`src/core/loops/turn-execution.ts`](../../src/core/loops/turn-execution.ts) |
|
|
192
|
+
| Close / reducer | [`src/core/loops/reconcile-turn.ts`](../../src/core/loops/reconcile-turn.ts), [`src/core/review-loop-close.ts`](../../src/core/review-loop-close.ts) |
|
|
193
|
+
| Result reducer | [`src/core/loops/result-reducers.ts`](../../src/core/loops/result-reducers.ts) |
|
|
194
|
+
| Tests | [`tests/unit/review-loop-close.test.ts`](../../tests/unit/review-loop-close.test.ts), [`tests/unit/loops-mcp-facade.test.ts`](../../tests/unit/loops-mcp-facade.test.ts) |
|
|
195
|
+
|
|
196
|
+
## Related
|
|
197
|
+
|
|
198
|
+
- [Loop Engine](../concepts/loop-engine.md)
|
|
199
|
+
- [Attempt authority](../concepts/attempt-authority.md)
|
|
200
|
+
- [Dispatch lifecycle](../concepts/dispatch-lifecycle.md)
|
|
@@ -408,7 +408,16 @@ will still succeed. A follow-up PR will strip the dead handler code.
|
|
|
408
408
|
changelog records the published MCP surface fingerprint. When a tool
|
|
409
409
|
name, tier, category, or input schema changes, the test fails until
|
|
410
410
|
this section is updated.
|
|
411
|
-
- MCP public surface fingerprint: `sha256:
|
|
411
|
+
- MCP public surface fingerprint: `sha256:81243f3d507c274e`
|
|
412
|
+
(updated 2026-08-23 for the common Loop Engine worker driver: `turn` exposes
|
|
413
|
+
real dispatch/model/candidate controls and `complete_turn` exposes the full
|
|
414
|
+
AttemptAuthority fence; bind remains engine-only with compatibility inputs.)
|
|
415
|
+
Previous: `sha256:47fa4e8a66fae55d`
|
|
416
|
+
(updated 2026-08-23 for AttemptAuthority v2: the public Loop Engine surface
|
|
417
|
+
exposes `open`, `verify`, `request_input`, and `provide_input`; Assignment and
|
|
418
|
+
Claim mutations carry the complete attempt fence and coordinator override is
|
|
419
|
+
explicit.)
|
|
420
|
+
Previous: `sha256:b8dbb80bae8f6e36`
|
|
412
421
|
(updated 2026-08-10 for pln#665: `bclaw_code_export` — additive Tier-B read tool for a required, bounded local Code Map subgraph. Its target, direction, depth, node/edge caps, confidence threshold, and optional Mermaid projection are explicit; JSON retains each relation's kind/source/confidence and never defaults to a whole-graph export.)
|
|
413
422
|
Previous: `sha256:9ed35ed6cc49ea9a`
|
|
414
423
|
(updated 2026-08-10 for pln#661: `bclaw_code_impact` — additive Tier-B read tool
|
|
@@ -420,10 +429,10 @@ will still succeed. A follow-up PR will strip the dead handler code.
|
|
|
420
429
|
source-ordered symbols of one indexed file from the existing shard; no reparse,
|
|
421
430
|
no mutation, bounded output. Purely additive.)
|
|
422
431
|
(updated 2026-07-25 for pln#632: `bclaw_loop` gains the `bind` intent — an
|
|
423
|
-
implementation loop
|
|
424
|
-
|
|
425
|
-
`max_assignments
|
|
426
|
-
|
|
432
|
+
implementation loop validates its linked sequence and advances bind→execute.
|
|
433
|
+
Historical launch-shaped properties `lanes`, `auto_execute`, `model`, and
|
|
434
|
+
`max_assignments` remain accepted but are ignored; worker launch now goes through
|
|
435
|
+
`turn(dispatch=true)` and AttemptAuthority. Additive — no tool removed/renamed.)
|
|
427
436
|
Previous: `sha256:f3d49b28d2d366bb`
|
|
428
437
|
(updated 2026-07-24 for pln#630 PR2b-a: `LoopSlotSchema` gains an optional
|
|
429
438
|
`current_turn_id`, which flows through the zod-derived `LoopSlotInput` into
|
|
@@ -82,42 +82,41 @@ The Loop engine (pln#394) was designed as a generic control plane —
|
|
|
82
82
|
one engine, many protocols. Review & Fix Loop (pln#395) was the first
|
|
83
83
|
shipped protocol. The strategic reflection clarifies that:
|
|
84
84
|
|
|
85
|
-
- We do **not** need to code eight protocols.
|
|
86
|
-
|
|
87
|
-
|
|
85
|
+
- We do **not** need to code eight protocols. The five shipped defaults
|
|
86
|
+
cover the high-leverage kinds; future work should polish their entry
|
|
87
|
+
points and document further patterns as composition variants.
|
|
88
88
|
- The engine already supports everything required: `open`, `turn`,
|
|
89
89
|
`advance`, `complete_turn`, `add_artifact`, `pause`, `resume`,
|
|
90
90
|
`close`, with per-phase `advance_when`, composite `StopCondition`,
|
|
91
91
|
idempotency, and CAS.
|
|
92
92
|
|
|
93
|
-
###
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
Sequences — makes plan creation less naive.
|
|
93
|
+
### Supported protocol families
|
|
94
|
+
|
|
95
|
+
The runtime ships **five default protocols**, not just a review loop:
|
|
96
|
+
|
|
97
|
+
| Protocol | What it structures | Public entry point |
|
|
98
|
+
|---|---|---|
|
|
99
|
+
| `review` | change summary → findings → response → verdict | `bclaw_coordinate(intent="review", open_loop=true)` or `bclaw_dispatch(intent="review", openLoop=true)` |
|
|
100
|
+
| `ideation` | proposal → adversarial critique ↔ revision → synthesis | `bclaw_coordinate(intent="ideate")`, with the optional `bootstrap` preset |
|
|
101
|
+
| `implementation` | bind a plan/sequence → execute ↔ verify → handoff | direct `bclaw_loop(intent="open", kind="implementation", allow_orphan=true)`, then `bind` |
|
|
102
|
+
| `research` | investigate ↔ synthesize → conclude | direct `bclaw_loop(intent="open", kind="research", allow_orphan=true)` |
|
|
103
|
+
| `debug` | reproduce → hypothesize ↔ isolate ↔ fix → handoff | direct `bclaw_loop(intent="open", kind="debug", allow_orphan=true)` |
|
|
104
|
+
|
|
105
|
+
The direct entry point requires `allow_orphan=true` because the caller is
|
|
106
|
+
responsible for driving or dispatching the loop. It does not mean the loop is
|
|
107
|
+
unsupported: `bclaw_loop` publicly exposes `open`, `turn`, `complete_turn`,
|
|
108
|
+
`advance`, `add_artifact`, `pause`, `resume`, `close`, and the
|
|
109
|
+
implementation-specific `bind` and `verify` actions.
|
|
110
|
+
|
|
111
|
+
**Clarification is cross-cutting.** Any protocol may use `request_input` and
|
|
112
|
+
`provide_input` to pause for a bounded, evidence-backed operator decision.
|
|
113
|
+
Treating it as a shared primitive avoids inventing a review-shaped loop for a
|
|
114
|
+
simple missing decision.
|
|
116
115
|
|
|
117
116
|
### Variants, not new protocols
|
|
118
117
|
|
|
119
|
-
The following items
|
|
120
|
-
|
|
118
|
+
The following items are compositions of the shipped protocols and do not
|
|
119
|
+
require separate engine work:
|
|
121
120
|
|
|
122
121
|
- **Reflection / Self-Critique** = ideation loop with `mode:
|
|
123
122
|
'symmetric'` and all slots assigned to the same agent. The engine
|
|
@@ -125,12 +124,12 @@ above and do not require separate engine work:
|
|
|
125
124
|
- **Validation & Approval Multi-Audience** = review loop with N
|
|
126
125
|
reviewer slots (one per audience) plus a consolidator slot. Purely
|
|
127
126
|
a slot-configuration pattern.
|
|
128
|
-
- **Optimization / Refactoring** = implementation loop framed around
|
|
129
|
-
|
|
127
|
+
- **Optimization / Refactoring** = implementation loop framed around a
|
|
128
|
+
before/after artifact pair. A convention, not a new protocol.
|
|
130
129
|
|
|
131
130
|
### What "wiring" means concretely (per protocol)
|
|
132
131
|
|
|
133
|
-
For
|
|
132
|
+
For a new protocol or a material protocol extension:
|
|
134
133
|
|
|
135
134
|
- Polished `DEFAULT_PROTOCOLS` entry (phases, stop_condition, default
|
|
136
135
|
roles) in `src/core/loops/types.ts`.
|
|
@@ -165,8 +164,9 @@ sections toward visible-to-human items.
|
|
|
165
164
|
|
|
166
165
|
## 5. Practical implications
|
|
167
166
|
|
|
168
|
-
- Next implementation move: reframer phase (pln#493) on top of the
|
|
169
|
-
shipped
|
|
167
|
+
- Next implementation move: a reframer phase (pln#493) on top of the
|
|
168
|
+
shipped ideation loop, then improved ergonomics and examples for the
|
|
169
|
+
already-shipped debug and research protocols.
|
|
170
170
|
- Parallel track: the cockpit needs dedicated planning once the engine
|
|
171
171
|
emits enough signals (event streaming, reputation exposure, audit
|
|
172
172
|
narrative generation, cost attribution).
|