brainclaw 1.26.2 → 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.
Files changed (86) hide show
  1. package/README.md +13 -0
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli/register-coordination.js +65 -1
  4. package/dist/commands/attempt-authority.js +80 -0
  5. package/dist/commands/harvest.js +140 -61
  6. package/dist/commands/loop.js +34 -0
  7. package/dist/commands/loops-handlers.js +87 -14
  8. package/dist/commands/mcp-catalog.js +42 -18
  9. package/dist/commands/mcp-schemas.generated.js +44 -0
  10. package/dist/commands/mcp-write-claims.js +128 -1
  11. package/dist/commands/mcp-write-coordination.js +146 -76
  12. package/dist/core/agent-capability.js +1 -1
  13. package/dist/core/agentrun-reconciler.js +148 -22
  14. package/dist/core/agentruns.js +254 -29
  15. package/dist/core/assignment-request-schema.js +7 -0
  16. package/dist/core/assignment-sweeper.js +5 -3
  17. package/dist/core/assignments.js +131 -33
  18. package/dist/core/claim-request-schema.js +7 -0
  19. package/dist/core/claims.js +53 -2
  20. package/dist/core/dispatch-status.js +16 -6
  21. package/dist/core/dispatcher.js +51 -51
  22. package/dist/core/entity-operations.js +20 -0
  23. package/dist/core/events.js +4 -0
  24. package/dist/core/execution-adapters.js +160 -14
  25. package/dist/core/execution-contract.js +345 -0
  26. package/dist/core/execution.js +130 -16
  27. package/dist/core/harness-adapters/base.js +150 -0
  28. package/dist/core/harness-adapters/claude.js +39 -0
  29. package/dist/core/harness-adapters/codex.js +57 -0
  30. package/dist/core/harness-adapters/harvest.js +109 -0
  31. package/dist/core/harness-adapters/index.js +8 -0
  32. package/dist/core/harness-adapters/prompt-only.js +13 -0
  33. package/dist/core/harness-adapters/registry.js +48 -0
  34. package/dist/core/harness-adapters/result.js +33 -0
  35. package/dist/core/harness-adapters/types.js +2 -0
  36. package/dist/core/ideation-loop-close.js +25 -2
  37. package/dist/core/instruction-templates.js +3 -2
  38. package/dist/core/loop-turn-dispatch.js +207 -0
  39. package/dist/core/loops/artifact-contract.js +11 -0
  40. package/dist/core/loops/attempt-authority.js +476 -0
  41. package/dist/core/loops/attempt-generations.js +509 -0
  42. package/dist/core/loops/attempt-reservation.js +197 -35
  43. package/dist/core/loops/attempt-rollout.js +404 -0
  44. package/dist/core/loops/attempt-takeover.js +155 -0
  45. package/dist/core/loops/bootstrap-acquire.js +7 -3
  46. package/dist/core/loops/evidence.js +187 -0
  47. package/dist/core/loops/facade-schema.js +41 -10
  48. package/dist/core/loops/gate-policy.js +485 -0
  49. package/dist/core/loops/impl-bind.js +37 -79
  50. package/dist/core/loops/index.js +9 -0
  51. package/dist/core/loops/iteration-engine.js +31 -19
  52. package/dist/core/loops/kind-policies.js +90 -0
  53. package/dist/core/loops/lock.js +71 -13
  54. package/dist/core/loops/reconcile-turn.js +235 -18
  55. package/dist/core/loops/result-reducers.js +99 -10
  56. package/dist/core/loops/store.js +30 -3
  57. package/dist/core/loops/turn-execution.js +480 -0
  58. package/dist/core/loops/types.js +113 -2
  59. package/dist/core/loops/verbs.js +332 -99
  60. package/dist/core/loops/verify-command.js +31 -8
  61. package/dist/core/loops/workspace-digest.js +54 -0
  62. package/dist/core/review-loop-close.js +25 -3
  63. package/dist/core/review-loop-turn-dispatch.js +210 -161
  64. package/dist/core/runtime-signals.js +62 -25
  65. package/dist/core/schema.js +35 -0
  66. package/dist/core/spawn-check.js +3 -2
  67. package/dist/core/upgrades/backup.js +27 -4
  68. package/dist/facts.js +7 -6
  69. package/dist/facts.json +6 -5
  70. package/docs/cli.md +49 -1
  71. package/docs/concepts/attempt-authority.md +407 -0
  72. package/docs/concepts/evidence-attestations.md +135 -0
  73. package/docs/concepts/execution-contract.md +166 -0
  74. package/docs/concepts/harness-adapters.md +166 -0
  75. package/docs/concepts/ideation-loop.md +5 -4
  76. package/docs/concepts/loop-engine.md +302 -113
  77. package/docs/index.md +4 -1
  78. package/docs/integrations/codex.md +3 -3
  79. package/docs/integrations/mcp.md +59 -5
  80. package/docs/loops/debug.md +144 -0
  81. package/docs/loops/ideation.md +158 -0
  82. package/docs/loops/implementation.md +154 -0
  83. package/docs/loops/research.md +136 -0
  84. package/docs/loops/review.md +200 -0
  85. package/docs/mcp-schema-changelog.md +14 -5
  86. package/package.json +1 -1
