brainclaw 1.15.0 → 1.17.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 (59) hide show
  1. package/README.md +25 -4
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli/register-capture.js +209 -0
  4. package/dist/cli/register-code-map.js +19 -0
  5. package/dist/cli/register-coordination.js +472 -0
  6. package/dist/cli/register-federation.js +258 -0
  7. package/dist/cli/register-lifecycle.js +436 -0
  8. package/dist/cli/register-memory-context.js +502 -0
  9. package/dist/cli/register-planning.js +167 -0
  10. package/dist/cli/register-review.js +149 -0
  11. package/dist/cli/shared.js +5 -0
  12. package/dist/cli.js +212 -2183
  13. package/dist/commands/dispatch-watch.js +25 -2
  14. package/dist/commands/harvest.js +107 -20
  15. package/dist/commands/mcp-catalog.js +1438 -0
  16. package/dist/commands/mcp-contract.js +33 -0
  17. package/dist/commands/mcp-presentation.js +27 -0
  18. package/dist/commands/mcp-read-handlers.js +72 -36
  19. package/dist/commands/mcp-write-admin.js +328 -0
  20. package/dist/commands/mcp-write-claims.js +864 -0
  21. package/dist/commands/mcp-write-coordination.js +1825 -0
  22. package/dist/commands/mcp-write-entities.js +620 -0
  23. package/dist/commands/mcp-write-memory.js +451 -0
  24. package/dist/commands/mcp-write-sequences.js +116 -0
  25. package/dist/commands/mcp-write-support.js +367 -0
  26. package/dist/commands/mcp.js +261 -5584
  27. package/dist/commands/update-handoff.js +28 -42
  28. package/dist/core/agent-capability.js +38 -16
  29. package/dist/core/agent-files.js +54 -3
  30. package/dist/core/agent-integrations.js +1 -0
  31. package/dist/core/coordination.js +5 -2
  32. package/dist/core/cross-project.js +35 -1
  33. package/dist/core/dispatcher.js +67 -27
  34. package/dist/core/entity-operations.js +335 -12
  35. package/dist/core/entity-registry.js +72 -9
  36. package/dist/core/execution.js +28 -4
  37. package/dist/core/facade-schema.js +18 -4
  38. package/dist/core/handoff-review.js +35 -0
  39. package/dist/core/protocol-tool-policy.js +113 -0
  40. package/dist/core/review-loop-close.js +184 -0
  41. package/dist/core/review-loop-turn-dispatch.js +183 -0
  42. package/dist/core/schema.js +24 -2
  43. package/dist/core/security-detectors.js +35 -6
  44. package/dist/core/security.js +32 -12
  45. package/dist/core/worktree.js +274 -12
  46. package/dist/facts.js +13 -11
  47. package/dist/facts.json +12 -10
  48. package/docs/PROTOCOL.md +7 -3
  49. package/docs/concepts/coordinator-runbook.md +3 -0
  50. package/docs/concepts/dispatch-lifecycle.md +4 -4
  51. package/docs/concepts/loop-engine.md +6 -2
  52. package/docs/concepts/troubleshooting.md +1 -1
  53. package/docs/integrations/codex.md +22 -6
  54. package/docs/integrations/overview.md +1 -1
  55. package/docs/mcp-schema-changelog.md +137 -2
  56. package/docs/playbooks/orchestration.md +1 -1
  57. package/docs/product/entity-model-audit.md +3 -2
  58. package/docs/security.md +22 -1
  59. package/package.json +3 -1
package/dist/facts.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "1.15.0",
3
- "generated_at": "2026-07-15T15:24:46.074Z",
2
+ "version": "1.17.0",
3
+ "generated_at": "2026-07-19T20:01:41.172Z",
4
4
  "tools": {
5
5
  "count": 67,
6
- "published_count": 66,
6
+ "published_count": 65,
7
7
  "names": [
8
8
  "bclaw_bootstrap",
9
9
  "bclaw_release_notes",
@@ -75,7 +75,7 @@
75
75
  ]
76
76
  },
77
77
  "entities": {
78
- "count": 17,
78
+ "count": 18,
79
79
  "names": [
80
80
  "plan",
81
81
  "step",
@@ -93,6 +93,7 @@
93
93
  "assignment",
94
94
  "agent_run",
95
95
  "action",
96
+ "agent",
96
97
  "cross_project_link"
97
98
  ],
98
99
  "short_label_prefixes": {
@@ -112,6 +113,7 @@
112
113
  "assignment": "asgn",
113
114
  "agent_run": "run",
114
115
  "action": "act",
116
+ "agent": "agt",
115
117
  "cross_project_link": "xpl"
116
118
  }
117
119
  },
@@ -217,7 +219,7 @@
217
219
  "workflow_model": "task-based",
218
220
  "tier": "A",
219
221
  "has_mcp": true,
220
- "has_hooks": false,
222
+ "has_hooks": true,
221
223
  "has_skills": true,
222
224
  "has_rules": true,
223
225
  "instruction_file": "AGENTS.md",
@@ -470,7 +472,7 @@
470
472
  },
