brainclaw 1.9.0 → 1.10.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 (149) hide show
  1. package/README.md +631 -499
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +18 -1
  4. package/dist/commands/code-map.js +129 -0
  5. package/dist/commands/codev.js +7 -0
  6. package/dist/commands/harvest.js +1 -1
  7. package/dist/commands/hooks.js +73 -73
  8. package/dist/commands/init.js +1 -1
  9. package/dist/commands/install-hooks.js +78 -78
  10. package/dist/commands/mcp-read-handlers.js +57 -14
  11. package/dist/commands/mcp.js +200 -13
  12. package/dist/commands/run-profile.js +3 -2
  13. package/dist/commands/switch.js +125 -93
  14. package/dist/commands/version.js +1 -1
  15. package/dist/core/agent-capability.js +19 -4
  16. package/dist/core/agent-files.js +131 -119
  17. package/dist/core/code-map/backend.js +123 -0
  18. package/dist/core/code-map/core.js +81 -0
  19. package/dist/core/code-map/drafts.js +2 -0
  20. package/dist/core/code-map/extractor.js +29 -0
  21. package/dist/core/code-map/finalizer.js +191 -0
  22. package/dist/core/code-map/freshness.js +108 -0
  23. package/dist/core/code-map/ids.js +0 -0
  24. package/dist/core/code-map/importable.js +35 -0
  25. package/dist/core/code-map/indexes.js +197 -0
  26. package/dist/core/code-map/lang/java/imports.scm +17 -0
  27. package/dist/core/code-map/lang/java/index.js +254 -0
  28. package/dist/core/code-map/lang/java/tags.scm +48 -0
  29. package/dist/core/code-map/lang/php/imports.scm +21 -0
  30. package/dist/core/code-map/lang/php/index.js +251 -0
  31. package/dist/core/code-map/lang/php/tags.scm +44 -0
  32. package/dist/core/code-map/lang/provider.js +9 -0
  33. package/dist/core/code-map/lang/providers.js +24 -0
  34. package/dist/core/code-map/lang/python/imports.scm +90 -0
  35. package/dist/core/code-map/lang/python/index.js +364 -0
  36. package/dist/core/code-map/lang/python/tags.scm +81 -0
  37. package/dist/core/code-map/lang/query-runtime.js +374 -0
  38. package/dist/core/code-map/lang/registry.js +125 -0
  39. package/dist/core/code-map/lang/typescript/imports.scm +90 -0
  40. package/dist/core/code-map/lang/typescript/index.js +306 -0
  41. package/dist/core/code-map/lang/typescript/tags.js.scm +106 -0
  42. package/dist/core/code-map/lang/typescript/tags.scm +151 -0
  43. package/dist/core/code-map/lock.js +210 -0
  44. package/dist/core/code-map/materialized.js +51 -0
  45. package/dist/core/code-map/memory-reader.js +59 -0
  46. package/dist/core/code-map/paths.js +53 -0
  47. package/dist/core/code-map/query.js +568 -0
  48. package/dist/core/code-map/refresh.js +0 -0
  49. package/dist/core/code-map/resolve.js +177 -0
  50. package/dist/core/code-map/store.js +206 -0
  51. package/dist/core/code-map/types.js +288 -0
  52. package/dist/core/code-map/vocabulary.js +57 -0
  53. package/dist/core/code-map/wasm-loader.js +294 -0
  54. package/dist/core/code-map/work-section.js +206 -0
  55. package/dist/core/codev-prompts.js +38 -38
  56. package/dist/core/codev-rounds.js +4 -0
  57. package/dist/core/default-profiles/doctor.yaml +11 -11
  58. package/dist/core/default-profiles/janitor.yaml +11 -11
  59. package/dist/core/default-profiles/onboarder.yaml +11 -11
  60. package/dist/core/default-profiles/reviewer.yaml +13 -13
  61. package/dist/core/dispatcher.js +1 -1
  62. package/dist/core/entity-operations.js +29 -3
  63. package/dist/core/execution-adapters.js +11 -10
  64. package/dist/core/execution-profile.js +58 -0
  65. package/dist/core/execution.js +1 -1
  66. package/dist/core/facade-schema.js +9 -0
  67. package/dist/core/instruction-templates.js +2 -0
  68. package/dist/core/loops/verbs.js +0 -1
  69. package/dist/core/mcp-command-resolution.js +3 -1
  70. package/dist/core/messaging.js +2 -2
  71. package/dist/core/protocol-skills.js +164 -164
  72. package/dist/core/runtime-signals.js +1 -1
  73. package/dist/core/search.js +19 -2
  74. package/dist/core/security-guard.js +207 -207
  75. package/dist/core/spawn-check.js +16 -2
  76. package/dist/core/staleness.js +1 -1
  77. package/dist/core/store-resolution.js +67 -11
  78. package/dist/core/worktree.js +18 -18
  79. package/dist/facts.js +9 -5
  80. package/dist/facts.json +8 -4
  81. package/dist/vendor/web-tree-sitter/tree-sitter.js +3980 -0
  82. package/dist/vendor/web-tree-sitter/tree-sitter.wasm +0 -0
  83. package/dist/wasm/tree-sitter-java.wasm +0 -0
  84. package/dist/wasm/tree-sitter-javascript.wasm +0 -0
  85. package/dist/wasm/tree-sitter-php.wasm +0 -0
  86. package/dist/wasm/tree-sitter-python.wasm +0 -0
  87. package/dist/wasm/tree-sitter-tsx.wasm +0 -0
  88. package/dist/wasm/tree-sitter-typescript.wasm +0 -0
  89. package/dist/wasm/tree-sitter.wasm +0 -0
  90. package/docs/PROTOCOL.md +1 -1
  91. package/docs/adapters/openclaw.md +43 -43
  92. package/docs/architecture/project-refs.md +328 -328
  93. package/docs/cli.md +2131 -2093
  94. package/docs/code-map.md +198 -0
  95. package/docs/concepts/coordination.md +52 -52
  96. package/docs/concepts/coordinator-runbook.md +129 -129
  97. package/docs/concepts/dispatch-lifecycle.md +245 -245
  98. package/docs/concepts/event-log-store.md +928 -928
  99. package/docs/concepts/ideation-loop.md +317 -317
  100. package/docs/concepts/loop-engine.md +520 -511
  101. package/docs/concepts/mcp-governance.md +268 -268
  102. package/docs/concepts/memory.md +84 -84
  103. package/docs/concepts/multi-agent-workflows.md +167 -167
  104. package/docs/concepts/observer-protocol.md +361 -361
  105. package/docs/concepts/plans-and-claims.md +217 -217
  106. package/docs/concepts/project-md-convention.md +35 -35
  107. package/docs/concepts/runtime-notes.md +38 -38
  108. package/docs/concepts/troubleshooting.md +254 -254
  109. package/docs/concepts/workspace-bootstrapping.md +142 -142
  110. package/docs/context-format-changelog.md +35 -35
  111. package/docs/context-format.md +48 -48
  112. package/docs/index.md +65 -65
  113. package/docs/integrations/agents.md +158 -158
  114. package/docs/integrations/claude-code.md +23 -23
  115. package/docs/integrations/cline.md +77 -77
  116. package/docs/integrations/continue.md +55 -55
  117. package/docs/integrations/copilot.md +68 -68
  118. package/docs/integrations/cursor.md +23 -23
  119. package/docs/integrations/kilocode.md +72 -72
  120. package/docs/integrations/mcp.md +385 -378
  121. package/docs/integrations/mistral-vibe.md +122 -122
  122. package/docs/integrations/openclaw.md +92 -92
  123. package/docs/integrations/opencode.md +84 -84
  124. package/docs/integrations/overview.md +115 -115
  125. package/docs/integrations/roo.md +71 -71
  126. package/docs/integrations/windsurf.md +77 -77
  127. package/docs/mcp-schema-changelog.md +364 -356
  128. package/docs/playbooks/integration/index.md +121 -121
  129. package/docs/playbooks/orchestration.md +37 -0
  130. package/docs/playbooks/productivity/index.md +99 -99
  131. package/docs/playbooks/team/index.md +117 -117
  132. package/docs/product/agent-first-model.md +184 -184
  133. package/docs/product/entity-model-audit.md +462 -462
  134. package/docs/product/positioning.md +86 -86
  135. package/docs/quickstart-existing-project.md +107 -107
  136. package/docs/quickstart.md +183 -183
  137. package/docs/release-maintenance.md +79 -79
  138. package/docs/reputation.md +52 -52
  139. package/docs/review.md +45 -45
  140. package/docs/security.md +212 -212
  141. package/docs/server-operations.md +118 -118
  142. package/docs/storage.md +106 -106
  143. package/package.json +86 -66
  144. package/docs/concepts/event-log-store-critique-A.md +0 -333
  145. package/docs/concepts/event-log-store-critique-B.md +0 -353
  146. package/docs/concepts/event-log-store-phase0-measurements.md +0 -58
  147. package/docs/concepts/event-log-store-proposal-A.md +0 -365
  148. package/docs/concepts/event-log-store-proposal-B.md +0 -404
  149. package/docs/concepts/identity-model-proposal.md +0 -371