package/docs/index.md CHANGED
@@ -28,8 +28,11 @@ Use this page as the entry point into the packaged Markdown documentation.
28
28
  - [concepts/workspace-bootstrapping.md](concepts/workspace-bootstrapping.md)
29
29
  - [concepts/troubleshooting.md](concepts/troubleshooting.md) — runbook for degraded coordination state
30
30
  - [concepts/memory-staleness.md](concepts/memory-staleness.md)
31
- - [concepts/loop-engine.md](concepts/loop-engine.md)
31
+ - [concepts/loop-engine.md](concepts/loop-engine.md) — shared runtime for the five loop protocols
32
+ - [concepts/attempt-authority.md](concepts/attempt-authority.md) — identity, dispatch decisions and spawn authority for every turn
33
+ - [concepts/evidence-attestations.md](concepts/evidence-attestations.md) — server-sealed loop evidence, independent attestations, and protocol gates
32
34
  - [concepts/ideation-loop.md](concepts/ideation-loop.md) — memory-confrontation ideation loop (v1.5.0+)
35
+ - Loop protocol guides — [review](loops/review.md), [ideation](loops/ideation.md), [implementation](loops/implementation.md), [research](loops/research.md), [debug](loops/debug.md)
33
36
  - [concepts/mcp-governance.md](concepts/mcp-governance.md)
34
37
  - [concepts/federation-v2-rfc.md](concepts/federation-v2-rfc.md) — contrat joint core + Cloud pour la fédération chiffrée v2
35
38
 
@@ -47,9 +47,9 @@ The `--sandbox workspace-write` setting is required, **not `read-only`** — the
47
47
 
48
48
  ### Prompt delivery: stdin_pipe (preferred)
49
49
 
50
- Since pln#475 (1.0.10+), Codex spawned as a child process receives its prompt via **stdin** rather than as an inline argument. The reason is Windows-specific: `codex.cmd` resolves through `cmd.exe`, where embedded backticks, `#`, or multi-line content can be mis-parsed and raise `unexpected argument`. Reading from stdin avoids that.
50
+ Since pln#475 (1.0.10+), Codex spawned as a child process receives its prompt via **stdin** rather than as an inline argument. The reason is Windows-specific: `codex.cmd` resolves through `cmd.exe`, where embedded backticks, `#`, or multi-line content can be mis-parsed and raise `unexpected argument`. Keeping the prompt out of argv avoids that.
51
51
 
52
- When you (or the dispatcher) calls Codex with no positional `[PROMPT]`, Codex reads stdin until EOF that's where brainclaw pipes the brief. `inline_arg` remains a fallback for short prompts on POSIX.
52
+ When you (or the dispatcher) calls Codex with no positional `[PROMPT]`, Codex reads stdin until EOF. A direct spawn pipes the brief normally. On Windows, an ack-wrapped spawn writes the brief to a private per-run file, redirects that file to Codex stdin, and deletes it after the terminal sentinel. This is still `stdin_pipe` at the harness contract: the file is a transport detail that guarantees EOF through `cmd.exe` and keeps prompt content out of shell syntax. `inline_arg` remains a fallback for short prompts on POSIX.
53
53
 
54
54
  ### Brief-ack handshake
55
55
 