471
473
  "bench": {
472
474
  "schema": "brainclaw.bench.v1",
473
- "generated_at": "2026-07-15T15:24:43.956Z",
475
+ "generated_at": "2026-07-19T20:01:39.038Z",
474
476
  "node_version": "v24.18.0",
475
477
  "platform": "linux-x64",
476
478
  "repeats": 3,
@@ -480,14 +482,14 @@
480
482
  "volume": "empty",
481
483
  "description": "fresh machine → init → first useful context. Baseline for time-to-first-value.",
482
484
  "duration_ms_median": 76,
483
- "payload_chars_median": 1650,
484
- "payload_tokens_est_median": 413
485
+ "payload_chars_median": 1640,
486
+ "payload_tokens_est_median": 410
485
487
  },
486
488
  {
487
489
  "name": "warm_work",
488
490
  "volume": "medium",
489
491
  "description": "bclaw_work consult over a real-shaped store (~200 plans / 500 handoffs / 450 claims).",
490
- "duration_ms_median": 126,
492
+ "duration_ms_median": 135,
491
493
  "payload_chars_median": 2626,
492
494
  "payload_tokens_est_median": 657
493
495
  },
@@ -495,7 +497,7 @@
495
497
  "name": "first_edit",
496
498
  "volume": "medium",
497
499
  "description": "code_find + code_brief on the fresh-agent path (missing index, first touch).",
498
- "duration_ms_median": 8,
500
+ "duration_ms_median": 7,
499
501
  "payload_chars_median": 442,
500
502
  "payload_tokens_est_median": 111
501
503
  }