@@ -0,0 +1,198 @@
1
+ # Code Map
2
+
3
+ Code Map is a per-project structural index of your JavaScript / TypeScript /
4
+ TSX codebase. It parses each supported file with Tree-sitter and records the
5
+ symbols it defines (functions, classes, types, interfaces, React components and
6
+ hooks), what it imports and exports, and how files relate — then answers fast
7
+ "what should I read before I edit this?" questions for both human operators and
8
+ coding agents.
9
+
10
+ Code Map is a **discovery aid**, not a build artifact. It never changes your
11
+ code, never blocks `bclaw_work`, and degrades gracefully: if the index is
12
+ missing or stale, every command says so via a freshness badge instead of
13
+ returning silently wrong answers.
14
+
15
+ The index lives under `.brainclaw/code-map/` (one JSONL shard per file, plus
16
+ named symbol/import indexes and a manifest). It is safe to delete; a refresh
17
+ rebuilds it.
18
+
19
+ ## When to use it
20
+
21
+ - **Before editing** an unfamiliar area: `code-map brief <symbol-or-path>` (or
22
+ `bclaw_code_brief`) returns a ranked list of files to read plus related
23
+ brainclaw memory.
24
+ - **To locate** a function/class/component/hook by name without grepping:
25
+ `code-map find <query>` (or `bclaw_code_find`).
26
+ - **To check coverage / staleness**: `code-map status` (or `bclaw_code_status`).
27
+ - **After pulling changes or doing work**: `code-map refresh` to bring the index
28
+ back to `fresh`.
29
+
30
+ ## CLI
31
+
32
+ All commands are available as `brainclaw code-map …` or `bclaw code-map …`, and
33
+ honor the global options (`--cwd`, `--verbose`, `--debug`). Every command also
34
+ accepts `--json` for machine-readable output, and prints a `Freshness:` line.
35
+
36
+ ### `brainclaw code-map status`
37
+
38
+ Read-only. Reports whether the store exists, the freshness badge, and index
39
+ stats (files indexed, nodes, edges). Never refreshes.
40
+
41
+ ```bash
42
+ brainclaw code-map status
43
+ ```
44
+
45
+ ```
46
+ Code Map status
47
+ Store: present
48
+ Freshness: fresh
49
+ Files: 142
50
+ Nodes: 1873
51
+ Edges: 2410
52
+ ```
53
+
54
+ ### `brainclaw code-map refresh [--changed | --all]`
55
+
56
+ Rebuilds the index behind a per-project lock. Defaults to `--changed`.
57
+
58
+ | Flag | Behavior |
59
+ |---|---|
60
+ | `--changed` (default) | Re-parses files whose **content** changed (git status + file-hash diff) **and** any shard whose stored extractor-config / grammar / engine hashes no longer match the current ones (i.e. `stale_extractor` / `stale_grammar`). A config or grammar bump is therefore healed by this cheap path — not only by `--all`. Compaction is limited to git-proven deletes. |
61
+ | `--all` | Enumerates every supported file, re-parses, and performs full orphan compaction (drops shards whose file is gone or now ignored). |
62
+
63
+ If a live writer already holds the project lock, `refresh` **fails fast** with a
64
+ clear status rather than blocking — it never stalls `bclaw_work`.
65
+
66
+ ```bash
67
+ brainclaw code-map refresh # changed (cheap, default)
68
+ brainclaw code-map refresh --all # full rebuild + compaction
69
+ ```
70
+
71
+ ### `brainclaw code-map find <query>`
72
+
73
+ Read-only. Searches the symbol index for a name/token and returns ranked matches
74
+ with path and score. A `missing_index` badge means you should run `refresh`
75
+ first.
76
+
77
+ ```bash
78
+ brainclaw code-map find useAuth
79
+ ```
80
+
81
+ ```
82
+ Code Map find: "useAuth"
83
+ Freshness: fresh
84
+ [9.0] useAuth hook — src/hooks/useAuth.ts
85
+ ```
86
+
87
+ ### `brainclaw code-map brief <symbol-or-path>`
88
+
89
+ Read-only. Builds a reading brief for a symbol or file: a ranked
90
+ `suggested files to read` list (capped at 12) plus related brainclaw memory
91
+ (decisions / constraints / traps, capped at 5). Use it before editing.
92
+
93
+ ```bash
94
+ brainclaw code-map brief App
95
+ ```
96
+
97
+ ## MCP tools
98
+
99
+ Capable agents should prefer the MCP surface. The four tools mirror the CLI and
100
+ all return a `freshness_badge`:
101
+
102
+ | Tool | Kind | Purpose |
103
+ |---|---|---|
104
+ | `bclaw_code_status` | read | Store presence, freshness badge, index stats. Never refreshes. |
105
+ | `bclaw_code_find` | read | Ranked symbol-index search (`query`, optional `limit`). Never refreshes. |
106
+ | `bclaw_code_brief` | read | Reading brief for a symbol/path (`target`, optional `limit`, files capped at 12). Never refreshes. |
107
+ | `bclaw_code_refresh` | write | Rebuild the index. `scope` = `"changed"` (default) or `"all"`. Fails fast on a live lock. |
108
+
109
+ The read tools never trigger a parse — if `bclaw_code_status` /
110
+ `bclaw_code_find` / `bclaw_code_brief` report `missing_index` or a stale badge,
111
+ call `bclaw_code_refresh` and retry.
112
+
113
+ ## Freshness badge model
114
+
115
+ Every Code Map response carries a freshness badge so a stale index is always
116
+ visible rather than silently misleading. The status is one of:
117
+
118
+ | Status | Meaning | Fix |
119
+ |---|---|---|
120
+ | `fresh` | Index matches the working tree, the extractor config, and the parser binaries. | — |
121
+ | `stale_changed_files` | One or more indexed files have changed on disk since they were parsed. | `refresh --changed` |
122
+ | `stale_extractor` | The extractor configuration (ignore rules, size caps, supported extensions, query budget, or active language set) changed since these shards were produced. | `refresh --changed` (heals on the cheap path) |
123
+ | `stale_grammar` | A Tree-sitter grammar (or the engine glue) binary changed since these shards were produced. | `refresh --changed` (heals on the cheap path) |
124
+ | `partial` | The index could not be fully read/built this pass (e.g. the project lock was held by a live writer). | retry |
125
+ | `missing_index` | No index exists yet for this project. | `refresh --all` |
126
+
127
+ Staleness reasons are kept separate on purpose: a content change
128
+ (`stale_changed_files`) is independent from a config change (`stale_extractor`)
129
+ which is independent from a parser-binary change (`stale_grammar`). The badge
130
+ surfaces the dominant reason; `--json` output and the manifest carry the per-file
131
+ counts.
132
+
133
+ ## Lifecycle — pull-based, no daemon
134
+
135
+ Code Map never runs in the background and never auto-reindexes. The model is lazy
136
+ reconciliation at the read path:
137
+
138
+ 1. You edit or pull code — the index does not change.
139
+ 2. The next `status` / `find` / `brief` recomputes a freshness badge (git status +
140
+ file-hash diff vs the stored shards), so a stale index is always *visible*,
141
+ never silently wrong.
142
+ 3. `refresh --changed` re-parses only the changed files (incremental); `--all` does
143
+ a full rebuild + orphan compaction.
144
+ 4. `bclaw_work` nudges a refresh when the badge is `missing_index` or stale, so an
145
+ agent knows to reconcile before trusting the map.
146
+
147
+ It never blocks `bclaw_work` (a held lock fails fast), so the worst case of a stale
148
+ index is a one-line "run refresh" hint — not a wrong answer.
149
+
150
+ ## Monorepos and nested projects
151
+
152
+ Code Map is **per project**: the index lives at `<project>/.brainclaw/code/`, and
153
+ `refresh` indexes the source tree under the project root it runs in — descending
154
+ into subdirectories but skipping `node_modules`, `dist`, `.git`, `.brainclaw`,
155
+ `vendor`, `target`, … at any depth.
156
+
157
+ There is no nested-project *boundary*, so the scope follows **where you run it**:
158
+
159
+ | You run refresh / find / brief … | … against |
160
+ |---|---|
161
+ | at the monorepo root | one index covering the whole tree (every child project's source) |
162
+ | inside a child project (e.g. `apps/api`) | that child's own index, at `apps/api/.brainclaw/code/` |
163
+
164
+ When an agent works inside a child project, brainclaw's project resolution routes
165
+ Code Map to **that child** — the same per-project scoping that powers `bclaw_work`
166
+ / `bclaw_switch` — so each project gets its own clean map without manual `--cwd`
167
+ juggling. A submodule that is itself an application (under e.g. `apps/`) is indexed
168
+ like any other directory.
169
+
170
+ **Not yet supported** (roadmap):
171
+
172
+ - A single aggregated view that keeps **separate per-child indexes and federates
173
+ them** at the root (a query spanning services without double-indexing).
174
+ - **Cross-service edges** — e.g. linking an API call to the route that defines it in
175
+ another service. Code Map indexes language *symbols* and *module imports*, not
176
+ framework routes or runtime HTTP calls, so it does not (today) map "service A calls
177
+ endpoint X defined in service B".
178
+
179
+ ## WASM bundling note
180
+
181
+ The parser is [Tree-sitter](https://tree-sitter.github.io/) compiled to
182
+ WebAssembly. The engine glue (`web-tree-sitter`) and the prebuilt grammar `.wasm`
183
+ files (TypeScript / TSX / JavaScript) are **bundled into the package** during the
184
+ build (`scripts/copy-code-map-wasm.mjs` copies them into `dist/wasm/` and vendors
185
+ the engine glue into `dist/vendor/web-tree-sitter/`).
186
+
187
+ Two properties matter for packaging:
188
+
189
+ 1. **Lazy load on first parse only.** The WASM engine is loaded via a dynamic
190
+ import the first time a file is actually parsed. Nothing in the CLI / MCP
191
+ module-load graph statically imports the parser, so `--version`,
192
+ `code-map status`, `code-map find`, and `code-map brief` all work even if the
193
+ engine is absent — only `refresh` needs it.
194
+ 2. **Self-contained at runtime.** Because the glue and grammars are vendored into
195
+ `dist/`, parsing works from the published package without the build-time
196
+ dev dependencies. WASM assets are resolved relative to the module
197
+ (`import.meta.url`), never the current working directory, so the loader is
198
+ safe inside git worktrees.
@@ -1,52 +1,52 @@
1
- # Coordination
2
-
3
- brainclaw is not only a memory layer.
4
- It is also a coordination layer.
5
-
6
- That distinction matters.
7
-
8
- ## Why coordination is needed
9
-
10
- Multiple humans and coding agents working in the same repo can easily:
11
-
12
- - duplicate work
13
- - miss handoffs
14
- - overwrite each other
15
- - diverge on plan status
16
- - act on stale assumptions
17
-
18
- Traditional instruction files do not solve this well because they describe how to behave, but not what is currently happening.
19
-
20
- ## What brainclaw adds
21
-
22
- brainclaw introduces shared operational state for a workspace, including:
23
-
24
- - plans
25
- - task status
26
- - file claims
27
- - handoffs
28
- - runtime notes
29
- - board views
30
-
31
- ## The key idea
32
-
33
- A workspace should expose not only what the project knows, but also what is currently being done.
34
-
35
- That includes:
36
-
37
- - what matters
38
- - what is active
39
- - who is working where
40
- - what is blocked
41
- - what needs review or handoff
42
-
43
- ## Why this is different from another agent
44
-
45
- brainclaw does not try to become the agent that does everything.
46
- It helps many tools collaborate against the same workspace state.
47
-
48
- ## Related pages
49
-
50
- - [plans-and-claims.md](plans-and-claims.md)
51
- - [runtime-notes.md](runtime-notes.md)
52
- - [../integrations/overview.md](../integrations/overview.md)
1
+ # Coordination
2
+
3
+ brainclaw is not only a memory layer.
4
+ It is also a coordination layer.
5
+
6
+ That distinction matters.
7
+
8
+ ## Why coordination is needed
9
+
10
+ Multiple humans and coding agents working in the same repo can easily:
11
+
12
+ - duplicate work
13
+ - miss handoffs
14
+ - overwrite each other
15
+ - diverge on plan status
16
+ - act on stale assumptions
17
+
18
+ Traditional instruction files do not solve this well because they describe how to behave, but not what is currently happening.
19
+
20
+ ## What brainclaw adds
21
+
22
+ brainclaw introduces shared operational state for a workspace, including:
23
+
24
+ - plans
25
+ - task status
26
+ - file claims
27
+ - handoffs
28
+ - runtime notes
29
+ - board views
30
+
31
+ ## The key idea
32
+
33
+ A workspace should expose not only what the project knows, but also what is currently being done.
34
+
35
+ That includes:
36
+
37
+ - what matters
38
+ - what is active
39
+ - who is working where
40
+ - what is blocked
41
+ - what needs review or handoff
42
+
43
+ ## Why this is different from another agent
44
+
45
+ brainclaw does not try to become the agent that does everything.
46
+ It helps many tools collaborate against the same workspace state.
47
+
48
+ ## Related pages
49
+
50
+ - [plans-and-claims.md](plans-and-claims.md)
51
+ - [runtime-notes.md](runtime-notes.md)
52
+ - [../integrations/overview.md](../integrations/overview.md)
@@ -1,129 +1,129 @@
1
- # Coordinator runbook
2
-
3
- Operational procedures for running multi-agent dispatches, distilled from the
4
- 2026-06-10 coordination session (pln#554). Audience: the coordinator — human or
5
- agent — who dispatched workers and now has to triage what came back (or didn't).
6
-
7
- Rule zero across everything below: **evidence before verdict**. Administrative
8
- status (assignment/run records) is the WEAKEST signal; worker-written results
9
- and git state are the strongest. Acting on administrative status alone expired
10
- live workers three times in one night (can_948acfd6).
11
-
12
- ## 1. Baseline triage — is it actually a regression?
13
-
14
- Before calling anything a regression, run the exact same check on the
15
- pre-change ref. Twice in the 2026-06-10 session a "sprint-1 regression" turned
16
- out to be a bug that had always existed — manual workflows had simply masked it
17
- (see also trap: bisect state before code).
18
-
19
- Procedure:
20
-
21
- 1. Reproduce the failure on the current ref. Capture the command verbatim.
22
- 2. `git stash` nothing, delete nothing — check out the pre-change ref in a
23
- SEPARATE worktree (`git worktree add ../baseline <ref>`).
24
- 3. Run the same command there.
25
- - Fails on the baseline too → not a regression. Re-scope the bug, exonerate
26
- the change, and continue the dispatch.
27
- - Passes on the baseline → real regression; only now is bisecting the diff
28
- worth the time.
29
- 4. Before bisecting code at all, read the historical ENTITY state first
30
- (assignment / event / completed_at records): the May 2026 codex
31
- `run_completed` "regression" was state drift, not code.
32
-
33
- ## 2. Dead-worker decision tree
34
-
35
- A worker looks dead (stale heartbeat, exited process, expired assignment).
36
- Collect worktree evidence BEFORE any kill / reroute / re-dispatch — recovery is
37
- cheap, a wrongly killed worker is not.
38
-
39
- ```
40
- worker presumed dead
41
-
42
- ├─ 1. LANE-RESULT.json at the worktree root?
43
- │ yes → it FINISHED. `brainclaw harvest <asgn> [--integrate]`. Done.
44
-
45
- ├─ 2. git evidence (shared helper: commits_ahead + dirty_tracked,
46
- │ surfaced by dispatch-status / dispatch watch):
47
- │ commits ahead + CLEAN tracked tree
48
- │ → worker delivered, only exit formalities missing.
49
- │ Harvest/merge it. NEVER kill-and-reroute a delivered lane.
50
-
51
- ├─ 3. dirty tracked files? → work in flight. Check liveness before declaring death:
52
- │ ├─ fs mtime fresh (logs/worktree written < ~5 min)? → ALIVE, leave it.
53
- │ ├─ real agent child process under the wrapper pid?
54
- │ │ (wrapper alive + child gone = abrupt death; orphaned grandchildren
55
- │ │ hold the pipes open so the wrapper never emits a sentinel)
56
- │ └─ both dead + fs stale → recover, do not re-dispatch blind:
57
- │ `brainclaw harvest <asgn> --orphaned`
58
- │ (typecheck if possible → commit on-behalf with the standard
59
- │ marker → lifecycle → release claim → run targeted tests + merge)
60
-
61
- └─ 4. clean tree, no commits ahead, no result → nothing to recover.
62
- Now (and only now) reroute / re-dispatch.
63
- ```
64
-
65
- Hard rules:
66
-
67
- - Never delete or reset a worktree during triage — the diff on disk IS the
68
- recovery (twice on 2026-06-10: 42 and 41 files recovered, zero loss).
69
- - Never kill processes by name; source the pid from agent_run.pid and
70
- cross-check launched_at (the operator's IDE runs the same binaries).
71
- - A failed observation is not evidence: "could not probe the child process"
72
- must never be read as "the child is dead".
73
-
74
- ## 3. Post-dispatch verification reflex
75
-
76
- Delivery is not execution. `delivered_and_started` means the message landed and
77
- a process spawned — not that the worker reached its work loop.
78
-
79
- After every dispatch:
80
-
81
- 1. `bclaw_dispatch_status(target_id: <asgn|clm|run>)` — one call resolves the
82
- assignment, claim, run, heartbeat, logs, lane-result, and git evidence into
83
- a single health verdict + next action.
84
- 2. Or query directly: `bclaw_find(entity: "agent_run", message_id: <msg>)` —
85
- no run record means the spawn never produced a process.
86
- 3. Expect the step-0 heartbeat (`.brainclaw-heartbeat-<asgn>` at the worktree
87
- root) within the first minutes. Missing heartbeat + no fs activity = the
88
- worker never reached its loop; check the captured stderr for boot
89
- signatures (model/config mismatches are diagnosed by dispatch-status).
90
-
91
- Known gap: `intent=ideate` dispatches are inbox-only (can_29f1e1ac) — there is
92
- no agent_run to verify; track those by reply message, not by run records.
93
-
94
- ## 4. `brainclaw dispatch watch` — monitor contract
95
-
96
- Blocking watch over one dispatch; encodes the decision tree above as a poller.
97
-
98
- ```
99
- brainclaw dispatch watch <asgn_|clm_|run_> [--interval 60] [--timeout 90] [--base master] [--json]
100
- ```
101
-
102
- Exit codes (script on these, not on the log text):
103
-
104
- | code | state | meaning / next action |
105
- |------|----------------------|---------------------------------------------------------|
106
- | 0 | done | lane-result, run completed, or committed-clean → harvest |
107
- | 2 | timeout | worker still running at --timeout → re-run or inspect |
108
- | 3 | failed | lane-result/run reported failure → read stderr, fix |
109
- | 4 | worker-process-gone | dead with uncommitted work → `harvest --orphaned` |
110
- | 5 | unresolved | target id did not resolve to anything |
111
-
112
- Evidence priority inside the watch (strongest first): worker-written results >
113
- git evidence > process evidence > administrative status. Fresh filesystem
114
- activity vetoes process-gone verdicts (a stale tracked pid after a manual
115
- respawn must not kill a worker that is visibly writing).
116
-
117
- ## Cross-references
118
-
119
- - can_948acfd6 — assignment expired while the worker was delivering; git
120
- evidence outranks administrative status.
121
- - can_d622e024 — claude -p "delivered-but-end-stalled": committed-clean is done.
122
- - can_9458576e — wrapper-alive/child-dead death mode (orphaned pipe holders).
123
- - can_29f1e1ac — intent=ideate is inbox-only; no run record to verify.
124
- - cnd_asgn_7336aa79_heartbeat_sandbox / can_asgn_b0169fd8_heartbeat — sandboxes
125
- refuse absolute heartbeat paths; briefs point sandboxed workers at a
126
- worktree-relative path.
127
- - trap: agent shell env contaminates tests — strip BRAINCLAW_CWD/_AGENT before
128
- running suites from an agent shell.
129
- - docs/concepts/dispatch-lifecycle.md — full entity/FSM model behind all of this.
1
+ # Coordinator runbook
2
+
3
+ Operational procedures for running multi-agent dispatches, distilled from the
4
+ 2026-06-10 coordination session (pln#554). Audience: the coordinator — human or
5
+ agent — who dispatched workers and now has to triage what came back (or didn't).
6
+
7
+ Rule zero across everything below: **evidence before verdict**. Administrative
8
+ status (assignment/run records) is the WEAKEST signal; worker-written results
9
+ and git state are the strongest. Acting on administrative status alone expired
10
+ live workers three times in one night (can_948acfd6).
11
+
12
+ ## 1. Baseline triage — is it actually a regression?
13
+
14
+ Before calling anything a regression, run the exact same check on the
15
+ pre-change ref. Twice in the 2026-06-10 session a "sprint-1 regression" turned
16
+ out to be a bug that had always existed — manual workflows had simply masked it
17
+ (see also trap: bisect state before code).
18
+
19
+ Procedure:
20
+
21
+ 1. Reproduce the failure on the current ref. Capture the command verbatim.
22
+ 2. `git stash` nothing, delete nothing — check out the pre-change ref in a
23
+ SEPARATE worktree (`git worktree add ../baseline <ref>`).
24
+ 3. Run the same command there.
25
+ - Fails on the baseline too → not a regression. Re-scope the bug, exonerate
26
+ the change, and continue the dispatch.
27
+ - Passes on the baseline → real regression; only now is bisecting the diff
28
+ worth the time.
29
+ 4. Before bisecting code at all, read the historical ENTITY state first
30
+ (assignment / event / completed_at records): the May 2026 codex
31
+ `run_completed` "regression" was state drift, not code.
32
+
33
+ ## 2. Dead-worker decision tree
34
+
35
+ A worker looks dead (stale heartbeat, exited process, expired assignment).
36
+ Collect worktree evidence BEFORE any kill / reroute / re-dispatch — recovery is
37
+ cheap, a wrongly killed worker is not.
38
+
39
+ ```
40
+ worker presumed dead
41
+
42
+ ├─ 1. LANE-RESULT.json at the worktree root?
43
+ │ yes → it FINISHED. `brainclaw harvest <asgn> [--integrate]`. Done.
44
+
45
+ ├─ 2. git evidence (shared helper: commits_ahead + dirty_tracked,
46
+ │ surfaced by dispatch-status / dispatch watch):
47
+ │ commits ahead + CLEAN tracked tree
48
+ │ → worker delivered, only exit formalities missing.
49
+ │ Harvest/merge it. NEVER kill-and-reroute a delivered lane.
50
+
51
+ ├─ 3. dirty tracked files? → work in flight. Check liveness before declaring death:
52
+ │ ├─ fs mtime fresh (logs/worktree written < ~5 min)? → ALIVE, leave it.
53
+ │ ├─ real agent child process under the wrapper pid?
54
+ │ │ (wrapper alive + child gone = abrupt death; orphaned grandchildren
55
+ │ │ hold the pipes open so the wrapper never emits a sentinel)
56
+ │ └─ both dead + fs stale → recover, do not re-dispatch blind:
57
+ │ `brainclaw harvest <asgn> --orphaned`
58
+ │ (typecheck if possible → commit on-behalf with the standard
59
+ │ marker → lifecycle → release claim → run targeted tests + merge)
60
+
61
+ └─ 4. clean tree, no commits ahead, no result → nothing to recover.
62
+ Now (and only now) reroute / re-dispatch.
63
+ ```
64
+
65
+ Hard rules:
66
+
67
+ - Never delete or reset a worktree during triage — the diff on disk IS the
68
+ recovery (twice on 2026-06-10: 42 and 41 files recovered, zero loss).
69
+ - Never kill processes by name; source the pid from agent_run.pid and
70
+ cross-check launched_at (the operator's IDE runs the same binaries).
71
+ - A failed observation is not evidence: "could not probe the child process"
72
+ must never be read as "the child is dead".
73
+
74
+ ## 3. Post-dispatch verification reflex
75
+
76
+ Delivery is not execution. `delivered_and_started` means the message landed and
77
+ a process spawned — not that the worker reached its work loop.
78
+
79
+ After every dispatch:
80
+
81
+ 1. `bclaw_dispatch_status(target_id: <asgn|clm|run>)` — one call resolves the
82
+ assignment, claim, run, heartbeat, logs, lane-result, and git evidence into
83
+ a single health verdict + next action.
84
+ 2. Or query directly: `bclaw_find(entity: "agent_run", message_id: <msg>)` —
85
+ no run record means the spawn never produced a process.
86
+ 3. Expect the step-0 heartbeat (`.brainclaw-heartbeat-<asgn>` at the worktree
87
+ root) within the first minutes. Missing heartbeat + no fs activity = the
88
+ worker never reached its loop; check the captured stderr for boot
89
+ signatures (model/config mismatches are diagnosed by dispatch-status).
90
+
91
+ Known gap: `intent=ideate` dispatches are inbox-only (can_29f1e1ac) — there is
92
+ no agent_run to verify; track those by reply message, not by run records.
93
+
94
+ ## 4. `brainclaw dispatch watch` — monitor contract
95
+
96
+ Blocking watch over one dispatch; encodes the decision tree above as a poller.
97
+
98
+ ```
99
+ brainclaw dispatch watch <asgn_|clm_|run_> [--interval 60] [--timeout 90] [--base master] [--json]
100
+ ```
101
+
102
+ Exit codes (script on these, not on the log text):
103
+
104
+ | code | state | meaning / next action |
105
+ |------|----------------------|---------------------------------------------------------|
106
+ | 0 | done | lane-result, run completed, or committed-clean → harvest |
107
+ | 2 | timeout | worker still running at --timeout → re-run or inspect |
108
+ | 3 | failed | lane-result/run reported failure → read stderr, fix |
109
+ | 4 | worker-process-gone | dead with uncommitted work → `harvest --orphaned` |
110
+ | 5 | unresolved | target id did not resolve to anything |
111
+
112
+ Evidence priority inside the watch (strongest first): worker-written results >
113
+ git evidence > process evidence > administrative status. Fresh filesystem
114
+ activity vetoes process-gone verdicts (a stale tracked pid after a manual
115
+ respawn must not kill a worker that is visibly writing).
116
+
117
+ ## Cross-references
118
+
119
+ - can_948acfd6 — assignment expired while the worker was delivering; git
120
+ evidence outranks administrative status.
121
+ - can_d622e024 — claude -p "delivered-but-end-stalled": committed-clean is done.
122
+ - can_9458576e — wrapper-alive/child-dead death mode (orphaned pipe holders).
123
+ - can_29f1e1ac — intent=ideate is inbox-only; no run record to verify.
124
+ - cnd_asgn_7336aa79_heartbeat_sandbox / can_asgn_b0169fd8_heartbeat — sandboxes
125
+ refuse absolute heartbeat paths; briefs point sandboxed workers at a
126
+ worktree-relative path.
127
+ - trap: agent shell env contaminates tests — strip BRAINCLAW_CWD/_AGENT before
128
+ running suites from an agent shell.
129
+ - docs/concepts/dispatch-lifecycle.md — full entity/FSM model behind all of this.