@@ -89,6 +89,6 @@ The file shape is `{ "hooks": { "<Event>": [ { "matcher": "", "hooks": [ { "type
89
89
  ## Caveats
90
90
 
91
91
  - **Sandbox blocks `git commit`, not MCP** (dec#133): a sandboxed Codex run reaches brainclaw MCP (the server is a separate out-of-sandbox process; `approval_policy=never` auto-approves). What the sandbox *does* block is direct writes to paths outside the worktree root — notably `.git`, so the worker cannot `git commit`. Leave fixes uncommitted; the coordinator integrates + commits the worktree diff at harvest. A LANE-RESULT.json / filesystem-direct candidate write remains a valid fallback for reporting.
92
- - **Windows quoting**: long prompts containing backticks or `#` fail when passed as inline args through `cmd.exe`. The default stdin_pipe path avoids this.
92
+ - **Windows prompt transport**: long prompts containing backticks or `#` fail when passed as inline args through `cmd.exe`, while a parent stdin pipe can fail to propagate EOF to a native grandchild. The default ack-wrapped path uses a per-run file redirected to stdin and removes it after the terminal sentinel, avoiding both failure modes.
93
93
  - **Sandbox vs review parity**: review runs use the same `workspace-write` sandbox as execution runs (older templates forced `read-only` on reviews; that path blocked PowerShell exec on Windows).
94
94
  - **No always-allow**: each MCP tool call still respects per-call approval policy unless explicitly set with `-c approval_policy="never"`.
@@ -68,7 +68,7 @@ Each tool also has an `annotations.category` field: `session`, `context`, `memor
68
68
  | `bclaw_context` | context | Unified context read for memory, execution, board, board summary, and deltas |
69
69
  | `bclaw_coordinate` | coordination | Assign, consult, review, ideate, reroute, or summarize across agents |
70
70
  | `bclaw_dispatch` | coordination | Analyze, execute, or review dispatch work through one intent-based entry point |
71
- | `bclaw_loop` | loops | Drive multi-turn review, ideation, implementation, research, or debug loops |
71
+ | `bclaw_loop` | loops | Drive review, ideation, implementation, research, or debug loops, including fenced physical-run takeover |
72
72
  | `bclaw_setup` | session | Agent-driven onboarding wizard |
73
73
 
74
74
  ### Standard tools
@@ -86,7 +86,7 @@ Each tool also has an `annotations.category` field: `session`, `context`, `memor
86
86
  | `bclaw_write_note` | memory | Record a runtime note |
87
87
  | `bclaw_quick_capture` | memory | Capture text and classify it locally as a decision, trap, or runtime note |
88
88
  | `bclaw_claim` | coordination | Claim a work scope (advisory lock, auto-worktree) |
89
- | `bclaw_release_claim` | coordination | Release a claim, optionally updating linked plan status |
89
+ | `bclaw_release_claim` | coordination | Release a legacy/unsettled-independent claim, optionally updating linked plan status; v2 loop claims are released by settlement projections or audited coordinator override |
90
90
  | `bclaw_session_start` | session | Start a session explicitly (granular workflow) |
91
91
  | `bclaw_session_end` | session | End session, optionally auto-reflect notes or handoffs |
92
92
  | `bclaw_add_step` | coordination | Add a sub-step to a plan item |