package/docs/PROTOCOL.md CHANGED
@@ -131,9 +131,13 @@ offered → accepted → started → (progress)* → completed
131
131
  ```
132
132
 
133
133
  Each transition is emitted via `transition('assignment', id, <status>)`.
134
- A worker that cannot reach the protocol transport (sandboxed) MAY drop a
135
- `LANE-RESULT.json` file at the worktree root as the fallback signal — the
136
- coordinator harvests it.
134
+ A worker MAY drop a `LANE-RESULT.json` file at the worktree root and let the
135
+ coordinator harvest it instead of emitting transitions itself. This is the
136
+ coordinator-owned contract for a sandboxed worker: its sandbox makes `.git`
137
+ read-only (so it cannot `git commit`), and the file is the harvestable signal —
138
+ NOT because MCP is unreachable (a sandboxed worker does reach the MCP server,
139
+ which runs out-of-process; dec#133). A genuinely MCP-less agent uses the same
140
+ file as its only channel.
137
141
 
138
142
  ### 5.3 Claim sentinels
139
143
 
@@ -41,6 +41,9 @@ worker presumed dead
41
41
  │
42
42
  ├─ 1. LANE-RESULT.json at the worktree root?
43
43
  │ yes → it FINISHED. `brainclaw harvest <asgn> [--integrate]`. Done.
44
+ │ (review lane: a `review_verdict` in the file is mapped onto the review
45
+ │ loop by harvest — a `verdict` artifact is recorded and the loop
46
+ │ auto-closes on `approve`; no manual bclaw_loop drive needed.)
44
47
  │
45
48
  ├─ 2. git evidence (shared helper: commits_ahead + dirty_tracked,
46
49
  │ surfaced by dispatch-status / dispatch watch):
@@ -152,16 +152,16 @@ You called `bclaw_coordinate(intent="review", open_loop=true, …)` and got back
152
152
 
153
153
  ## Worktree-as-contract harvest
154
154
 
155
- Some dispatched workers cannot self-commit or call MCP. For example, a sandboxed Codex run may have `dispatchCanCommit=false` because its writable root is the linked worktree, while `.git` lives outside that root. In that case the worker contract is intentionally small:
155
+ Some dispatched workers cannot self-commit. For example, a sandboxed Codex run has `dispatchCanCommit=false` because its writable root is the linked worktree, while `.git` lives outside that root — so it cannot `git commit`. (It *can* still call brainclaw MCP — dec#133 — but the file-based contract below is used regardless, so harvesting stays coordinator-owned and does not depend on the worker's MCP writes.) In that case the worker contract is intentionally small:
156
156
 
157
157
  1. Edit files inside the dispatched worktree.
158
- 2. Write `LANE-RESULT.json` at the worktree root.
158
+ 2. Write `LANE-RESULT.json` at the worktree root — `{ assignment_id, status: completed|blocked|failed, summary, files_changed?, artifacts?, notes? }`. For a **review** lane, the worker also sets `review_verdict` (`approve` | `request_changes`) and `review_summary`; harvest maps those onto the review loop and auto-closes it on `approve` (pln#628 Focus 4B — see [loop-engine.md](./loop-engine.md#automation-extending-bclaw_coordinateintentreview)).
159
159
 
160
160
  The worker does not need to commit, call `bclaw_assignment_update`, or release the claim itself. The worktree is the contract.
161
161
 
162
162
  When the coordinator runs `brainclaw harvest <assignment_id> --integrate`, brainclaw reads the worker's `LANE-RESULT.json`, commits the linked worktree diff on the worker's behalf onto the lane branch, then completes the assignment and releases the claim, including the normal plan-status cascade.
163
163
 
164
- The on-behalf commit is guarded by the linked-worktree check (`isLinkedWorktree`): integration only targets the worktree associated with the assignment, never the main repository. This keeps sandboxed-worker harvesting from turning into an accidental main-repo commit path.
164
+ The on-behalf commit is guarded by the linked-worktree check (`isLinkedWorktree`): integration only targets the worktree associated with the assignment, never the main repository. This keeps sandboxed-worker harvesting from turning into an accidental main-repo commit path. It also excludes brainclaw's own transient/provisioned files from the lane commit — `LANE-RESULT.json`, `.brainclaw/`, `.brainclaw-worktree.json`, heartbeat files, and the `node_modules` link(s) brainclaw provisions (top-level + monorepo `**/node_modules`). The `node_modules` exclusion is tracked-aware: a project that *vendors* (commits) `node_modules` keeps a worker's change to a tracked file — only the freshly-provisioned link/dir is dropped.
165
165
 
166
166
  Integration is strictly additive and opt-in. Plain `brainclaw harvest <assignment_id>` remains report-only; it reads and reports the lane result without committing or mutating assignment / claim state. The on-behalf commit and lifecycle completion happen only when the coordinator passes `--integrate`.
167
167
 
@@ -255,7 +255,7 @@ A dead dispatch needs four cleanup steps (no single facade does all of them toda
255
255
 
256
256
  Spawn behaviour varies by agent. The capability profile in `src/core/agent-capability.ts` describes each agent's prompt delivery, sandbox model, and MCP availability. Per-agent caveats:
257
257
 
258
- - [codex.md](../integrations/codex.md#caveats) — `--sandbox workspace-write` required; spawned codex may not have brainclaw MCP wired; stdin_pipe prompt delivery; brief-ack required for headless dispatch detection.
258
+ - [codex.md](../integrations/codex.md#caveats) — `--sandbox workspace-write` required; sandboxed codex reaches MCP but cannot `git commit` (dec#133 — coordinator harvests the worktree diff); stdin_pipe prompt delivery; brief-ack required for headless dispatch detection.
259
259
  - [claude-code.md](../integrations/claude-code.md) — interactive vs `-p` headless modes; tools whitelist.
260
260
  - [copilot.md](../integrations/copilot.md), [windsurf.md](../integrations/windsurf.md), [cline.md](../integrations/cline.md), [opencode.md](../integrations/opencode.md), [roo.md](../integrations/roo.md), [kilocode.md](../integrations/kilocode.md), [continue.md](../integrations/continue.md) — per-agent specifics.
261
261
  - [mistral-vibe.md](../integrations/mistral-vibe.md) — EU/GDPR self-hosted option.
@@ -330,7 +330,11 @@ When `bclaw_coordinate(intent='review', open_loop: true)` is called, it:
330
330
  3. Links the provided handoff/candidate to the loop as an artifact at `change_summary`.
331
331
  4. Advances to `findings` and calls `bclaw_loop(intent: 'turn')` to dispatch to the reviewer.
332
332
  5. On turn completion with a verdict artifact, auto-advances; `reviewer_green` stop closes.
333
- 6. On non-green verdict with `iteration_count < max`, advances to `author_response`, dispatches to author.
333
+ 6. On a `request_changes` verdict, the fix cycle re-dispatches the reviewer into the same worktree until `approve` or the `max_iterations` cap.
334
+
335
+ **How the verdict reaches the loop (shipped, pln#628 Focus 4B).** A dispatched reviewer worker does not call `bclaw_loop` itself — it writes its outcome to `LANE-RESULT.json` at the worktree root, including an optional `review_verdict` (`approve` | `request_changes`) and `review_summary`. When the coordinator runs `brainclaw harvest <assignment_id>` (report-only path and `--integrate`), a review lane carrying a `review_verdict` is mapped onto its loop: brainclaw records a `verdict` artifact on the reviewer slot (`approve` → an `accepted…` body) and calls `advance`, which **auto-closes the loop on `reviewer_green` for `approve`** — no human driving `complete_turn`/`advance`.
336
+
337
+ **The autonomous fix cycle (PR2, `--integrate` only).** On `request_changes`, `harvest --integrate` bumps the loop's round counter, **keeps the claim + worktree alive**, and re-dispatches the same reviewer slot into that **same worktree** (symmetric mode) with a findings-aware brief: apply the requested changes in place, then re-review. Commits accumulate on one branch — no fresh worktree per turn, so the branch-per-scope / refuse-unharvested-commits invariants are never tripped. The cycle repeats until `approve` (→ `reviewer_green` close) or the `max_iterations` cap (n=3 → auto-close `blocked`, handed to a human). The report-only harvest path never cycles (it can neither re-dispatch nor retain the claim); it defers `request_changes` to `--integrate` and still closes on `approve`. The mapping is idempotent, resolves the reviewer slot strictly by `assignment_id` (so symmetric multi-reviewer loops target the right slot), and runs the `complete_turn`+`advance` pair under the loop lock so an interrupted pass resumes rather than stalls. Asymmetric (author ≠ reviewer) cross-agent worktree sharing is a planned follow-up.
334
338
 
335
339
  ### Symmetric review-AND-fix mode
336
340
 
@@ -514,7 +518,7 @@ Status after Codex schema review (cnd#574 / `dec_be66ccbf`, verdict `needs_revis
514
518
 
515
519
  The loop surface exposed over MCP is intentionally narrow:
516
520
 
517
- - **Review loops** — `bclaw_coordinate(intent="review", open_loop=true, review_mode="asymmetric"|"symmetric", targetAgents=[…])` opens the loop and dispatches the first turn. Drive subsequent turns with `bclaw_loop(intent="turn"|"complete_turn"|"advance"|"close")`.
521
+ - **Review loops** — `bclaw_coordinate(intent="review", open_loop=true, review_mode="asymmetric"|"symmetric", targetAgents=[…])` opens the loop and dispatches the first turn. The reviewer's verdict is then harvested from `LANE-RESULT.json` (`review_verdict`) and **auto-advances/closes the loop on approve** — no manual driving needed for the approve path (pln#628 Focus 4B). `bclaw_loop(intent="turn"|"complete_turn"|"advance"|"close")` remains available to drive turns by hand (e.g. the `request_changes` fix cycle, or a human-operated slot).
518
522
  - **Ideation loops** — `bclaw_coordinate(intent="ideate", preset="bootstrap")` opens an ideation loop from a preset.
