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
@@ -1,6 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { loadActiveProject, saveActiveProject, clearActiveProject } from '../core/active-project.js';
3
- import { buildOperationalIdentity, loadCurrentSession, saveCurrentSession } from '../core/identity.js';
3
+ import { buildOperationalIdentity, loadCurrentSession, loadSessionById, resolveCurrentSessionId, saveCurrentSession } from '../core/identity.js';
4
4
  import { memoryExists } from '../core/io.js';
5
5
  import { resolveProjectRef } from '../core/store-resolution.js';
6
6
  import { resolveCrossProjectLinks, resolveProjectCwd } from '../core/cross-project.js';
@@ -44,10 +44,28 @@ export function switchProject(projectRef, options = {}) {
44
44
  catch { /* name is optional */ }
45
45
  const now = new Date().toISOString();
46
46
  const sessionOnly = options.sessionOnly ?? true;
47
- let session = loadCurrentSession(cwd);
47
+ let session = options.sessionId ? loadSessionById(options.sessionId, cwd) : loadCurrentSession(cwd);
48
48
  if (!session && sessionOnly) {
49
- buildOperationalIdentity(undefined, cwd, { persistImplicitSession: true });
50
- session = loadCurrentSession(cwd);
49
+ if (options.sessionId) {
50
+ const identity = buildOperationalIdentity(undefined, cwd, {
51
+ sessionId: options.sessionId,
52
+ persistImplicitSession: false,
53
+ });
54
+ saveCurrentSession({
55
+ session_id: options.sessionId,
56
+ started_at: now,
57
+ last_seen_at: now,
58
+ agent: identity.agent,
59
+ agent_id: identity.agent_id,
60
+ host_id: identity.host_id,
61
+ user: process.env.USER || process.env.USERNAME || undefined,
62
+ pid: process.pid,
63
+ }, cwd);
64
+ }
65
+ else {
66
+ buildOperationalIdentity(undefined, cwd, { persistImplicitSession: true });
67
+ }
68
+ session = options.sessionId ? loadSessionById(options.sessionId, cwd) : loadCurrentSession(cwd);
51
69
  }
52
70
  if (session && sessionOnly) {
53
71
  saveCurrentSession({
@@ -78,11 +96,14 @@ export function switchProject(projectRef, options = {}) {
78
96
  * List available projects in the workspace.
79
97
  */
80
98
  export function listAvailableProjects(cwd) {
99
+ return listAvailableProjectsForSession(cwd);
100
+ }
101
+ export function listAvailableProjectsForSession(cwd, sessionId) {
81
102
  const wsRoot = findOutermostWorkspaceRoot(cwd ?? process.cwd());
82
103
  if (!wsRoot) {
83
104
  throw new Error('No brainclaw workspace found.');
84
105
  }
85
- const sessionActive = loadCurrentSession(cwd)?.active_project;
106
+ const sessionActive = (sessionId ? loadSessionById(sessionId, cwd) : loadCurrentSession(cwd))?.active_project;
86
107
  const globalActive = loadActiveProject(wsRoot);
87
108
  const active = sessionActive ?? globalActive;
88
109
  const activeSource = sessionActive ? 'session' : globalActive ? 'global' : 'none';
@@ -139,59 +160,70 @@ export function runSwitch(projectRef, options = {}) {
139
160
  }
140
161
  // --list: show available projects
141
162
  if (options.list) {
142
- listProjects(wsRoot, options.json ?? false);
163
+ listProjects(wsRoot, cwd, options.json ?? false);
143
164
  return;
144
165
  }
145
- // --clear: remove active project
166
+ // --clear: remove active project. Session-scoped by default (F3) — clearing
167
+ // the SHARED global pointer is an opt-in (--global) so one agent's clear no
168
+ // longer wipes every other agent's resolution.
146
169
  if (options.clear) {
147
- const session = loadCurrentSession(cwd);
148
- if (session?.active_project) {
149
- const { active_project: _removed, ...rest } = session;
150
- saveCurrentSession(rest, cwd);
170
+ let scope;
171
+ if (options.global) {
172
+ clearActiveProject(wsRoot);
173
+ scope = 'global';
174
+ }
175
+ else {
176
+ const session = loadCurrentSession(cwd);
177
+ if (session?.active_project) {
178
+ const { active_project: _removed, ...rest } = session;
179
+ saveCurrentSession(rest, cwd);
180
+ }
181
+ scope = 'session';
151
182
  }
152
- clearActiveProject(wsRoot);
153
183
  if (options.json) {
154
- console.log(JSON.stringify({ cleared: true }));
184
+ console.log(JSON.stringify({ cleared: true, scope }));
155
185
  }
156
186
  else {
157
- console.log('✔ Active project cleared. Commands will use current directory.');
187
+ const hint = scope === 'session' ? ' (session-scoped)' : ' (global)';
188
+ console.log(`✔ Active project cleared${hint}. Commands will use current directory.`);
158
189
  }
159
190
  return;
160
191
  }
161
192
  // No argument: show current active project
162
193
  if (!projectRef) {
163
- showCurrent(wsRoot, options.json ?? false);
194
+ showCurrent(wsRoot, cwd, options.json ?? false);
164
195
  return;
165
196
  }
166
197
  // Switch to project
167
- const resolved = resolveProjectRef(projectRef, cwd);
168
- if (!resolved) {
169
- console.error(`Error: cannot resolve project "${projectRef}".`);
170
- console.error('Use `brainclaw switch --list` to see available projects.');
171
- process.exit(1);
172
- }
173
- let projectName;
174
- try {
175
- const config = loadConfig(resolved);
176
- projectName = config.project_name;
177
- }
178
- catch {
179
- // name is optional
180
- }
181
198
  const now = new Date().toISOString();
182
- const session = loadCurrentSession(cwd);
183
- const scopedToSession = options.session ?? !!session;
184
199
  let scope;
185
- if (scopedToSession && session) {
186
- // Write to session state — only this agent sees this switch
187
- saveCurrentSession({
188
- ...session,
189
- active_project: { path: resolved, name: projectName, switched_at: now },
190
- }, cwd);
191
- scope = 'session';
192
- }
193
- else {
194
- // Fall back to global active-project.json
200
+ let switchedPath;
201
+ let switchedName;
202
+ if (options.global) {
203
+ // Opt-in, audited: set the SHARED workspace default for every agent on the
204
+ // host. Bypasses the session entirely (an operator setting a default).
205
+ // Resolve store-chain children AND cross-project links (mirror switchProject)
206
+ // so `switch <linked> --global` matches what --list shows and what the
207
+ // session path can target (Codex final review F3-F5 finding).
208
+ let resolved = resolveProjectRef(projectRef, cwd);
209
+ if (!resolved) {
210
+ try {
211
+ const linkResolved = resolveProjectCwd(projectRef, cwd);
212
+ if (linkResolved !== cwd)
213
+ resolved = linkResolved;
214
+ }
215
+ catch { /* falls through to the error below */ }
216
+ }
217
+ if (!resolved) {
218
+ console.error(`Error: cannot resolve project "${projectRef}".`);
219
+ console.error('Use `brainclaw switch --list` to see available projects.');
220
+ process.exit(1);
221
+ }
222
+ let projectName;
223
+ try {
224
+ projectName = loadConfig(resolved).project_name;
225
+ }
226
+ catch { /* name is optional */ }
195
227
  saveActiveProject(wsRoot, {
196
228
  path: resolved,
197
229
  name: projectName,
@@ -199,21 +231,47 @@ export function runSwitch(projectRef, options = {}) {
199
231
  switched_by: process.env.BRAINCLAW_AGENT_NAME ?? process.env.USER ?? 'unknown',
200
232
  });
201
233
  scope = 'global';
234
+ switchedPath = resolved;
235
+ switchedName = projectName;
236
+ }
237
+ else {
238
+ // F3 default: session-scoped + isolated. Delegate to switchProject — the
239
+ // safe model that auto-creates the session, honours an explicit
240
+ // BRAINCLAW_SESSION_ID (resolveCurrentSessionId returns it WITHOUT
241
+ // persisting, so the session file must be created), resolves cross-project
242
+ // links, and never touches the shared global pointer.
243
+ try {
244
+ const explicitSessionId = resolveCurrentSessionId(process.env, cwd) || undefined;
245
+ const result = switchProject(projectRef, { cwd, sessionOnly: true, sessionId: explicitSessionId });
246
+ scope = 'session';
247
+ switchedPath = result.path;
248
+ switchedName = result.name;
249
+ }
250
+ catch (err) {
251
+ console.error(`Error: ${err.message}`);
252
+ console.error('Use `brainclaw switch --list` to see available projects.');
253
+ process.exit(1);
254
+ }
202
255
  }
203
256
  if (options.json) {
204
- console.log(JSON.stringify({ switched: true, path: resolved, name: projectName, scope }));
257
+ console.log(JSON.stringify({ switched: true, path: switchedPath, name: switchedName, scope }));
205
258
  }
206
259
  else {
207
- const rel = path.relative(wsRoot, resolved) || '.';
208
- const scopeHint = scope === 'session' ? ' (session-scoped)' : '';
209
- console.log(`✔ Switched to ${projectName ? `"${projectName}" (${rel})` : rel}${scopeHint}`);
260
+ const rel = path.relative(wsRoot, switchedPath) || '.';
261
+ const scopeHint = scope === 'session' ? ' (session-scoped)' : ' (global — all agents)';
262
+ console.log(`✔ Switched to ${switchedName ? `"${switchedName}" (${rel})` : rel}${scopeHint}`);
210
263
  }
211
264
  }
212
- function showCurrent(wsRoot, json) {
213
- const active = loadActiveProject(wsRoot);
265
+ function showCurrent(wsRoot, cwd, json) {
266
+ // F5: prefer the session's own active project so an agent sees its own
267
+ // session-scoped switch, not just the shared global pointer.
268
+ const sessionActive = loadCurrentSession(cwd)?.active_project;
269
+ const globalActive = loadActiveProject(wsRoot);
270
+ const active = sessionActive ?? globalActive;
271
+ const source = sessionActive ? 'session' : globalActive ? 'global' : 'none';
214
272
  if (!active) {
215
273
  if (json) {
216
- console.log(JSON.stringify({ active: false }));
274
+ console.log(JSON.stringify({ active: false, scope: 'none' }));
217
275
  }
218
276
  else {
219
277
  console.log('No active project. Commands use current directory.');
@@ -222,67 +280,41 @@ function showCurrent(wsRoot, json) {
222
280
  return;
223
281
  }
224
282
  const rel = path.relative(wsRoot, active.path) || '.';
283
+ const switchedBy = 'switched_by' in active ? active.switched_by : undefined;
225
284
  if (json) {
226
- console.log(JSON.stringify({ active: true, ...active, relative_path: rel }));
285
+ console.log(JSON.stringify({ active: true, ...active, relative_path: rel, scope: source }));
227
286
  }
228
287
  else {
229
- console.log(`Active project: ${active.name ? `"${active.name}" (${rel})` : rel}`);
288
+ const scopeHint = source === 'session' ? ' (session-scoped)' : ' (global — all agents)';
289
+ console.log(`Active project: ${active.name ? `"${active.name}" (${rel})` : rel}${scopeHint}`);
230
290
  console.log(` switched at: ${active.switched_at}`);
231
- if (active.switched_by)
232
- console.log(` switched by: ${active.switched_by}`);
291
+ if (switchedBy)
292
+ console.log(` switched by: ${switchedBy}`);
233
293
  }
234
294
  }
235
- function listProjects(wsRoot, json) {
236
- const active = loadActiveProject(wsRoot);
237
- const projects = [];
238
- // Add workspace root itself
239
- if (memoryExists(wsRoot)) {
240
- try {
241
- const config = loadConfig(wsRoot);
242
- projects.push({
243
- name: config.project_name,
244
- path: wsRoot,
245
- relative_path: '.',
246
- active: active?.path === wsRoot,
247
- });
248
- }
249
- catch {
250
- projects.push({
251
- path: wsRoot,
252
- relative_path: '.',
253
- active: active?.path === wsRoot,
254
- });
255
- }
256
- }
257
- // Discover child projects (depth 7 covers deep workspace layouts like /srv/dev/repos/global/applications/*/...)
258
- const children = scanNestedBrainclawProjects(wsRoot, 7);
259
- for (const child of children) {
260
- const childPath = path.resolve(child.path);
261
- if (childPath === wsRoot)
262
- continue;
263
- const rel = path.relative(wsRoot, childPath) || '.';
264
- projects.push({
265
- name: child.project_name,
266
- path: childPath,
267
- relative_path: rel,
268
- active: active?.path === childPath,
269
- });
270
- }
295
+ function listProjects(wsRoot, cwd, json) {
296
+ // F5: delegate to the session-aware lister so the active marker reflects the
297
+ // agent's own session active project, falling back to the global pointer.
298
+ const result = listAvailableProjectsForSession(cwd);
271
299
  if (json) {
272
- console.log(JSON.stringify({ workspace: wsRoot, projects }, null, 2));
300
+ console.log(JSON.stringify({
301
+ workspace: result.workspace_root,
302
+ active_source: result.active_source,
303
+ projects: result.projects,
304
+ }, null, 2));
273
305
  return;
274
306
  }
275
- if (projects.length === 0) {
307
+ if (result.projects.length === 0) {
276
308
  console.log('No brainclaw projects found in this workspace.');
277
309
  return;
278
310
  }
279
- console.log(`Projects in ${wsRoot}:\n`);
280
- for (const p of projects) {
311
+ console.log(`Projects in ${result.workspace_root}:\n`);
312
+ for (const p of result.projects) {
281
313
  const marker = p.active ? '→ ' : ' ';
282
314
  const name = p.name ? `${p.name} (${p.relative_path})` : p.relative_path;
283
315
  console.log(`${marker}${name}`);
284
316
  }
285
- if (!active) {
317
+ if (result.active_source === 'none') {
286
318
  console.log('\nNo active project. Use `brainclaw switch <project>` to set one.');
287
319
  }
288
320
  }
@@ -8,7 +8,7 @@ import { generateAgentReleaseNotes } from './release-notes.js';
8
8
  export function runVersion(options = {}) {
9
9
  const cwd = options.cwd ?? process.cwd();
10
10
  const initialized = memoryExists(cwd);
11
- let config = initialized ? loadConfig(cwd) : undefined;
11
+ const config = initialized ? loadConfig(cwd) : undefined;
12
12
  let publishedLocalRelease;
13
13
  if (options.publishLocal) {
14
14
  if (!initialized || !config) {
@@ -23,9 +23,21 @@ const AGENT_ALIASES = {
23
23
  'vibe': 'mistral-vibe',
24
24
  'hermes-agent': 'hermes',
25
25
  };
26
- /** Resolve an alias to its canonical agent name, or return the input unchanged. */
26
+ /**
27
+ * Resolve an alias to its canonical agent name (case-insensitive).
28
+ *
29
+ * Agent names are case-insensitive: every canonical profile key and every alias
30
+ * is lowercase, so we trim + lowercase the input before resolving. This is the
31
+ * single normalization point — registry, messaging, spawn-check and the
32
+ * coordinate/dispatch pre-flight all route through here, so a target like
33
+ * "Codex" or "Gemini" resolves identically to "codex" / "gemini". Without it the
34
+ * dispatch pre-flight collapsed an unresolved name into "no CLI spawn template
35
+ * (IDE-only?)" and silently dropped the reviewer (github-copilot/Gemini hit this
36
+ * passing targetAgents=["Codex"]).
37
+ */
27
38
  export function resolveAgentAlias(name) {
28
- return AGENT_ALIASES[name] ?? name;
39
+ const key = name.trim().toLowerCase();
40
+ return AGENT_ALIASES[key] ?? key;
29
41
  }
30
42
  const PROFILES = {
31
43
  // --- Code agents (interactive, IDE-driven) ---
@@ -314,7 +326,10 @@ const _customProfiles = new Map();
314
326
  * Custom profiles take precedence over DEFAULT_CAPABILITY_PROFILES on lookup.
315
327
  */
316
328
  export function registerCapabilityProfile(profile) {
317
- _customProfiles.set(profile.name, profile);
329
+ // Key by the normalized (lowercased) name so lookups through the
330
+ // case-insensitive resolveAgentAlias match regardless of the casing the
331
+ // registrant used.
332
+ _customProfiles.set(profile.name.trim().toLowerCase(), profile);
318
333
  }
319
334
  /**
320
335
  * Get the capability profile for an agent by name.
@@ -667,7 +682,7 @@ export function resolveBriefMode(agentName) {
667
682
  * pln#528 — capability matrix DERIVED from the spawn template, so it stays in
668
683
  * sync with how each agent is actually invoked (no per-profile duplication).
669
684
  *
670
- * The motivating reality (debrief LeaseUp): codex is spawned with
685
+ * The motivating reality (a cross-project field debrief): codex is spawned with
671
686
  * `--sandbox workspace-write`, which (a) does NOT wire the brainclaw MCP server
672
687
  * and (b) puts `.git` outside the sandbox root — so a sandboxed worker can
673
688
  * neither call `bclaw_*` nor `git commit`, regardless of the profile's nominal
@@ -13,46 +13,58 @@ export { resetMcpCommandCache };
13
13
  export const BRAINCLAW_SECTION_START = '<!-- brainclaw:start -->';
14
14
  export const BRAINCLAW_SECTION_END = '<!-- brainclaw:end -->';
15
15
  export function buildBrainclawSection(storageDir) {
16
- return `${BRAINCLAW_SECTION_START}
17
- ## Brainclaw — shared project memory
18
-
19
- This project uses brainclaw for shared coordination between humans and agents.
20
-
21
- ### Session start (required)
22
-
23
- 1. Run \`brainclaw context\` to load shared state (constraints, decisions, traps, plans, handoffs)
24
- 2. Check **Your open work** for active claims and in-progress plans assigned to you
25
- 3. Respect active claims from other agents — check \`brainclaw claim list\` before editing a claimed scope
26
-
27
- ### Before finishing (required)
28
-
29
- 1. Release claims you opened: \`brainclaw claim release <id>\` or \`brainclaw session-end --auto-release\`
30
- 2. Update completed plan items: \`brainclaw plan update <id> --status done\`
31
-
32
- ### Recording work
33
-
34
- \`\`\`bash
35
- brainclaw memory create decision "<text>" # record a decision
36
- brainclaw memory create constraint "<text>" # record an active constraint
37
- brainclaw memory create trap "<text>" # record a known trap
38
- brainclaw claim create "<text>" --scope <path> # claim a scope before editing
39
- brainclaw plan create "<text>" # add a shared work item
40
- \`\`\`
41
-
42
- Memory is stored in \`${storageDir}/\`. Run \`brainclaw doctor\` to verify health.
16
+ return `${BRAINCLAW_SECTION_START}
17
+ ## Brainclaw — shared project memory
18
+
19
+ This project uses brainclaw for shared coordination between humans and agents.
20
+
21
+ ### Session start (required)
22
+
23
+ 1. Run \`brainclaw context\` to load shared state (constraints, decisions, traps, plans, handoffs)
24
+ 2. Check **Your open work** for active claims and in-progress plans assigned to you
25
+ 3. Respect active claims from other agents — check \`brainclaw claim list\` before editing a claimed scope
26
+
27
+ ### Before editing unfamiliar code (Code Map)
28
+
29
+ Don't grep the repo blind. Orient with the Code Map first:
30
+
31
+ \`\`\`bash
32
+ brainclaw code-map brief <symbol-or-path> # ranked reading list + related decisions/traps (MCP: bclaw_code_brief)
33
+ brainclaw code-map find <name> # locate a symbol/class/component (MCP: bclaw_code_find)
34
+ brainclaw code-map status # freshness
35
+ brainclaw code-map refresh --all # when status is missing_index
36
+ brainclaw code-map refresh --changed # when status is stale_*
37
+ \`\`\`
38
+
39
+ ### Before finishing (required)
40
+
41
+ 1. Release claims you opened: \`brainclaw claim release <id>\` — or \`brainclaw session-end --auto-release\`
42
+ 2. Update completed plan items: \`brainclaw plan update <id> --status done\`
43
+
44
+ ### Recording work
45
+
46
+ \`\`\`bash
47
+ brainclaw memory create decision "<text>" # record a decision
48
+ brainclaw memory create constraint "<text>" # record an active constraint
49
+ brainclaw memory create trap "<text>" # record a known trap
50
+ brainclaw claim create "<text>" --scope <path> # claim a scope before editing
51
+ brainclaw plan create "<text>" # add a shared work item
52
+ \`\`\`
53
+
54
+ Memory is stored in \`${storageDir}/\`. Run \`brainclaw doctor\` to verify health.
43
55
  ${BRAINCLAW_SECTION_END}`;
44
56
  }
45
57
  export function buildHygieneSection() {
46
- return `## Brainclaw — required coordination
47
-
48
- Before starting work:
49
- 1. Run \`brainclaw context\` (or \`brainclaw context --json\`) to load shared memory
50
- 2. Run \`brainclaw claim list\` — do not edit a file claimed by another agent
51
- 3. Create a plan for significant work: \`brainclaw plan create "<description>"\`
52
- 4. Claim files you will modify: \`brainclaw claim create "<description>" --scope <path>\`
53
-
54
- Before finishing:
55
- 1. Run \`brainclaw session-end --auto-release\` — releases claims and updates plans
58
+ return `## Brainclaw — required coordination
59
+
60
+ Before starting work:
61
+ 1. Run \`brainclaw context\` (or \`brainclaw context --json\`) to load shared memory
62
+ 2. Run \`brainclaw claim list\` — do not edit a file claimed by another agent
63
+ 3. Create a plan for significant work: \`brainclaw plan create "<description>"\`
64
+ 4. Claim files you will modify: \`brainclaw claim create "<description>" --scope <path>\`
65
+
66
+ Before finishing:
67
+ 1. Run \`brainclaw session-end --auto-release\` — releases claims and updates plans
56
68
  2. Or manually: \`brainclaw claim release <id>\` and \`brainclaw plan update <id> --status done\``;
57
69
  }
58
70
  export function hasBrainclawSection(content) {
@@ -727,13 +739,13 @@ export function describeAutoConfigWrite(result) {
727
739
  return `✔ ${verb} ${result.label} at ${displayPath}`;
728
740
  }
729
741
  export function buildClaudeCodeCommandText() {
730
- return `Load brainclaw project memory and prepare for coordinated work.
731
-
732
- Steps:
733
- 1. Run \`brainclaw context --json\` — load constraints, decisions, traps, plans, handoffs
734
- 2. Run \`brainclaw claim list\` — check what files other agents have claimed
735
- 3. Before editing any file, run \`brainclaw claim create "<description>" --scope <path>\`
736
- 4. Before finishing, run \`brainclaw session-end --auto-release\`
742
+ return `Load brainclaw project memory and prepare for coordinated work.
743
+
744
+ Steps:
745
+ 1. Run \`brainclaw context --json\` — load constraints, decisions, traps, plans, handoffs
746
+ 2. Run \`brainclaw claim list\` — check what files other agents have claimed
747
+ 3. Before editing any file, run \`brainclaw claim create "<description>" --scope <path>\`
748
+ 4. Before finishing, run \`brainclaw session-end --auto-release\`
737
749
  `;
738
750
  }
739
751
  export function ensureClineMcpConfig(cwd) {
@@ -799,34 +811,34 @@ export function ensureWindsurfMcpConfig(homeDir) {
799
811
  */
800
812
  export function ensureWindsurfModernRules(cwd) {
801
813
  const filePath = path.join(cwd, WINDSURF_MODERN_RULES_RELATIVE_PATH);
802
- const content = `# Brainclaw coordination rules
803
-
804
- Brainclaw is the shared coordination layer. Use its MCP facades first — the CLI is only a fallback when MCP is unavailable.
805
-
806
- ## Session start
807
-
808
- Call \`bclaw_work(intent)\`. It loads memory (constraints, decisions, traps, plans, handoffs), resolves the claim, and starts a session in a single call.
809
-
810
- - \`bclaw_work(intent: "resume")\` — continue existing work (auto-surfaces the context diff).
811
- - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` — start new work and claim the scope.
812
- - \`bclaw_work(intent: "consult")\` — read-only context without claiming.
813
-
814
- ## During work
815
-
816
- - Mark plan steps done: \`bclaw_complete_step(planId, stepId)\`.
817
- - Read the inbox: \`bclaw_read_inbox\`.
818
- - Record notes, decisions, traps: \`bclaw_write_note\`, \`bclaw_create(entity, data)\`.
819
-
820
- ## To coordinate with other agents
821
-
822
- \`bclaw_coordinate(intent)\` — \`assign\`, \`consult\`, \`review\`, or \`reroute\`.
823
-
824
- ## Before finishing
825
-
826
- - Release your claims: \`bclaw_release_claim(id)\`.
827
- - Close the session: \`bclaw_session_end\` (auto-releases remaining claims).
828
-
829
- CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
814
+ const content = `# Brainclaw coordination rules
815
+
816
+ Brainclaw is the shared coordination layer. Use its MCP facades first — the CLI is only a fallback when MCP is unavailable.
817
+
818
+ ## Session start
819
+
820
+ Call \`bclaw_work(intent)\`. It loads memory (constraints, decisions, traps, plans, handoffs), resolves the claim, and starts a session in a single call.
821
+
822
+ - \`bclaw_work(intent: "resume")\` — continue existing work (auto-surfaces the context diff).
823
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` — start new work and claim the scope.
824
+ - \`bclaw_work(intent: "consult")\` — read-only context without claiming.
825
+
826
+ ## During work
827
+
828
+ - Mark plan steps done: \`bclaw_complete_step(planId, stepId)\`.
829
+ - Read the inbox: \`bclaw_read_inbox\`.
830
+ - Record notes, decisions, traps: \`bclaw_write_note\`, \`bclaw_create(entity, data)\`.
831
+
832
+ ## To coordinate with other agents
833
+
834
+ \`bclaw_coordinate(intent)\` — \`assign\`, \`consult\`, \`review\`, or \`reroute\`.
835
+
836
+ ## Before finishing
837
+
838
+ - Release your claims: \`bclaw_release_claim(id)\`.
839
+ - Close the session: \`bclaw_session_end\` (auto-releases remaining claims).
840
+
841
+ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
830
842
  `;
831
843
  const { created, updated } = writeTextFileIfChanged(filePath, content);
832
844
  return {
@@ -840,22 +852,22 @@ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw s
840
852
  }
841
853
  export function ensureCopilotSkill(cwd) {
842
854
  const filePath = path.join(cwd, '.github', 'skills', 'brainclaw-context', 'SKILL.md');
843
- const content = `---
844
- name: brainclaw-context
845
- description: "Use this skill when you need the latest Brainclaw context, active plans, constraints, traps, or handoffs before coding. Trigger phrases: refresh project memory, load brainclaw context, inspect active plans, inspect constraints."
846
- ---
847
-
848
- # Brainclaw Context
849
-
850
- Fetch live project memory before significant edits. Prefer the Brainclaw MCP facade; use the CLI only as a fallback when MCP is unavailable.
851
-
852
- ## Steps
853
-
854
- 1. Call \`bclaw_work(intent: "resume")\` to continue existing work, or \`bclaw_work(intent: "consult")\` for read-only context. The response contains active plans, constraints, decisions, traps, and handoffs.
855
- 2. Prefer Brainclaw state over stale assumptions from older instructions or prior sessions.
856
- 3. Coordinate with other agents via \`bclaw_coordinate(intent)\` (\`assign\`, \`consult\`, \`review\`).
857
-
858
- CLI fallback: \`brainclaw context --json\` if the MCP server is not reachable.
855
+ const content = `---
856
+ name: brainclaw-context
857
+ description: "Use this skill when you need the latest Brainclaw context, active plans, constraints, traps, or handoffs before coding. Trigger phrases: refresh project memory, load brainclaw context, inspect active plans, inspect constraints."
858
+ ---
859
+
860
+ # Brainclaw Context
861
+
862
+ Fetch live project memory before significant edits. Prefer the Brainclaw MCP facade; use the CLI only as a fallback when MCP is unavailable.
863
+
864
+ ## Steps
865
+
866
+ 1. Call \`bclaw_work(intent: "resume")\` to continue existing work, or \`bclaw_work(intent: "consult")\` for read-only context. The response contains active plans, constraints, decisions, traps, and handoffs.
867
+ 2. Prefer Brainclaw state over stale assumptions from older instructions or prior sessions.
868
+ 3. Coordinate with other agents via \`bclaw_coordinate(intent)\` (\`assign\`, \`consult\`, \`review\`).
869
+
870
+ CLI fallback: \`brainclaw context --json\` if the MCP server is not reachable.
859
871
  `;
860
872
  const { created, updated } = writeTextFileIfChanged(filePath, content);
861
873
  return {
@@ -877,24 +889,24 @@ CLI fallback: \`brainclaw context --json\` if the MCP server is not reachable.
877
889
  */
878
890
  export function ensureUniversalBrainclawSkill(cwd) {
879
891
  const filePath = path.join(cwd, UNIVERSAL_SKILL_RELATIVE_PATH);
880
- const content = `---
881
- name: brainclaw
882
- description: 'Load and act on Brainclaw project memory, active claims, plans, traps, and handoffs before code changes. Trigger: refresh brainclaw context, check active claims, load coordination state.'
883
- allowed-tools: 'Read Bash(npx brainclaw:*)'
884
- ---
885
-
886
- # Brainclaw
887
-
888
- Load the shared coordination state before any significant code change. Prefer the Brainclaw MCP facade; the CLI is a fallback when MCP is not reachable.
889
-
890
- ## Steps
891
-
892
- 1. Call \`bclaw_work(intent)\` — \`resume\` to continue existing work, \`execute\` to claim a new scope, or \`consult\` for read-only context. The response gives you memory, active claims, plans, traps, and handoffs.
893
- 2. Respect active claims from other agents reported in the response; do not edit a claimed scope unless you own the claim.
894
- 3. Use \`bclaw_coordinate(intent)\` to assign, consult, or review other agents when needed.
895
- 4. When done, call \`bclaw_session_end\` (auto-releases your remaining claims).
896
-
897
- CLI fallback only: \`brainclaw context --json\` / \`brainclaw claim create\` / \`brainclaw session-end --auto-release\` if the MCP server is unavailable.
892
+ const content = `---
893
+ name: brainclaw
894
+ description: 'Load and act on Brainclaw project memory, active claims, plans, traps, and handoffs before code changes. Trigger: refresh brainclaw context, check active claims, load coordination state.'
895
+ allowed-tools: 'Read Bash(npx brainclaw:*)'
896
+ ---
897
+
898
+ # Brainclaw
899
+
900
+ Load the shared coordination state before any significant code change. Prefer the Brainclaw MCP facade; the CLI is a fallback when MCP is not reachable.
901
+
902
+ ## Steps
903
+
904
+ 1. Call \`bclaw_work(intent)\` — \`resume\` to continue existing work, \`execute\` to claim a new scope, or \`consult\` for read-only context. The response gives you memory, active claims, plans, traps, and handoffs.
905
+ 2. Respect active claims from other agents reported in the response; do not edit a claimed scope unless you own the claim.
906
+ 3. Use \`bclaw_coordinate(intent)\` to assign, consult, or review other agents when needed.
907
+ 4. When done, call \`bclaw_session_end\` (auto-releases your remaining claims).
908
+
909
+ CLI fallback only: \`brainclaw context --json\` / \`brainclaw claim create\` / \`brainclaw session-end --auto-release\` if the MCP server is unavailable.
898
910
  `;
899
911
  const { created, updated } = writeTextFileIfChanged(filePath, content);
900
912
  return {
@@ -1005,19 +1017,19 @@ export function ensureVscodeExtensionRecommendation(cwd) {
1005
1017
  }
1006
1018
  export function ensureCursorMdc(cwd) {
1007
1019
  const filePath = path.join(cwd, '.cursor', 'rules', 'brainclaw-mcp-shim.mdc');
1008
- const content = `---
1009
- description: Use this rule when work depends on live Brainclaw memory or active project rules.
1010
- globs: "**/*"
1011
- alwaysApply: true
1012
- ---
1013
-
1014
- Brainclaw is the shared coordination layer. Call the MCP facade first; the CLI is only a fallback when MCP is not reachable.
1015
-
1016
- Before significant edits or when asked about project rules, call \`bclaw_work(intent: "consult")\` (or \`"resume"\` if continuing a task) via the Brainclaw MCP server. The response carries active claims, in-progress plans, constraints, decisions, traps, and handoffs.
1017
-
1018
- If the response lists active claims or in-progress plans, follow them before editing. Use \`bclaw_coordinate(intent)\` to dispatch, consult, or review other agents.
1019
-
1020
- CLI fallback only when MCP is unavailable: \`brainclaw context --json\`.
1020
+ const content = `---
1021
+ description: Use this rule when work depends on live Brainclaw memory or active project rules.
1022
+ globs: "**/*"
1023
+ alwaysApply: true
1024
+ ---
1025
+
1026
+ Brainclaw is the shared coordination layer. Call the MCP facade first; the CLI is only a fallback when MCP is not reachable.
1027
+
1028
+ Before significant edits or when asked about project rules, call \`bclaw_work(intent: "consult")\` (or \`"resume"\` if continuing a task) via the Brainclaw MCP server. The response carries active claims, in-progress plans, constraints, decisions, traps, and handoffs.
1029
+
1030
+ If the response lists active claims or in-progress plans, follow them before editing. Use \`bclaw_coordinate(intent)\` to dispatch, consult, or review other agents.
1031
+
1032
+ CLI fallback only when MCP is unavailable: \`brainclaw context --json\`.
1021
1033
  `;
1022
1034
  const { created, updated } = writeTextFileIfChanged(filePath, content);
1023
1035
  return {