@@ -98,7 +98,7 @@ Each tool also has an `annotations.category` field: `session`, `context`, `memor
98
98
  | `bclaw_update_sequence` | coordination | Update a sequence's status, metadata, or items |
99
99
  | `bclaw_delete_sequence` | coordination | Delete a sequence by ID |
100
100
  | `bclaw_correct_handoff` | coordination | Write an immutable correction handoff that supersedes an earlier one |
101
- | `bclaw_assignment_update` | coordination | Report assignment lifecycle status |
101
+ | `bclaw_assignment_update` | coordination | Report assignment lifecycle status; v2 logical Assignments require the full generation fence and accept only accepted/started/progress before settlement |
102
102
  | `bclaw_assignment_action` | coordination | Resolve or reject a pending ActionRequired item |
103
103
  | `bclaw_harvest_candidates` | coordination | Harvest sandboxed worktree candidate files into the main project store |
104
104
  | `bclaw_find` | memory | List canonical entities with filters |
@@ -399,7 +399,8 @@ bclaw_context({ kind: 'board_summary' })
399
399
  // Review dispatch with structured loop
400
400
  bclaw_dispatch({ intent: 'review', openLoop: true, reviewMode: 'symmetric' })
401
401
 
402
- // Open a memory-confrontation ideation loop (single-agent: champion drives manually)
402
+ // Open a single-agent ideation loop. Proposal is manual; critique, revision and
403
+ // synthesis are worker phases available through trusted turn(dispatch:true).
403
404
  bclaw_coordinate({ intent: 'ideate', task: 'Should we extract the dispatcher into a separate package?' })
404
405
 
405
406
  // Multi-agent ideation: critic gets a context-filtered, BM25-ranked brief auto-dispatched
@@ -410,7 +411,8 @@ bclaw_coordinate({
410
411
  })
411
412
 
412
413
  // Open a direct implementation loop. The caller owns subsequent bind/turn
413
- // actions, which is why allow_orphan is explicit.
414
+ // actions, which is why allow_orphan is explicit. Bind is engine-only; after
415
+ // it advances to execute, turn(dispatch:true) is the worker launch path.
414
416
  bclaw_loop({
415
417
  intent: 'open',
416
418
  kind: 'implementation',
@@ -420,6 +422,52 @@ bclaw_loop({
420
422
  verify: { command: ['npm', 'test'] },
421
423
  })
422
424
 
425
+ bclaw_loop({ intent: 'bind', loop_id: 'lop_abc' })
426
+ bclaw_loop({
427
+ intent: 'turn', loop_id: 'lop_abc', slot_id: 'lsl_worker',
428
+ dispatch: true, target_agents: ['codex', 'claude-code'],
429
+ })
430
+
431
+ // Direct research/debug loops use the same facade. A plain turn records state;
432
+ // trusted dispatch:true actually prepares, fences and launches a worker.
433
+ bclaw_loop({
434
+ intent: 'open',
435
+ kind: 'research',
436
+ title: 'Determine the safe migration boundary',
437
+ goal: 'Produce a sourced synthesis',
438
+ allow_orphan: true,
439
+ })
440
+ bclaw_loop({
441
+ intent: 'turn',
442
+ loop_id: 'lop_research',
443
+ slot_id: 'lsl_investigator',
444
+ dispatch: true,
445
+ target_agents: ['codex', 'claude-code'], // only used when the slot is unbound
446
+ })
447
+
448
+ bclaw_loop({
449
+ intent: 'open',
450
+ kind: 'debug',
451
+ title: 'Reproduce and fix the Windows dispatch failure',
452
+ allow_orphan: true,
453
+ })
454
+ bclaw_loop({ intent: 'turn', loop_id: 'lop_debug', slot_id: 'lsl_reproducer', dispatch: true })
455
+
456
+ // Fence a stale physical generation without changing the logical turn or Assignment.
457
+ // This arms the successor; dispatch the same turn afterwards to contend on launch.
458
+ bclaw_loop({
459
+ intent: 'takeover',
460
+ loop_id: 'lop_abc',
461
+ slot_id: 'lsl_abc',
462
+ turn_id: 'tat_abc',
463
+ expected_epoch: 0,
464
+ cause: 'heartbeat and process evidence are stale',
465
+ liveness_evidence: 'no heartbeat for 30m; wrapper exited',
466
+ external_effect_policy: 'idempotent',
467
+ next_workspace_path: 'C:\\worktrees\\brainclaw-retry-1',
468
+ agent: 'coordinator',
469
+ })
470
+
423
471
  // Correct a handoff instead of mutating it
424
472
  bclaw_correct_handoff({ originalId: 'hnd_xyz', reason: 'wrong contract', text: '...' })
425
473
  ```
@@ -430,6 +478,12 @@ advance gate, brief assembly, single vs multi-agent UX), see
430
478
  engine supports the five built-in `review`, `ideation`, `implementation`,
431
479
  `research`, and `debug` workflows, plus cross-cutting `request_input` /
432
480
  `provide_input`; see [docs/concepts/loop-engine.md](../concepts/loop-engine.md).