519
523
 
520
524
  Custom phase lists (`LoopPhase[]`) and bespoke `StopCondition` logic exist in the loop engine internally, but are **not** exposed through the MCP facade today: `CoordinateRequestSchema` accepts only `open_loop`, `review_mode`, `preflight`, `ref`, and `preset` — no `phases` or `stop_condition` — and the standalone `bclaw_loop` tool does not expose an `open` intent. Programmatic construction of ad-hoc loops is therefore internal / future work until the facade is extended.
@@ -206,7 +206,7 @@ brainclaw stale resolve <plan_id> # → dropped (default for stale)
206
206
 
207
207
  **Symptom**: a dispatched assignment shows `running` indefinitely, and `bclaw_assignment_events` shows `run_running` but no further progress.
208
208
 
209
- **Why**: the spawned worker process either (a) crashed before reading its inbox, (b) read the inbox but couldn't acknowledge (e.g., MCP unavailable inside the spawned sandbox — common with codex `--sandbox workspace-write`), or (c) is genuinely still working but slow.
209
+ **Why**: the spawned worker process either (a) crashed before reading its inbox, (b) started but the brief-ack sentinel never fired (spawn wrapper died, wrong CODEX_HOME/auth, or the CLI exited early — NOT because the sandbox blocks MCP: dec#133 shows a sandboxed codex reaches MCP fine), or (c) is genuinely still working but slow.
210
210
 
211
211
  **Diagnostic order**:
212
212
 
@@ -1,13 +1,13 @@
1
1
  # Codex Integration
2
2
 
3
- brainclaw integrates with OpenAI's Codex CLI through MCP tools and shared instruction files. Codex has MCP access, universal skills support, and headless CLI spawn capability, but no native lifecycle hook surface.
3
+ brainclaw integrates with OpenAI's Codex CLI through MCP tools, shared instruction files, and native lifecycle hooks. Codex has MCP access, universal skills support, headless CLI spawn capability, and a native lifecycle hook surface (added upstream in 2026 — [developers.openai.com/codex/hooks](https://developers.openai.com/codex/hooks)).
4
4
 
5
5
  ## Auto-setup
6
6
 
7
7
  Codex setup is split across machine and project scope:
8
8
 
9
9
  - `brainclaw setup-machine --agents codex --yes` writes the machine-level MCP config at `~/.codex/config.toml`
10
- - `brainclaw init` creates or refreshes the current project's Brainclaw state and writes `AGENTS.md`
10
+ - `brainclaw init` creates or refreshes the current project's Brainclaw state, writes `AGENTS.md`, and writes project-level lifecycle hooks to `.codex/hooks.json` (git-ignored)
11
11
 
12
12
  If the project already has `.brainclaw/`, rerunning `brainclaw init` is safe and refreshes the managed Brainclaw/Codex files for the current machine.
13
13
 
@@ -43,7 +43,7 @@ Codex is CLI-spawnable for parallel lanes and dispatched workflows. The canonica
43
43
  codex exec -c approval_policy="never" --sandbox workspace-write "{prompt}"
44
44
  ```
45
45
 
46
- The `--sandbox workspace-write` setting is required, **not `read-only`** — the read-only sandbox blocks the MCP filesystem writes that brainclaw needs (worktree handoffs, session files, etc.) and forces fallback to GitHub connectors which fail for local-only commits.
46
+ The `--sandbox workspace-write` setting is required, **not `read-only`** — the worker needs to write files in its own worktree (the edits it produces, plus its `LANE-RESULT.json`) so the coordinator has a harvestable diff. This is about the worker's *file* writes, not MCP: the brainclaw MCP server runs out-of-sandbox and is reachable under either sandbox mode (dec#133). What the sandbox does block is `git commit` (`.git` is outside the writable root), so the coordinator commits the worktree diff at harvest.
47
47
 
48
48
  ### Prompt delivery: stdin_pipe (preferred)
49
49
 
@@ -53,7 +53,7 @@ When you (or the dispatcher) calls Codex with no positional `[PROMPT]`, Codex re
53
53
 
54
54
  ### Brief-ack handshake
55
55
 
56
- Since pln#476 (1.0.13+), spawned Codex workers are marked `delivered_and_started` once the wrapping shell touches a brief-ack sentinel at `.brainclaw/coordination/runtime/ack/<assignmentId>.ack`. This proves the spawn actually executed and decouples the handshake from MCP availability inside the worker — important because Codex spawned in `--sandbox workspace-write` may not have brainclaw MCP wired in its session.
56
+ Since pln#476 (1.0.13+), spawned Codex workers are marked `delivered_and_started` once the wrapping shell touches a brief-ack sentinel at `.brainclaw/coordination/runtime/ack/<assignmentId>.ack`. This proves the spawn actually executed and decouples the handshake from whatever the worker does next — the spawn is confirmed even before the worker makes its first MCP call. (Note — dec#133: a sandboxed Codex run **does** reach brainclaw MCP; the server runs out-of-sandbox and `approval_policy=never` auto-approves. The sentinel is about confirming the spawn, not about MCP being unavailable.)
57
57
 
58
58
  ## Capability profile
59
59
 
@@ -61,7 +61,7 @@ Since pln#476 (1.0.13+), spawned Codex workers are marked `delivered_and_started
61
61
  |-------|-------|
62
62
  | Tier | A |
63
63
  | MCP | yes |
64
- | Hooks | no |
64
+ | Hooks | yes (`.codex/hooks.json`, project scope) |
65
65
  | Auto-approve | manual (per-tool approval) |
66
66
  | Skills | yes |
67
67
  | CLI spawnable | yes |
@@ -70,9 +70,25 @@ Since pln#476 (1.0.13+), spawned Codex workers are marked `delivered_and_started
70
70
  | MCP config scope | machine |
71
71
  | Prompt delivery | `stdin_pipe` (preferred), `inline_arg` (fallback) |
72
72
 
73
+ ## Lifecycle hooks
74
+
75
+ `brainclaw init` writes project-level hooks to `.codex/hooks.json` (git-ignored, machine-specific command paths). Codex reads hooks from `hooks.json` or an inline `[hooks]` table at user (`~/.codex/`) and project (`<repo>/.codex/`) scope ([Codex hooks docs](https://developers.openai.com/codex/hooks)). brainclaw wires three events:
76
+
77
+ | Event | brainclaw command | Purpose |
78
+ |-------|-------------------|---------|
79
+ | `SessionStart` | `brainclaw session-start --include-context` | Load shared context (constraints, decisions, traps, plans, handoffs) when a session begins |
80
+ | `UserPromptSubmit` | `brainclaw context-diff` | Surface what changed since the last turn |
81
+ | `Stop` | `brainclaw session-end --auto-release --reflect --reflect-handoff --dispatch-review` | Release claims, reflect, and dispatch review at turn end |
82
+
83
+ The file shape is `{ "hooks": { "<Event>": [ { "matcher": "", "hooks": [ { "type": "command", "command": "…" } ] } ] } }` (`matcher: ""` = match all occurrences). brainclaw **owns** these three event arrays: reruns overwrite them (idempotent, no cross-upgrade pile-up) — the same contract as the Cursor / Antigravity hook writers. A user's own hook placed on one of these three events is replaced on the next `init`; hooks on any **other** event are left untouched.
84
+
85
+ **Scope — interactive sessions, not headless dispatch.** These hooks serve an *interactive* Codex session. Non-managed command hooks require a one-time trust in Codex (`/hooks` — inspect and trust) before they run, so a fresh `.codex/hooks.json` is inert until the user trusts it. Headless dispatched workers (`codex exec`, used by `bclaw_dispatch` / `bclaw_coordinate`) do **not** rely on these hooks at all — they receive their context in the dispatch brief and report via `LANE-RESULT.json`; an untrusted project hook is simply skipped there, which is harmless. (A "managed" hook path via `requirements.toml`/MDM could bypass the trust step for fleets — a possible future enhancement.)
86
+
87
+ **Per-event output contract.** `SessionStart` and `UserPromptSubmit` emit their stdout as **model-visible context** — that is exactly the point (inject shared brainclaw state / the context diff). `Stop`, by contrast, expects a **JSON** response from Codex to shape turn-end behavior; brainclaw's `session-end` runs mainly for its side effects (release claims, reflect, dispatch review) and does not emit that JSON, so it does not gate the turn. Emitting a conformant per-event JSON response (notably for `Stop`) is a planned follow-up.
88
+
73
89
  ## Caveats
74
90
 
75
- - **Sandbox blocks MCP writes**: when running with strict sandbox, the spawned Codex cannot write to `.brainclaw/` directly. Use the brief-ack file plus filesystem-direct candidate writes (the dispatcher harvests them).
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.
76
92
  - **Windows quoting**: long prompts containing backticks or `#` fail when passed as inline args through `cmd.exe`. The default stdin_pipe path avoids this.
77
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).
78
94
  - **No always-allow**: each MCP tool call still respects per-call approval policy unless explicitly set with `-c approval_policy="never"`.
@@ -103,7 +103,7 @@ The developer can dial back individual surfaces if needed, but the default is fu
103
103
 
104
104
  brainclaw's store mutations are serialized (MCP single-writer queue + file-based lock), so memory writes are safe even under contention.
105
105
 
106
- For **parallel work**, dispatch a sequence with `bclaw_dispatch(intent="execute")` — each lane gets its own auto-worktree under `~/.brainclaw/worktrees/<project-hash>/`, and the coordinator integrates with an octopus merge. For **review-fix loops**, `bclaw_coordinate(intent="review", open_loop=true, review_mode="symmetric")` runs an alternating review-and-fix conversation across two slots without shared-checkout collisions. These are the supported parallel paths today.
106
+ For **parallel work**, dispatch a sequence with `bclaw_dispatch(intent="execute")` — each lane gets its own auto-worktree under `~/.brainclaw/worktrees/<project-hash>/`, and the coordinator integrates with an octopus merge. For **review-fix loops**, `bclaw_coordinate(intent="review", open_loop=true, review_mode="symmetric")` runs an alternating review-and-fix conversation across two slots without shared-checkout collisions — and the loop **auto-closes on reviewer approve** (the verdict is harvested from `LANE-RESULT.json`, no manual drive). These are the supported parallel paths today.
107
107
 
108
108
  For **sequential work** in the same project, let one agent claim at a time and rely on handoffs to keep continuity across sessions.
109
109
 
@@ -10,6 +10,112 @@ guarantees this changelog follows.
10
10
 
11
11
  ## Unreleased
12
12
 
13
+ **Added — `LaneResultSchema.review_verdict` / `review_summary` (pln#628 Focus 4B)**
14
+ - `LANE-RESULT.json` (the worktree-root file a dispatched worker writes) gains two
15
+ optional fields: `review_verdict` (`approve` | `request_changes`) and
16
+ `review_summary` (one-line rationale). Absent on non-review lanes.
17
+ - Consumed by `brainclaw harvest` (report path + `--integrate`): a review lane
18
+ carrying a `review_verdict` is mapped onto its review loop — a `verdict` artifact
19
+ is recorded and the loop advances, auto-closing on `reviewer_green` for
20
+ `approve`. Additive + backward-compatible; no tool added/removed/renamed and no
21
+ surface-fingerprint change (LaneResultSchema is not part of the read/write
22
+ contract fingerprint).
23
+
24
+ **Added — `bclaw_update(entity='handoff')` incl. review/contract (pln#625 Phase 3)**
25
+ - The handoff update path is now wired. Previously `bclaw_update(entity='handoff')`
26
+ fell through to "not yet wired" (the field check passed for narrative/tags but
27
+ there was no handler case). `handoff.updatable` now also includes `review` and
28
+ `contract`, each validated against `HandoffReviewSchema` / `HandoffContractSchema`
29
+ and merged onto the record.
30
+ - This **restores the review-state write capability lost at v1.0** when
31
+ `bclaw_update_handoff` was removed: an agent can write a review verdict via
32
+ `bclaw_update(entity='handoff', data={ review: { verdict, summary, … } })`.
33
+ A verdict auto-stamps `review.reviewed_at`. The review loop's core
34
+ (`applyHandoffUpdates`) is unchanged — this is the canonical-grammar front door
35
+ onto the same record.
36
+ - Tip guard: a superseded (tombstoned) handoff is refused, pointing at the tip.
37
+ - No tool added/removed/renamed; `updatable` is not part of the surface
38
+ fingerprint, so no fingerprint change.
39
+
40
+ **Removed — `bclaw_list_agents` (pln#625; migrate to `bclaw_find(entity='agent')`)**
41
+ - `bclaw_list_agents` — the last surviving `bclaw_list_*` tool — is retired into
42
+ `REMOVED_IN_V1_TOOLS`: hidden from every `tools/list`, with a direct-call
43
+ deprecation warning pointing at `bclaw_find(entity='agent')`. The handler
44
+ stays as a redacted read escape-hatch (`LEGACY_READ_TOOL_HANDLERS`), same as
45
+ its `list_*` siblings.
46
+ - To preserve its one unique capability, `bclaw_find(entity='agent')` gains an
47
+ agent-only `includeReputation` filter that attaches the public reputation
48
+ summary per agent (same join the CLI `list-agents --with-reputation` uses).
49
+ - Net surface coherence: `agent` reads now flow through one grammar path with a
50
+ single redacted projection (`projectAgentForRead`), closing the divergent
51
+ double-surface (the old tool leaked raw `identity_key`/`invoke.env`).
52
+
53
+ **Changed — governance guard now covers grammar entities AND the filter contract (pln#625)**
54
+ - `tests/unit/mcp-governance.test.ts` folds two free-form parts of the callable
55
+ contract into the public-surface fingerprint: the set of addressable grammar
56
+ entities (`ENTITY_NAMES`) and the find/get filter grammar
57
+ (`GRAMMAR_FILTER_CONTRACT` — accepted keys, entity-scoping, constrained
58
+ values). Both were previously invisible (the `entity` and `filter` args are
59
+ free-form and their enumerating descriptions are stripped), so wiring a new
60
+ `bclaw_find/get(entity='…')` target or adding/re-scoping/re-valuing a filter
61
+ key (e.g. the Phase 2c `scope`) could ship without a changelog entry.
62
+ - `GRAMMAR_FILTER_CONTRACT` (exported from `entity-operations.ts`) is now the
63
+ single source of truth for the handler's filter validation AND the
64
+ fingerprint, so the two can never drift. A mutation test proves the
65
+ fingerprint reacts to an added entity, key, re-scope, and new value.
66
+ - Closes the blind spot surfaced by the Phase 2c ideation loop; the filter-grammar
67
+ extension came from the Codex review of PR #82.
68
+
69
+ **Added — read-only `agent` entity in the canonical grammar (pln#625 Phase 2c)**
70
+ - `bclaw_find/get(entity='agent')` are now wired. They return a REDACTED,
71
+ read-only projection: `id`, `name`, `kind`, `trust_level`, `capabilities`,
72
+ `fingerprint` (full sha256(PEM) — the public canonical key id), `model`,
73
+ `context_profile`, `created_at`. The private key material (`identity_key`,
74
+ `public_key` PEM) and `invoke` (unpopulated dead field; would leak
75
+ `invoke.command`) are never surfaced. Writes (`create/update/remove/transition`)
76
+ return the `SystemManagedError` boundary — agents are managed via
77
+ `bclaw_setup` / `enable-agent`, not the grammar.
78
+ - New agent-only filter `scope`: `bclaw_find(entity='agent')` defaults to the
79
+ current project's registry; `filter.scope='global'` additionally unions the
80
+ static dispatchable catalog (`getSpawnableAgents`) and annotates each entry
81
+ with `dispatchable` (canBeSpawnedCli) + `registered`. `scope` is rejected for
82
+ any other entity, and its value must be `project` (default) or `global`.
83
+ - `bclaw_list_agents` now redacts through the SAME projection (one source of
84
+ truth). It previously spread the raw identity document, leaking
85
+ `identity_key.public_key` and `invoke.env` in the clear — a pre-existing
86
+ disclosure, now closed. `includeReputation` still attaches the reputation
87
+ add-on.
88
+ - This supersedes the Phase 1a stopgap that reported `agent` as "not addressable
89
+ via the canonical grammar" (never released; last tag v1.15.0).
90
+
91
+ **Fixed — `bclaw_transition(entity='handoff')` wired (pln#625 Phase 2a)**
92
+ - The handoff lifecycle (`open→accepted|closed`, `accepted→closed`) is now
93
+ wired. It previously fell to the "not yet wired" default, which also broke
94
+ `brainclaw stale resolve <handoff-id>` (that command routes through the
95
+ canonical transition). A tip guard refuses to transition a handoff carrying
96
+ `superseded_by` (an immutable correction tombstone) and points at the tip.
97
+ - No tool was added, removed, or renamed; no required argument changed.
98
+
99
+ **Fixed — `bclaw_coordinate` published-schema parity (pln#622 PR0b)**
100
+ - The published inputSchema of `bclaw_coordinate` now declares `preset`
101
+ (loop preset selector, valid only with `intent='ideate'`; v1 ships the
102
+ single preset `bootstrap`; unknown names are rejected with
103
+ `unknown_preset`, other intents with `preset_kind_mismatch`) and
104
+ `client_request_id` (caller-minted ULID/UUIDv7 for idempotent retries,
105
+ observed on `intent='review'` + `open_loop=true`, safe elsewhere). Both
106
+ were already accepted by `CoordinateRequestSchema` and used by the
107
+ handler — and `next_actions` literally recommended
108
+ `bclaw_coordinate(intent='ideate', preset='bootstrap')` — but the catalog
109
+ never declared them, so strict MCP clients could not follow the product's
110
+ own recommendation.
111
+ - New guard: `tests/unit/mcp-facade-structural-parity.test.ts` asserts
112
+ bidirectional structural parity (keys + shared enum values) between the
113
+ hand-written facade schemas (`bclaw_work`, `bclaw_coordinate`) and their
114
+ zod sources, with an explicit allowlist for adapter-envelope fields
115
+ (`agent`, `agentId`).
116
+ - No tool was added, removed, or renamed; no required argument changed.
117
+ - Surface fingerprint bumped in the `(current)` section below.
118
+
13
119
  **Changed — MCP model selection parity (pln#520/#606)**
14
120
  - `bclaw_dispatch` and `bclaw_coordinate` gain an optional `model` string that
15
121
  selects the spawned worker's model (e.g. `sonnet`, `gpt-5-codex`), decoupled
@@ -132,8 +238,37 @@ will still succeed. A follow-up PR will strip the dead handler code.
132
238
  changelog records the published MCP surface fingerprint. When a tool
133
239
  name, tier, category, or input schema changes, the test fails until
134
240
  this section is updated.
135
- - MCP public surface fingerprint: `sha256:b53eb56d4391b5a6`
136
- (updated 2026-07-15 for pln#520/#606: optional `model` string added to
241
+ - MCP public surface fingerprint: `sha256:468f0103414e97e8`
242
+ (updated 2026-07-18 for pln#625 PR #83 + Codex review: `bclaw_list_agents`
243
+ retired and `bclaw_find(entity='agent')` gains `includeReputation` — now typed
244
+ as a boolean in `GRAMMAR_FILTER_CONTRACT.booleanKeys` and validated at the MCP
245
+ front door, so a non-boolean value is rejected instead of silently coercing to
246
+ a no-op. The added boolean-type declaration moves the fingerprint.)
247
+ Previous: `sha256:be0df1e4cc33936f`
248
+ (updated 2026-07-17 for pln#625 PR #83: `bclaw_list_agents` retired from the
249
+ published surface — migrated to `bclaw_find(entity='agent')` which gains an
250
+ agent-only `includeReputation` filter. Both the removed tool and the new
251
+ filter key move the fingerprint via the guard now covering PUBLISHED_TOOLS +
252
+ ENTITY_NAMES + GRAMMAR_FILTER_CONTRACT.)
253
+ Previous: `sha256:e12fd2f34dae1ac0`
254
+ (updated 2026-07-17 for pln#625 Phase 2c + PR #82: the fingerprint now folds in
255
+ two parts of the callable contract that the tool inputSchema cannot express —
256
+ the set of grammar-addressable entities (`ENTITY_NAMES`) and the find/get
257
+ filter grammar (`GRAMMAR_FILTER_CONTRACT`: accepted keys, entity-scoping, and
258
+ constrained values such as `scope=project|global`). Both were invisible to the
259
+ fingerprint before (`entity` and `filter` are free-form and their enumerating
260
+ descriptions are stripped), so wiring a new addressable entity — or adding /
261
+ re-scoping / re-valuing a filter key like the Phase 2c `scope` — slipped past
262
+ this guard. Additive: no tool added, removed, or renamed.)
263
+ Previous: `sha256:45c02576aff36244`
264
+ (updated 2026-07-15 for pln#622 PR0b: `preset` and `client_request_id` added
265
+ to the published `bclaw_coordinate` input schema. Both were already accepted
266
+ by `CoordinateRequestSchema` and used by the handler — and `next_actions`
267
+ recommended `bclaw_coordinate(intent='ideate', preset='bootstrap')` — but
268
+ the catalog never declared them. Additive: no tool added, removed, or
269
+ renamed; no required argument changed.
270
+ Previous: `sha256:b53eb56d4391b5a6`
271
+ updated 2026-07-15 for pln#520/#606: optional `model` string added to
137
272
  `bclaw_dispatch` and `bclaw_coordinate` input schemas — selects the spawned
138
273
  worker's model, decoupled from agent identity (CLI/MCP parity with
139
274
  `dispatch run --model`). Additive: no tool added, removed, or renamed; no
@@ -24,7 +24,7 @@ With the plan and sequences established, assign the work to execution agents.
24
24
 
25
25
  - **Sequence-driven execution:** Use `bclaw_dispatch(intent="execute")` to parallelize plans across your defined sequence lanes automatically.
26
26
  - **Direct orchestration:** For ad-hoc delegation, use `bclaw_coordinate(intent="assign")` to assign specific tasks to target agents. This seamlessly generates the necessary claims and dispatch briefs.
27
- - **Reviews & Loops:** To open a structured review process on completed work, use `bclaw_coordinate(intent="review", open_loop=true)`.
27
+ - **Reviews & Loops:** To open a structured review process on completed work, use `bclaw_coordinate(intent="review", open_loop=true)`. The reviewer's verdict is harvested from its `LANE-RESULT.json` (`review_verdict`) and the loop **auto-closes on approve** — no manual `complete_turn`/`advance` round-trip to close the approve path (pln#628 Focus 4B).
28
28
  - Use `bclaw_dispatch_status` to verify worker liveness, examine log tails, and ensure dispatches are progressing healthily.
29
29
 
30
30
  ## Step 4: Manage the Inbox
@@ -84,8 +84,9 @@ load-bearing; simplifications cannot break them.
84
84
  "never init --force"). Strongest concept; drives hook injection
85
85
  to remind agents of the process.
86
86
  - **Trap**: environmental or process pitfall to avoid (e.g., "git
87
- merge wipes node_modules", "sandbox X blocks MCP writes"). May
88
- trigger a corrective plan when resolvable.
87
+ merge wipes node_modules", "a sandboxed worker's `.git` is read-only
88
+ → it cannot `git commit`"). May trigger a corrective plan when
89
+ resolvable.
89
90
  All three drive different agent behaviours (decisions = retrieve for
90
91
  context, constraints = enforce, traps = warn + resolve).
91
92
 
package/docs/security.md CHANGED
@@ -45,7 +45,28 @@ matches block the write.
45
45
 
46
46
  When `security.block_sensitive_paths: true` (default), content that
47
47
  references paths like `.env`, `secrets/`, `.git/`, or `node_modules/`
48
- emits a warning.
48
+ is flagged. `block_sensitive_paths` is the **enable-gate** for this layer;
49
+ the flagged level follows the same rule as every other signal — a `warn`
50
+ normally, escalating to `block` under `strict_redaction: true` (mode:
51
+ strict). It is not a standalone block toggle: in warn mode a sensitive-path
52
+ mention warns; in strict mode it blocks, uniformly with redaction, structural,
53
+ and entropy matches.
54
+
55
+ ### Signal layers and levels
56
+
57
+ `scanText` runs four independent layers, each with its own enable-gate, and
58
+ they all share one level rule:
59
+
60
+ | Layer | Enable-gate | Level (warn mode / strict) |
61
+ |-------|-------------|----------------------------|
62
+ | Redaction patterns | `redaction.enabled` | warn / block |
63
+ | Structural detectors | `security.token_detection.enabled` | warn / block |
64
+ | Entropy detector | `security.token_detection.entropy.enabled` | warn / block |
65
+ | Sensitive paths | `security.block_sensitive_paths` | warn / block |
66
+
67
+ `strict_redaction: true` escalates **every** matched signal to `block`
68
+ uniformly; there is no per-layer level override. Excerpts in messages are
69
+ always irreversibly masked.
49
70
 
50
71
  ### Configuration
51
72
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainclaw",
3
- "version": "1.15.0",
3
+ "version": "1.17.0",
4
4
  "description": "Shared project memory for humans and coding agents.",
5
5
  "type": "module",
6
6
  "repository": {
@@ -62,6 +62,8 @@
62
62
  "test:coverage:check": "npm run build:test && c8 --all --check-coverage --lines 55 --functions 60 --branches 65 --statements 55 --src dist-test/src --reporter=text-summary --exclude=dist-test/tests/** --exclude=dist-test/scripts/** node scripts/run-tests.mjs default",
63
63
  "bench": "npm run build:test && node scripts/bench.mjs",
64
64
  "bench:check": "node scripts/bench-check.mjs",
65
+ "bench:cold-start": "node scripts/bench-cold-start.mjs",
66
+ "bench:cold-start:check": "node scripts/bench-cold-start.mjs --check",
65
67
  "prepublishOnly": "npm run build:release && npm run pack:check"
66
68
  },
67
69
  "keywords": [