481
+ Takeover is likewise cross-cutting, not review-specific. Once a turn has an
482
+ AttemptAuthority v2 generation chain, terminal evidence must echo the complete
483
+ `assignment_id`, `turn_id`, `attempt_epoch`, `run_id`, `nonce`,
484
+ `execution_contract_hash`, and `workspace_digest` fence; a stale generation is
485
+ retained for audit but cannot converge loop state. See
486
+ [docs/concepts/attempt-authority.md](../concepts/attempt-authority.md).
433
487
 
434
488
  #### Deprecation status
435
489
 
@@ -0,0 +1,144 @@
1
+ # Debug loop
2
+
3
+ > Loop kind: `debug`. 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 use `repro`, `hypothesis`, `isolation_report`, and
9
+ `verify_report` respectively. The mutating `fix` phase remains claimed until
10
+ `harvest --integrate`; the earlier read-only phases may converge on report.
11
+
12
+ ## Purpose
13
+
14
+ A `debug` loop drives a broken system back to green. The invariant it
15
+ enforces: "bug fixed" ⟺ "the reproducing command is now green" ⟺ "a passing
16
+ `verify_report`". It mirrors [`implementation`](./implementation.md)'s
17
+ `execute ↔ verify` pattern but starts one step earlier: `reproduce` must
18
+ land a concrete repro before hypothesise-isolate-fix begins.
19
+
20
+ ## Default protocol
21
+
22
+ ```
23
+ reproduce → hypothesize ↔ isolate ↔ fix → handoff
24
+ └────── iterate (≤3) ─────┘
25
+ ```
26
+
27
+ | Phase | Purpose | Artifact | Context filter |
28
+ |---|---|---|---|
29
+ | `reproduce` | Land a reliable repro of the bug | `repro` | `traps`, `runtime_notes`, `handoffs`, `plans` |
30
+ | `hypothesize` | Propose a cause | `hypothesis` | `decisions`, `constraints`, `traps`, `runtime_notes` |
31
+ | `isolate` | Narrow to a single change | `isolation_report` | `decisions`, `constraints`, `traps`, `runtime_notes` |
32
+ | `fix` | Apply the fix; re-run the repro | edits + `verify_report` | `traps`, `runtime_notes`, `constraints` |
33
+ | `handoff` | Ship the diff to review | `handoff` | `handoffs`, `plans` |
34
+
35
+ **Iteration.** `hypothesize ↔ isolate ↔ fix` cycles up to
36
+ `max_iterations: 3`. `exit_when: 'command_green'` — the same predicate
37
+ `implementation` uses — exits early on a passing `verify_report` in the
38
+ current iteration. `advance_when: 'all'` is the default.
39
+
40
+ ## Entry points
41
+
42
+ - **Direct open (typical).**
43
+ `bclaw_loop(intent='open', kind='debug', linked={handoff_ids:[…]}, allow_orphan=true)`
44
+ followed by a `turn` for the `reproduce` phase. There is no coordinator
45
+ shortcut for `debug` today. Plain `turn` is state-only; trusted
46
+ `turn(dispatch=true)` launches a worker phase through the common
47
+ AttemptAuthority path.
48
+ - **Referred from `implementation`.** An `implementation` loop that
49
+ closes `blocked` at the cycle cap with a red `verify_report` is a
50
+ natural feeder — open a `debug` loop that links the red report as its
51
+ seed `repro` artifact.
52
+
53
+ ## Advance gates
54
+
55
+ Two phases carry gates:
56
+
57
+ **`reproduce`** — cannot start hypothesising without a concrete repro:
58
+
59
+ ```ts
60
+ { kind: 'artifact_produced', phase: 'reproduce', type: 'repro' }
61
+ ```
62
+
63
+ **`fix`** — cannot leave `fix` without a `verify_report` this iteration
64
+ (same shape as `implementation`'s verify gate):
65
+
66
+ ```ts
67
+ { kind: 'min_artifacts_by_type', type: 'verify_report', n: 1, scope: 'phase' }
68
+ ```
69
+
70
+ ## Stop condition
71
+
72
+ ```ts
73
+ { kind: 'any', conditions: [
74
+ { kind: 'artifact_produced', phase: 'handoff', type: 'handoff' },
75
+ { kind: 'max_iterations', n: 3 },
76
+ ] }
77
+ ```
78
+
79
+ - **Handoff produced** → close `completed`. The handoff carries the diff
80
+ for a downstream `review` loop.
81
+ - **Cycle cap** → close `blocked`; the last red `verify_report` stays on
82
+ the loop as evidence. A human picks up.
83
+
84
+ ## Artifacts
85
+
86
+ | Type | Phase | Body |
87
+ |---|---|---|
88
+ | `repro` | `reproduce` | inline ≤ 4 KB: the command / test / URL that fails, and the exit signature |
89
+ | `hypothesis` | `hypothesize` | inline ≤ 4 KB |
90
+ | `isolation_report` | `isolate` | inline ≤ 4 KB |
91
+ | `verify_report` | `fix` | inline JSON: `{ command, exit_code, passed, duration_ms?, stdout_tail?, stderr_tail? }` |
92
+ | `file_diff` | any phase | ref-based body (`{ref, byte_count, sha256}`) |
93
+ | `handoff` | `handoff` | `ref` to a `handoff` primitive |
94
+
95
+ ## Routing
96
+
97
+ `debug` is claim-routed: `slot.claim_id` points at the scope claim the
98
+ fixer slot holds. The scope of the claim should cover the code under
99
+ investigation so the isolation and fix turns can edit freely.
100
+ `session_id` is observability-only.
101
+
102
+ ## Recovery
103
+
104
+ - **Fixer worker crashed mid-cycle.** Launch grant lease expires;
105
+ `sweepExpiredLaunchGrants` revokes it; re-dispatch arms a new
106
+ generation at a strictly greater epoch. A prior-iteration
107
+ `verify_report` cannot satisfy the current iteration's gate.
108
+ - **Command-green mid-cycle.** `exit_when: 'command_green'`
109
+ short-circuits the cycle; the driver advances to `handoff` on the next
110
+ `advance`.
111
+ - **Reproduce blocked.** The `phase_advance_blocked` system event records
112
+ the missing `repro`. Add a repro artifact, or narrow the loop scope.
113
+ - **Red `verify_report` at cap.** Loop closes `blocked`; the accumulated
114
+ hypotheses, isolation reports, and red verify reports stay on the loop
115
+ so the next human or agent has the trail.
116
+
117
+ ## When NOT to use
118
+
119
+ - **Building something new that doesn't reproduce anything.** Use
120
+ [`implementation`](./implementation.md).
121
+ - **Investigating an open-ended "why?" with no failing command.** Use
122
+ [`research`](./research.md).
123
+ - **Choosing between two architectural fixes.** Use
124
+ [`ideation`](./ideation.md) to pressure the choice against project
125
+ memory first.
126
+ - **Validating a landed fix.** Use [`review`](./review.md); the
127
+ `handoff` a debug loop emits is exactly what a review loop consumes.
128
+
129
+ ## Reference implementation
130
+
131
+ | Component | File |
132
+ |---|---|
133
+ | Default protocol | [`src/core/loops/types.ts`](../../src/core/loops/types.ts) (`DEFAULT_PROTOCOLS.debug`) |
134
+ | Iteration FSM (`command_green`) | [`src/core/loops/iteration-engine.ts`](../../src/core/loops/iteration-engine.ts) |
135
+ | Gate evaluator | [`src/core/loops/verbs.ts`](../../src/core/loops/verbs.ts) (`evaluatePhaseAdvanceGate`) |
136
+ | 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) |
137
+ | Result reducer | [`src/core/loops/result-reducers.ts`](../../src/core/loops/result-reducers.ts) |
138
+ | 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), [`tests/unit/loops-impl-protocol.test.ts`](../../tests/unit/loops-impl-protocol.test.ts) |
139
+
140
+ ## Related
141
+
142
+ - [Loop Engine](../concepts/loop-engine.md)
143
+ - [Attempt authority](../concepts/attempt-authority.md)
144
+ - [dispatch-lifecycle.md](../concepts/dispatch-lifecycle.md)
@@ -0,0 +1,158 @@
1
+ # Ideation loop
2
+
3
+ > Loop kind: `ideation`. 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 automated critic returns `artifact_type: "critique"` with a non-empty
9
+ `body`. A narrative `summary` alone never creates a critique or opens the gate.
10
+
11
+ ## Purpose
12
+
13
+ An `ideation` loop stress-tests a proposal **before** it crystallises into a
14
+ plan. Where [`review`](./review.md) validates a finished artifact and asks
15
+ "is this good?", `ideation` takes a fresh proposal and asks "what does our
16
+ accumulated project experience say will go wrong with this?"
17
+
18
+ The adversarial substrate is the project's own memory — traps, feedback
19
+ memos, runtime notes. Even a single-agent run produces useful pressure
20
+ because the phase context filter forces the critic to confront adversarial
21
+ memory rather than the positive context that seeded the proposal. See
22
+ [ideation-loop.md](../concepts/ideation-loop.md) for the full RFC-level
23
+ design; this page is the operator-facing summary.
24
+
25
+ ## Default protocol
26
+
27
+ ```
28
+ proposal → critique ↔ revision → synthesis
29
+ └─── iterate (≤3) ────┘
30
+ ```
31
+
32
+ | Phase | Purpose | Artifact | Context filter |
33
+ |---|---|---|---|
34
+ | `proposal` | Seed: the original idea | `proposal` (text ≤ 4 KB) | `decisions`, `constraints`, `plans`, `project_vision` |
35
+ | `critique` | Adversarial review against project memory | `critique` (repeatable) | `traps`, `feedback`, `runtime_notes`, `critique_history` |
36
+ | `revision` | Champion responds to the critique batch | `revision` | `*` |
37
+ | `synthesis` | Fold the cycle's outputs into a plan draft | `plan_draft` | `*` |
38
+
39
+ **Iteration.** `critique ↔ revision` iterates up to
40
+ `max_iterations: 3`; `exit_when: 'no_new_critique_artifacts'` stops the cycle
41
+ when a full round adds no new critique. `critic_signal` is available for
42
+ explicit early exit.
43
+
44
+ ## Entry points
45
+
46
+ - **Coordinator shortcut (recommended).**
47
+ `bclaw_coordinate(intent='ideate', task=…, [targetAgents=[…]])` opens the
48
+ loop with a `champion` slot (caller) and one `critic` slot per target
49
+ agent, stores `task` as the `proposal` artifact, advances to `critique`
50
+ in multi-agent mode, and dispatches the first critic with a brief
51
+ assembled by [`buildIdeationBrief`](../../src/core/loops/brief-assembly.ts).
52
+ - **Single-agent mode** — omit `targetAgents`. The champion drives each
53
+ turn via `bclaw_loop(intent='turn'|'advance')`. A plain `turn` only records
54
+ the assignment; on a worker phase, a trusted caller can set
55
+ `dispatch=true` to launch through AttemptAuthority. Useful when you want the
56
+ loop's structure (memory filter, gate, iteration accounting) without the
57
+ coordinator shortcut.
58
+ - **Direct open.** `bclaw_loop(intent='open', kind='ideation', allow_orphan=true)`.
59
+
60
+ ## Advance gates
61
+
62
+ The `critique` phase carries a default `advance_gate`:
63
+
64
+ ```ts
65
+ { kind: 'min_artifacts_by_type', type: 'critique', n: 3, scope: 'phase' }
66
+ ```
67
+
68
+ Advance to `revision` is refused until at least 3 `critique` artifacts have
69
+ been produced **in the current iteration window**. A previous round's
70
+ critiques do not satisfy the gate for a new round. On gate failure, the
71
+ driver emits a `phase_advance_blocked` system event with a structured
72
+ `gate_reason` and throws an actionable error.
73
+
74
+ ## Stop condition
75
+
76
+ ```ts
77
+ { kind: 'artifact_produced', phase: 'synthesis', type: 'plan_draft' }
78
+ ```
79
+
80
+ The loop closes `completed` on the first `plan_draft` artifact in
81
+ `synthesis`. Override via
82
+ `bclaw_loop(intent='open', stop_condition: …)` — e.g. a
83
+ `min_artifacts_by_type { type: 'critique', n: 5, scope: 'loop' }` stops after
84
+ five critiques have accumulated loop-wide.
85
+
86
+ ## Artifacts
87
+
88
+ | Type | Phase | Body |
89
+ |---|---|---|
90
+ | `proposal` | `proposal` | inline text ≤ 4 KB |
91
+ | `critique` | `critique` | inline ≤ 4 KB; must cite memory ids used |
92
+ | `revision` | `revision` | inline ≤ 4 KB |
93
+ | `plan_draft` | `synthesis` | inline ≤ 4 KB; MUST carry `addresses_critique: [artifact_id, …]` |
94
+ | `critic_signal` | `critique` | inline ≤ 4 KB; opts an explicit early cycle exit |
95
+
96
+ `plan_draft` field-presence is enforced at the zod level on
97
+ `LoopArtifactSchema` — a synthesis that omits `addresses_critique` is
98
+ rejected at write time.
99
+
100
+ ## Brief assembly
101
+
102
+ Each critic turn ships a size-capped brief (48 KB) with a BM25-ranked
103
+ memory bundle scoped to the phase's `context_filter`. When the bundle
104
+ overflows, the assembler appends a truncation tail and surfaces `truncated`,
105
+ `includedItems`, and `droppedItems` per-slot. This mitigates
106
+ [trp#179](../../src/core/loops/brief-assembly.ts) — oversized bundles push
107
+ agents onto CLI tools instead of MCP semantics.
108
+
109
+ ## Routing
110
+
111
+ `ideation` routes turns by `slot_id`; the coordinator shortcut queues a
112
+ message per critic with the brief as body and
113
+ `{intent: 'ideate', loop_id, slot_id, phase, iteration, proposal_artifact_id}`
114
+ as payload. Dispatch failures per slot surface as `partial`; the loop stays
115
+ at the proposal phase and callers can retry manually.
116
+
117
+ ## Recovery
118
+
119
+ - **Critic worker crashed mid-turn.** Launch grant lease expires;
120
+ `sweepExpiredLaunchGrants` revokes it; the coordinator can re-dispatch
121
+ with a fresh generation.
122
+ - **Gate blocked at critique.** The `phase_advance_blocked` system event
123
+ records the structured reason. Champion adds more `critique` artifacts,
124
+ or overrides the gate on `open` for a permissive one-shot run.
125
+ - **Cycle cap hit without saturation.** `iteration-engine` emits
126
+ `max_iterations_reached`; the driver moves to `synthesis` regardless.
127
+ - **Synthesis missing `addresses_critique`.** Rejected at
128
+ `complete_turn` — the champion re-emits with the ids populated.
129
+
130
+ ## When NOT to use
131
+
132
+ - **Quick clarification.** A 2-turn message thread is cheaper.
133
+ - **Operationally urgent decisions.** The iteration block adds latency —
134
+ use `bclaw_coordinate(intent='consult')` for "the build is broken".
135
+ - **A domain with no accumulated project memory.** The critic will fetch
136
+ nothing and the brief will be a no-op; seed memory first, or run a
137
+ literal multi-agent loop where the critic brings its own perspective.
138
+ - **Validating a change that already exists.** Use
139
+ [`review`](./review.md).
140
+
141
+ ## Reference implementation
142
+
143
+ | Component | File |
144
+ |---|---|
145
+ | Default protocol | [`src/core/loops/types.ts`](../../src/core/loops/types.ts) (`DEFAULT_PROTOCOLS.ideation`) |
146
+ | Iteration FSM | [`src/core/loops/iteration-engine.ts`](../../src/core/loops/iteration-engine.ts) |
147
+ | Gate evaluator | [`src/core/loops/verbs.ts`](../../src/core/loops/verbs.ts) (`evaluatePhaseAdvanceGate`) |
148
+ | Brief assembler | [`src/core/loops/brief-assembly.ts`](../../src/core/loops/brief-assembly.ts) |
149
+ | Driver | [`src/commands/mcp-write-coordination.ts`](../../src/commands/mcp-write-coordination.ts) (`req.intent === 'ideate'`) |
150
+ | 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) |
151
+ | Result reducer | [`src/core/loops/result-reducers.ts`](../../src/core/loops/result-reducers.ts) |
152
+ | 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), [`tests/unit/loops-brief-assembly.test.ts`](../../tests/unit/loops-brief-assembly.test.ts), [`tests/unit/ideation-loop-e2e.test.ts`](../../tests/unit/ideation-loop-e2e.test.ts) |
153
+
154
+ ## Related
155
+
156
+ - [Loop Engine](../concepts/loop-engine.md)
157
+ - [Attempt authority](../concepts/attempt-authority.md)
158
+ - [ideation-loop.md](../concepts/ideation-loop.md) — full RFC
@@ -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)