brainclaw 1.8.0 → 1.9.1

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 (178) hide show
  1. package/README.md +592 -505
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +138 -13
  4. package/dist/commands/add-step.js +1 -1
  5. package/dist/commands/bootstrap.js +2 -26
  6. package/dist/commands/check-security-mcp.js +50 -33
  7. package/dist/commands/check-security.js +86 -43
  8. package/dist/commands/claim.js +22 -21
  9. package/dist/commands/confirm.js +26 -0
  10. package/dist/commands/context-diff.js +1 -1
  11. package/dist/commands/dispatch-watch.js +142 -0
  12. package/dist/commands/doctor.js +113 -2
  13. package/dist/commands/estimation-report.js +115 -16
  14. package/dist/commands/harvest.js +286 -23
  15. package/dist/commands/hooks.js +73 -73
  16. package/dist/commands/init.js +124 -22
  17. package/dist/commands/install-hooks.js +78 -78
  18. package/dist/commands/loops-handlers.js +4 -0
  19. package/dist/commands/mcp-read-handlers.js +253 -41
  20. package/dist/commands/mcp.js +664 -102
  21. package/dist/commands/memory.js +21 -17
  22. package/dist/commands/migrate.js +81 -17
  23. package/dist/commands/prune.js +78 -4
  24. package/dist/commands/reflect.js +26 -20
  25. package/dist/commands/register-agent.js +57 -1
  26. package/dist/commands/repair.js +20 -0
  27. package/dist/commands/session-end.js +15 -6
  28. package/dist/commands/session-start.js +18 -1
  29. package/dist/commands/setup-security.js +39 -18
  30. package/dist/commands/setup.js +26 -27
  31. package/dist/commands/stale.js +16 -2
  32. package/dist/commands/switch.js +26 -5
  33. package/dist/commands/uninstall.js +126 -34
  34. package/dist/commands/update-step.js +6 -0
  35. package/dist/commands/version.js +1 -1
  36. package/dist/commands/worktree.js +60 -0
  37. package/dist/core/actions.js +12 -3
  38. package/dist/core/agent-capability.js +30 -17
  39. package/dist/core/agent-files.js +963 -666
  40. package/dist/core/agent-integrations.js +0 -3
  41. package/dist/core/agent-inventory.js +67 -0
  42. package/dist/core/agent-registry.js +163 -29
  43. package/dist/core/agentrun-reconciler.js +33 -2
  44. package/dist/core/agentruns.js +7 -1
  45. package/dist/core/ai-agent-detection.js +31 -44
  46. package/dist/core/archival.js +15 -9
  47. package/dist/core/assignment-reconciler.js +56 -0
  48. package/dist/core/assignment-sweeper.js +127 -4
  49. package/dist/core/assignments.js +69 -11
  50. package/dist/core/bootstrap.js +233 -67
  51. package/dist/core/brainclaw-version.js +22 -0
  52. package/dist/core/candidates.js +21 -1
  53. package/dist/core/claims.js +313 -150
  54. package/dist/core/codev-prompts.js +38 -38
  55. package/dist/core/config.js +6 -1
  56. package/dist/core/context-diff.js +148 -20
  57. package/dist/core/context.js +129 -8
  58. package/dist/core/coordination.js +22 -3
  59. package/dist/core/default-profiles/doctor.yaml +11 -11
  60. package/dist/core/default-profiles/janitor.yaml +11 -11
  61. package/dist/core/default-profiles/onboarder.yaml +11 -11
  62. package/dist/core/default-profiles/reviewer.yaml +13 -13
  63. package/dist/core/dispatch-status.js +79 -5
  64. package/dist/core/dispatcher.js +65 -12
  65. package/dist/core/entity-operations.js +74 -27
  66. package/dist/core/entity-registry.js +31 -5
  67. package/dist/core/event-log.js +138 -21
  68. package/dist/core/events/checkpoint.js +258 -0
  69. package/dist/core/events/genesis.js +220 -0
  70. package/dist/core/events/journal.js +507 -0
  71. package/dist/core/events/materialize.js +126 -0
  72. package/dist/core/events/registry-post-image.js +110 -0
  73. package/dist/core/events/verify.js +109 -0
  74. package/dist/core/execution-adapters.js +23 -0
  75. package/dist/core/execution.js +1 -1
  76. package/dist/core/facade-schema.js +38 -0
  77. package/dist/core/gc-semantic.js +130 -5
  78. package/dist/core/handoff-snapshot.js +68 -0
  79. package/dist/core/ids.js +19 -8
  80. package/dist/core/instruction-templates.js +34 -115
  81. package/dist/core/io.js +39 -3
  82. package/dist/core/json-store.js +10 -1
  83. package/dist/core/lock.js +153 -28
  84. package/dist/core/loops/bootstrap-acquire.js +25 -1
  85. package/dist/core/loops/facade-schema.js +2 -0
  86. package/dist/core/loops/hooks/survey-signals-baseline.js +36 -0
  87. package/dist/core/loops/index.js +1 -0
  88. package/dist/core/loops/presets/bootstrap.js +7 -0
  89. package/dist/core/loops/store.js +17 -0
  90. package/dist/core/loops/verbs.js +24 -2
  91. package/dist/core/markdown.js +8 -76
  92. package/dist/core/mcp-command-resolution.js +245 -0
  93. package/dist/core/memory-compactor.js +5 -3
  94. package/dist/core/memory-lifecycle.js +282 -0
  95. package/dist/core/merge-risk.js +150 -0
  96. package/dist/core/messaging.js +10 -3
  97. package/dist/core/migration.js +11 -1
  98. package/dist/core/observer-mode.js +26 -0
  99. package/dist/core/operations/memory-mutation.js +90 -65
  100. package/dist/core/operations/plan.js +27 -1
  101. package/dist/core/protocol-skills.js +210 -0
  102. package/dist/core/reflection-safety.js +6 -7
  103. package/dist/core/reputation.js +84 -2
  104. package/dist/core/runtime-signals.js +72 -10
  105. package/dist/core/runtime.js +84 -1
  106. package/dist/core/schema.js +114 -0
  107. package/dist/core/search.js +19 -2
  108. package/dist/core/security-detectors.js +125 -0
  109. package/dist/core/security-extract.js +189 -0
  110. package/dist/core/security-guard.js +217 -139
  111. package/dist/core/security-packages.js +121 -0
  112. package/dist/core/security-scoring.js +76 -9
  113. package/dist/core/security.js +34 -2
  114. package/dist/core/sequence.js +11 -2
  115. package/dist/core/setup-flow.js +141 -13
  116. package/dist/core/spawn-check.js +16 -2
  117. package/dist/core/staleness.js +73 -2
  118. package/dist/core/state.js +250 -54
  119. package/dist/core/store-resolution.js +45 -12
  120. package/dist/core/worktree.js +90 -26
  121. package/dist/facts.js +8 -8
  122. package/dist/facts.json +7 -7
  123. package/docs/PROTOCOL.md +223 -0
  124. package/docs/adapters/openclaw.md +43 -43
  125. package/docs/architecture/project-refs.md +328 -328
  126. package/docs/cli.md +2097 -2096
  127. package/docs/concepts/coordination.md +52 -52
  128. package/docs/concepts/coordinator-runbook.md +129 -0
  129. package/docs/concepts/dispatch-lifecycle.md +245 -245
  130. package/docs/concepts/event-log-store.md +928 -0
  131. package/docs/concepts/ideation-loop.md +317 -317
  132. package/docs/concepts/loop-engine.md +520 -511
  133. package/docs/concepts/mcp-governance.md +268 -268
  134. package/docs/concepts/memory.md +89 -88
  135. package/docs/concepts/multi-agent-workflows.md +167 -167
  136. package/docs/concepts/observer-protocol.md +361 -0
  137. package/docs/concepts/parallel-merge-protocol.md +71 -0
  138. package/docs/concepts/plans-and-claims.md +217 -174
  139. package/docs/concepts/project-md-convention.md +35 -35
  140. package/docs/concepts/runtime-notes.md +38 -38
  141. package/docs/concepts/skills.md +78 -0
  142. package/docs/concepts/troubleshooting.md +254 -254
  143. package/docs/concepts/workspace-bootstrapping.md +142 -81
  144. package/docs/context-format-changelog.md +35 -35
  145. package/docs/context-format.md +48 -48
  146. package/docs/index.md +65 -65
  147. package/docs/integrations/agents.md +162 -162
  148. package/docs/integrations/claude-code.md +23 -23
  149. package/docs/integrations/cline.md +87 -88
  150. package/docs/integrations/codex.md +2 -2
  151. package/docs/integrations/continue.md +60 -60
  152. package/docs/integrations/copilot.md +82 -80
  153. package/docs/integrations/cursor.md +23 -23
  154. package/docs/integrations/kilocode.md +72 -72
  155. package/docs/integrations/mcp.md +377 -377
  156. package/docs/integrations/mistral-vibe.md +122 -122
  157. package/docs/integrations/openclaw.md +99 -98
  158. package/docs/integrations/opencode.md +84 -84
  159. package/docs/integrations/overview.md +122 -122
  160. package/docs/integrations/roo.md +74 -74
  161. package/docs/integrations/windsurf.md +83 -83
  162. package/docs/mcp-schema-changelog.md +360 -329
  163. package/docs/playbooks/integration/index.md +121 -121
  164. package/docs/playbooks/orchestration.md +37 -0
  165. package/docs/playbooks/productivity/index.md +99 -99
  166. package/docs/playbooks/team/index.md +117 -117
  167. package/docs/product/agent-first-model.md +184 -184
  168. package/docs/product/entity-model-audit.md +462 -462
  169. package/docs/product/positioning.md +86 -86
  170. package/docs/quickstart-existing-project.md +107 -107
  171. package/docs/quickstart.md +148 -147
  172. package/docs/release-maintenance.md +79 -79
  173. package/docs/reputation.md +52 -52
  174. package/docs/review.md +45 -45
  175. package/docs/security.md +212 -53
  176. package/docs/server-operations.md +118 -118
  177. package/docs/storage.md +110 -108
  178. package/package.json +86 -69
@@ -9,33 +9,33 @@ import { BRAINCLAW_SECTION_START, BRAINCLAW_SECTION_END, upsertBrainclawSection,
9
9
  * deterministically into every agent conversation.
10
10
  */
11
11
  export function generateCursorHook(projectName) {
12
- return `---
13
- description: brainclaw session bootstrap for ${projectName}
14
- alwaysApply: true
15
- ---
16
-
17
- # Brainclaw session bootstrap
18
-
19
- Brainclaw is the shared coordination layer for this project. Use its MCP facades first — the CLI is only a fallback when MCP is unavailable.
20
-
21
- ## At the start of every session
22
-
23
- Call \`bclaw_work(intent)\` — it handles session setup, context load, and scope claim in a single call.
24
-
25
- - \`bclaw_work(intent: "resume")\` when continuing an existing task.
26
- - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
27
- - \`bclaw_work(intent: "consult")\` to read context without claiming.
28
-
29
- ## To coordinate with other agents
30
-
31
- \`bclaw_coordinate(intent)\` — \`assign\`, \`consult\`, \`review\`, or \`reroute\`.
32
-
33
- ## Before finishing
34
-
35
- - Release your claims: \`bclaw_release_claim(id)\`.
36
- - Close out the session: \`bclaw_session_end\` (or let it auto-release via the session hook).
37
-
38
- CLI fallback only: \`brainclaw context\` / \`brainclaw session-end --auto-release\` if MCP is not reachable.
12
+ return `---
13
+ description: brainclaw session bootstrap for ${projectName}
14
+ alwaysApply: true
15
+ ---
16
+
17
+ # Brainclaw session bootstrap
18
+
19
+ Brainclaw is the shared coordination layer for this project. Use its MCP facades first — the CLI is only a fallback when MCP is unavailable.
20
+
21
+ ## At the start of every session
22
+
23
+ Call \`bclaw_work(intent)\` — it handles session setup, context load, and scope claim in a single call.
24
+
25
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
26
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
27
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
28
+
29
+ ## To coordinate with other agents
30
+
31
+ \`bclaw_coordinate(intent)\` — \`assign\`, \`consult\`, \`review\`, or \`reroute\`.
32
+
33
+ ## Before finishing
34
+
35
+ - Release your claims: \`bclaw_release_claim(id)\`.
36
+ - Close out the session: \`bclaw_session_end\` (or let it auto-release via the session hook).
37
+
38
+ CLI fallback only: \`brainclaw context\` / \`brainclaw session-end --auto-release\` if MCP is not reachable.
39
39
  `;
40
40
  }
41
41
  /**
@@ -44,58 +44,58 @@ CLI fallback only: \`brainclaw context\` / \`brainclaw session-end --auto-releas
44
44
  * delimited "SESSION START" block acts as a deterministic trigger.
45
45
  */
46
46
  export function generateWindsurfHook(projectName) {
47
- return `# Brainclaw session trigger — ${projectName}
48
- # This block is always active. Windsurf Cascade reads .windsurfrules on every activation.
49
-
50
- ## SESSION START (always run first)
51
-
52
- Call the Brainclaw MCP facade before responding to any request:
53
-
54
- - \`bclaw_work(intent: "resume")\` when continuing an existing task.
55
- - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
56
- - \`bclaw_work(intent: "consult")\` to read context without claiming.
57
-
58
- This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
59
-
60
- ## COORDINATION
61
-
62
- \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
63
-
64
- ## SESSION END (before finishing)
65
-
66
- - \`bclaw_release_claim(id)\` for each claim you hold.
67
- - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
68
-
69
- CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
47
+ return `# Brainclaw session trigger — ${projectName}
48
+ # This block is always active. Windsurf Cascade reads .windsurfrules on every activation.
49
+
50
+ ## SESSION START (always run first)
51
+
52
+ Call the Brainclaw MCP facade before responding to any request:
53
+
54
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
55
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
56
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
57
+
58
+ This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
59
+
60
+ ## COORDINATION
61
+
62
+ \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
63
+
64
+ ## SESSION END (before finishing)
65
+
66
+ - \`bclaw_release_claim(id)\` for each claim you hold.
67
+ - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
68
+
69
+ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
70
70
  `;
71
71
  }
72
72
  /**
73
73
  * Generate a generic markdown session-trigger section.
74
74
  */
75
75
  export function generateMarkdownHook(agentName, projectName) {
76
- return `# Brainclaw session trigger — ${projectName}
77
- # This block is always active. ${agentName} reads this file on every activation.
78
-
79
- ## SESSION START (always run first)
80
-
81
- Call the Brainclaw MCP facade before responding to any request:
82
-
83
- - \`bclaw_work(intent: "resume")\` when continuing an existing task.
84
- - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
85
- - \`bclaw_work(intent: "consult")\` to read context without claiming.
86
-
87
- This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
88
-
89
- ## COORDINATION
90
-
91
- \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
92
-
93
- ## SESSION END (before finishing)
94
-
95
- - \`bclaw_release_claim(id)\` for each claim you hold.
96
- - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
97
-
98
- CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
76
+ return `# Brainclaw session trigger — ${projectName}
77
+ # This block is always active. ${agentName} reads this file on every activation.
78
+
79
+ ## SESSION START (always run first)
80
+
81
+ Call the Brainclaw MCP facade before responding to any request:
82
+
83
+ - \`bclaw_work(intent: "resume")\` when continuing an existing task.
84
+ - \`bclaw_work(intent: "execute", scope: "<path>", task: "<text>")\` when starting new work on a specific scope.
85
+ - \`bclaw_work(intent: "consult")\` to read context without claiming.
86
+
87
+ This returns active constraints, recent decisions, known traps, open plans, active claims, and the last handoff. Do not skip.
88
+
89
+ ## COORDINATION
90
+
91
+ \`bclaw_coordinate(intent)\` to assign, consult, review, or reroute other agents.
92
+
93
+ ## SESSION END (before finishing)
94
+
95
+ - \`bclaw_release_claim(id)\` for each claim you hold.
96
+ - \`bclaw_session_end\` to close the session (auto-releases remaining claims).
97
+
98
+ CLI fallback only when MCP is unavailable: \`brainclaw context\` / \`brainclaw session-end --auto-release\`.
99
99
  `;
100
100
  }
101
101
  export function writeHook(content, relativePath, cwd) {
@@ -16,8 +16,11 @@ import { BRAINCLAW_EXCLUSIVE_DIRECTORIES, describeAutoConfigWrite, ensureAgentFi
16
16
  import { detectAiAgent, detectWslEnvironment } from '../core/ai-agent-detection.js';
17
17
  import { buildAiSurfaceInventory, renderAiSurfaceUsageHints } from '../core/ai-surface-inventory.js';
18
18
  import { ensureUserStore, hasCompletedSetup } from '../core/setup-state.js';
19
+ import { resolveEmptyMemoryRecommendation } from '../core/setup-flow.js';
19
20
  import { writeDetectedAgentExport } from './export.js';
20
21
  import { writeDetectedAgentHooks } from './hooks.js';
22
+ import { checkGitPresence, runGlobalInstall } from './setup.js';
23
+ import { createBackup, BackupError } from '../core/upgrades/backup.js';
21
24
  import { ConfigSchema } from '../core/schema.js';
22
25
  export async function runInit(options = {}) {
23
26
  const cwd = options.cwd ?? process.cwd();
@@ -29,6 +32,14 @@ export async function runInit(options = {}) {
29
32
  if (!hasCompletedSetup()) {
30
33
  ensureUserStore();
31
34
  }
35
+ // Git-presence gate, aligned with `brainclaw setup`: agent-first onboarding
36
+ // assumes git for memory versioning + post-merge hooks. Allow override via
37
+ // BRAINCLAW_SKIP_REPO_ANALYSIS=1 for tests that exercise non-git fixtures.
38
+ if (process.env.BRAINCLAW_SKIP_REPO_ANALYSIS !== '1' && !checkGitPresence()) {
39
+ console.error('brainclaw init needs git to work.');
40
+ console.error('Install git from https://git-scm.com and try again.');
41
+ process.exit(1);
42
+ }
32
43
  if (containingMemoryStore) {
33
44
  console.error(`Error: cannot run \`brainclaw init\` from inside an existing project memory store (${containingMemoryStore}).`);
34
45
  console.error('Run `brainclaw init` from the project root directory instead.');
@@ -61,6 +72,29 @@ export async function runInit(options = {}) {
61
72
  const storageDir = resolveStorageDir(options.storageDir);
62
73
  const projectMemoryExists = memoryExists(cwd);
63
74
  const existingConfig = projectMemoryExists ? loadExistingConfig(cwd, storageDir) : undefined;
75
+ // --force backup gate: feedback_no_init_force (June 2026) entered the code.
76
+ // Before rebuilding identity fields on top of an existing store, take a
77
+ // sibling backup so curator personalisations (redaction patterns, claim
78
+ // TTL, governance, sensitive_paths) can always be recovered even if the
79
+ // merge below regresses or the agent ran `init --force` by mistake.
80
+ let forceBackupPath;
81
+ if (options.force && projectMemoryExists) {
82
+ try {
83
+ const handle = createBackup({
84
+ storePath: path.join(cwd, storageDir),
85
+ note: 'init --force pre-reconstruction snapshot',
86
+ storeSchemaVersion: existingConfig ? String(existingConfig.schema_version) : null,
87
+ });
88
+ forceBackupPath = handle.backupPath;
89
+ }
90
+ catch (err) {
91
+ const reason = err instanceof BackupError
92
+ ? `${err.code}: ${err.message}`
93
+ : err instanceof Error ? err.message : String(err);
94
+ console.error(`Error: --force backup failed (${reason}). Aborting to preserve the existing store. Re-run without --force, or move the store aside manually.`);
95
+ process.exit(1);
96
+ }
97
+ }
64
98
  const topology = resolveTopology(options.topology, existingConfig?.topology);
65
99
  const ignoreStrategy = resolveIgnoreStrategy(topology, existingConfig?.ignore_strategy);
66
100
  const skipAgentBootstrap = options.skipAgentBootstrap === true || process.env.BRAINCLAW_SKIP_AGENT_BOOTSTRAP === '1';
@@ -83,11 +117,13 @@ export async function runInit(options = {}) {
83
117
  });
84
118
  // Auto-detect and register the AI coding agent running in this environment
85
119
  const detectedAi = skipAgentBootstrap ? undefined : detectAiAgent();
86
- let registeredAiAgent = detectedAi
120
+ const registeredAiAgent = detectedAi
87
121
  ? registerAgentIdentity({
88
122
  agentName: detectedAi.name,
89
123
  kind: detectedAi.kind,
90
- trustLevel: detectedAi.trust_level,
124
+ // pln#562 step 2 — auto-registration never exceeds contributor;
125
+ // elevation is an explicit curator act (set-trust / register-agent).
126
+ trustLevel: 'contributor',
91
127
  cwd,
92
128
  preferredDirName: storageDir,
93
129
  })
@@ -123,7 +159,15 @@ export async function runInit(options = {}) {
123
159
  storageDir,
124
160
  topology,
125
161
  ignoreStrategy,
126
- existingConfig: options.force ? undefined : existingConfig,
162
+ // --force rebuilds identity (project_id, agent, topology, storage_dir)
163
+ // but merges through existingConfig so curator personalisations
164
+ // (redaction patterns, governance, claims TTL, sensitive_paths,
165
+ // cross_project_links, custom markdown caps) survive the reset.
166
+ // The original `force ? undefined` path wiped these silently —
167
+ // discovered when feedback_no_init_force was promoted from a memory
168
+ // habit to a tracked regression.
169
+ existingConfig,
170
+ defaultJournalMode: !projectMemoryExists,
127
171
  compact: options.compact === true,
128
172
  });
129
173
  if (detectedAi && isAgentIntegrationName(detectedAi.name)) {
@@ -141,6 +185,19 @@ export async function runInit(options = {}) {
141
185
  .filter((hook) => hook.relativePath !== detectedExport?.relativePath))
142
186
  : [];
143
187
  const detectedAutoConfig = detectedAi ? writeDetectedAgentAutoConfig(detectedAi.name, cwd) : [];
188
+ // Per-agent slice of machine prerequisites (the same writes setup performs
189
+ // globally, but scoped to the detected agent). This makes `init` the single
190
+ // entry point for the carte-blanche / fresh-repo case: an agent-first
191
+ // bootstrap no longer needs a separate `brainclaw setup` shell-out + session
192
+ // reload. Idempotent — each ensure* function returns "skipped" when the
193
+ // agent's user-scope config doesn't exist.
194
+ const skipMachinePrereqs = options.skipMachinePrereqs === true
195
+ || skipAgentBootstrap
196
+ || testMode
197
+ || process.env.BRAINCLAW_INIT_SKIP_MACHINE_PREREQS === '1';
198
+ const machinePrereqsWritten = detectedAi && !skipMachinePrereqs
199
+ ? safeRunMachinePrereqs(detectedAi.name)
200
+ : [];
144
201
  // Register in global project registry
145
202
  try {
146
203
  const entry = scanProject(cwd);
@@ -177,7 +234,10 @@ export async function runInit(options = {}) {
177
234
  if (projectMemoryExists) {
178
235
  console.log(`✔ Refreshed existing project memory in ${storageDir}/`);
179
236
  if (options.force) {
180
- console.log('✔ Existing memory preserved; rebuilt managed configuration and agent integration files from defaults');
237
+ if (forceBackupPath) {
238
+ console.log(`✔ Pre-reconstruction backup at ${forceBackupPath} (rollback: brainclaw upgrade --rollback)`);
239
+ }
240
+ console.log('✔ Existing memory preserved; rebuilt managed identity and refreshed agent integration files (customisations merged through)');
181
241
  }
182
242
  else {
183
243
  console.log('✔ Existing memory preserved; refreshed managed configuration and agent integration files');
@@ -192,6 +252,12 @@ export async function runInit(options = {}) {
192
252
  if (registeredAiAgent) {
193
253
  console.log(`✔ AI agent detected: ${registeredAiAgent.agent_name} [${detectedAi.detection_source}] (${registeredAiAgent.agent_id})`);
194
254
  }
255
+ if (machinePrereqsWritten.length > 0) {
256
+ console.log(`\u2714 Machine prerequisites for ${detectedAi.name}:`);
257
+ for (const filePath of machinePrereqsWritten) {
258
+ console.log(` - ${filePath}`);
259
+ }
260
+ }
195
261
  if (detectedExport) {
196
262
  console.log(`\u2714 Agent instructions written to ${detectedExport.relativePath} (${detectedExport.created ? 'created' : 'updated'})`);
197
263
  }
@@ -265,25 +331,36 @@ export async function runInit(options = {}) {
265
331
  // Install post-merge hook for auto-release of claims after merge
266
332
  installPostMergeHookIfMissing(cwd);
267
333
  if (!testMode) {
268
- const onboardingPreflight = runBootstrapProfile({ cwd, refresh: true });
334
+ // Shared empty-memory rule (see docs/concepts/workspace-bootstrapping.md):
335
+ // repo with content → bclaw_bootstrap extraction; greenfield → bootstrap
336
+ // loop. The brownfield preflight scan is skipped on greenfield — there is
337
+ // nothing to harvest yet.
338
+ const emptyMemoryRec = resolveEmptyMemoryRecommendation(cwd);
269
339
  console.log('');
270
- console.log('Onboarding preflight:');
271
- for (const line of renderBootstrapSummary(onboardingPreflight).split('\n')) {
272
- console.log(` ${line}`);
273
- }
274
- if (onboardingPreflight.importPlan.suggestion_count > 0) {
275
- console.log('');
276
- console.log(`Next step: run 'brainclaw bootstrap --apply' to import ${onboardingPreflight.importPlan.suggestion_count} suggested item(s) into canonical memory.`);
277
- console.log(`Rollback: run 'brainclaw bootstrap --uninstall' to deactivate the last bootstrap-managed import.`);
278
- }
279
- if ((onboardingPreflight.importPlan.interview?.question_count ?? 0) > 0) {
280
- console.log('');
281
- console.log(`Interview: run 'brainclaw bootstrap --interview --audience cli' for terminal agents or '--audience ide_chat' for IDE chat agents.`);
282
- console.log(`Apply confirmed answers: write a JSON answers file and run 'brainclaw bootstrap --answers-file <path> --apply'.`);
340
+ if (emptyMemoryRec.route === 'ideate') {
341
+ console.log(`Onboarding: ${emptyMemoryRec.text}`);
283
342
  }
284
- else if ((onboardingPreflight.profile.gaps?.length ?? 0) > 0) {
285
- console.log('');
286
- console.log(`Next step: review the onboarding gaps, then use 'brainclaw bootstrap --json' as the basis for an interview/import flow.`);
343
+ else {
344
+ const onboardingPreflight = runBootstrapProfile({ cwd, refresh: true });
345
+ console.log('Onboarding preflight:');
346
+ console.log(` ${emptyMemoryRec.text}`);
347
+ for (const line of renderBootstrapSummary(onboardingPreflight).split('\n')) {
348
+ console.log(` ${line}`);
349
+ }
350
+ if (onboardingPreflight.importPlan.suggestion_count > 0) {
351
+ console.log('');
352
+ console.log(`Next step: run 'brainclaw bootstrap --apply' to import ${onboardingPreflight.importPlan.suggestion_count} suggested item(s) into canonical memory.`);
353
+ console.log(`Rollback: run 'brainclaw bootstrap --uninstall' to deactivate the last bootstrap-managed import.`);
354
+ }
355
+ if ((onboardingPreflight.importPlan.interview?.question_count ?? 0) > 0) {
356
+ console.log('');
357
+ console.log(`Interview: run 'brainclaw bootstrap --interview --audience cli' for terminal agents or '--audience ide_chat' for IDE chat agents.`);
358
+ console.log(`Apply confirmed answers: write a JSON answers file and run 'brainclaw bootstrap --answers-file <path> --apply'.`);
359
+ }
360
+ else if ((onboardingPreflight.profile.gaps?.length ?? 0) > 0) {
361
+ console.log('');
362
+ console.log(`Next step: review the onboarding gaps, then use 'brainclaw bootstrap --json' as the basis for an interview/import flow.`);
363
+ }
287
364
  }
288
365
  }
289
366
  console.log('');
@@ -293,7 +370,16 @@ export async function runInit(options = {}) {
293
370
  else {
294
371
  console.log(`Tip: run 'brainclaw init' again later to refresh the detected agent's integration files on this project.`);
295
372
  }
296
- console.log(`Tip: run 'brainclaw context --json' to load the shared memory into your agent session.`);
373
+ console.log(`Tip: in an agent session, call the bclaw_work MCP tool (intent: "consult") to load the shared memory; from a terminal, 'brainclaw context --json' does the same.`);
374
+ }
375
+ function safeRunMachinePrereqs(agentName) {
376
+ try {
377
+ return runGlobalInstall([agentName]);
378
+ }
379
+ catch {
380
+ // Non-fatal: machine-scope writes are best-effort, never block init.
381
+ return [];
382
+ }
297
383
  }
298
384
  function installPostMergeHookIfMissing(cwd) {
299
385
  try {
@@ -483,6 +569,12 @@ function buildInitConfig(input) {
483
569
  storageDir: input.storageDir,
484
570
  topology: input.topology,
485
571
  ignoreStrategy: input.ignoreStrategy,
572
+ // Solo-agent fresh default: the human running init is the default curator.
573
+ // Without it, approval_policy=review + curators=[] = every candidate sits
574
+ // in pending forever — a surprise the 2026-06-10 front-door audit flagged.
575
+ // mergeConfigWithDefaults preserves any explicit curators list on an
576
+ // existing store, so this only takes effect on fresh installs.
577
+ curatorName: input.currentAgent.name,
486
578
  });
487
579
  const config = input.existingConfig
488
580
  ? mergeConfigWithDefaults(input.existingConfig, fallbackConfig)
@@ -512,6 +604,16 @@ function buildInitConfig(input) {
512
604
  max_items_per_section: Math.min(markdown.max_items_per_section, 20),
513
605
  };
514
606
  }
607
+ // pln#567 (decision A) — the event journal is ON by default for projects
608
+ // created through init. Set HERE, never in defaultConfig:
609
+ // createTestWorkspace builds its config straight from defaultConfig, so a dual
610
+ // default there would make the whole core suite dual-write (trp_65176454).
611
+ // Existing stores keep their current value, including unset legacy configs:
612
+ // `migrate --enable-journal` is the explicit path that turns them on and
613
+ // backfills genesis before future dual-writes depend on the journal.
614
+ if (input.defaultJournalMode === true && config.store?.journal?.mode === undefined) {
615
+ config.store = { ...config.store, journal: { ...config.store?.journal, mode: 'dual' } };
616
+ }
515
617
  return config;
516
618
  }
517
619
  function mergeConfigWithDefaults(existingConfig, fallbackConfig) {
@@ -40,63 +40,63 @@ export function runInstallHooks(options = {}) {
40
40
  }
41
41
  }
42
42
  function generateClaudePreToolScript() {
43
- return `#!/bin/sh
44
- # brainclaw Claude Code preToolUse hook
45
- # Generated by: brainclaw install-hooks
46
- exec node -e "
47
- const fs = require('fs');
48
- const path = require('path');
49
- const { execSync } = require('child_process');
50
-
51
- const toolName = process.env.CLAUDE_TOOL_NAME || process.argv[2] || process.env.TOOL_NAME || '';
52
- const isWrite = /edit|write|replace|bash|str_replace/i.test(toolName);
53
-
54
- if (!isWrite || !toolName) process.exit(0);
55
-
56
- try {
57
- const BCLAW_CMD = fs.existsSync(path.join(process.cwd(), 'node_modules', '.bin', 'brainclaw'))
58
- ? 'npx brainclaw' : 'brainclaw';
59
- const out = execSync(BCLAW_CMD + ' claim list --json', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
60
- const claims = JSON.parse(out);
61
- if (claims && claims.length > 0) process.exit(0);
62
- } catch (e) {
63
- // ignore if brainclaw not found or fails
64
- process.exit(0);
65
- }
66
-
67
- const sessionMark = path.join(process.cwd(), '.brainclaw', 'tmp', 'claude_warned');
68
- if (!fs.existsSync(path.dirname(sessionMark))) fs.mkdirSync(path.dirname(sessionMark), { recursive: true });
69
-
70
- if (fs.existsSync(sessionMark)) {
71
- const mtime = fs.statSync(sessionMark).mtimeMs;
72
- if (Date.now() - mtime < 2 * 60 * 60 * 1000) {
73
- process.exit(0); // already warned this session
74
- }
75
- }
76
- fs.writeFileSync(sessionMark, Date.now().toString());
77
-
78
- process.stderr.write('\\n[Brainclaw] ⚠️ WARNING: You are about to use an Edit/Write tool (' + toolName + ') but you have NO active claim.\\n');
79
- process.stderr.write('[Brainclaw] Consider running \\\`brainclaw claim create <scope>\\\` to lock your work and avoid conflicts.\\n\\n');
80
- " 2>&1 || exit 0
43
+ return `#!/bin/sh
44
+ # brainclaw Claude Code preToolUse hook
45
+ # Generated by: brainclaw install-hooks
46
+ exec node -e "
47
+ const fs = require('fs');
48
+ const path = require('path');
49
+ const { execSync } = require('child_process');
50
+
51
+ const toolName = process.env.CLAUDE_TOOL_NAME || process.argv[2] || process.env.TOOL_NAME || '';
52
+ const isWrite = /edit|write|replace|bash|str_replace/i.test(toolName);
53
+
54
+ if (!isWrite || !toolName) process.exit(0);
55
+
56
+ try {
57
+ const BCLAW_CMD = fs.existsSync(path.join(process.cwd(), 'node_modules', '.bin', 'brainclaw'))
58
+ ? 'npx brainclaw' : 'brainclaw';
59
+ const out = execSync(BCLAW_CMD + ' claim list --json', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'ignore'] });
60
+ const claims = JSON.parse(out);
61
+ if (claims && claims.length > 0) process.exit(0);
62
+ } catch (e) {
63
+ // ignore if brainclaw not found or fails
64
+ process.exit(0);
65
+ }
66
+
67
+ const sessionMark = path.join(process.cwd(), '.brainclaw', 'tmp', 'claude_warned');
68
+ if (!fs.existsSync(path.dirname(sessionMark))) fs.mkdirSync(path.dirname(sessionMark), { recursive: true });
69
+
70
+ if (fs.existsSync(sessionMark)) {
71
+ const mtime = fs.statSync(sessionMark).mtimeMs;
72
+ if (Date.now() - mtime < 2 * 60 * 60 * 1000) {
73
+ process.exit(0); // already warned this session
74
+ }
75
+ }
76
+ fs.writeFileSync(sessionMark, Date.now().toString());
77
+
78
+ process.stderr.write('\\n[Brainclaw] ⚠️ WARNING: You are about to use an Edit/Write tool (' + toolName + ') but you have NO active claim.\\n');
79
+ process.stderr.write('[Brainclaw] Consider running \\\`brainclaw claim create <scope>\\\` to lock your work and avoid conflicts.\\n\\n');
80
+ " 2>&1 || exit 0
81
81
  `;
82
82
  }
83
83
  function generatePostMergeScript() {
84
- return `#!/bin/sh
85
- # brainclaw post-merge hook
86
- # Auto-releases claims whose scope overlaps with files changed by the merge
87
- # Generated by: brainclaw install-hooks
88
-
89
- BCLAW_CMD=""
90
- if command -v brainclaw >/dev/null 2>&1; then
91
- BCLAW_CMD="brainclaw"
92
- elif command -v bclaw >/dev/null 2>&1; then
93
- BCLAW_CMD="bclaw"
94
- else
95
- BCLAW_CMD="npx --no brainclaw"
96
- fi
97
-
98
- $BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true
99
- $BCLAW_CMD worktree clean 2>/dev/null || true
84
+ return `#!/bin/sh
85
+ # brainclaw post-merge hook
86
+ # Auto-releases claims whose scope overlaps with files changed by the merge
87
+ # Generated by: brainclaw install-hooks
88
+
89
+ BCLAW_CMD=""
90
+ if command -v brainclaw >/dev/null 2>&1; then
91
+ BCLAW_CMD="brainclaw"
92
+ elif command -v bclaw >/dev/null 2>&1; then
93
+ BCLAW_CMD="bclaw"
94
+ else
95
+ BCLAW_CMD="npx --no brainclaw"
96
+ fi
97
+
98
+ $BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true
99
+ $BCLAW_CMD worktree clean 2>/dev/null || true
100
100
  `;
101
101
  }
102
102
  function findGitRoot(cwd) {
@@ -113,30 +113,30 @@ function findGitRoot(cwd) {
113
113
  function generateHookScript() {
114
114
  // Use node directly to avoid sh.exe pipe issues on Windows (SIGPIPE).
115
115
  // The script is a self-contained node -e that runs both checks.
116
- return `#!/bin/sh
117
- # brainclaw pre-commit hook — generated by brainclaw install-hooks
118
- # Runs via node to avoid sh.exe SIGPIPE issues on Windows.
119
- exec node -e "
120
- const { execSync } = require('child_process');
121
- const staged = execSync('git diff --cached --name-only', { encoding: 'utf-8' }).trim();
122
- if (!staged) process.exit(0);
123
-
124
- // Check 1: reject staged .brainclaw/ files
125
- const brainclawFiles = staged.split('\\\\n').filter(f => f.startsWith('.brainclaw/'));
126
- if (brainclawFiles.length > 0) {
127
- process.stderr.write('\\\\nbrainclaw: .brainclaw/ files are staged — blocked.\\\\n');
128
- brainclawFiles.forEach(f => process.stderr.write(' ' + f + '\\\\n'));
129
- process.stderr.write(' Fix: git reset HEAD .brainclaw/\\\\n\\\\n');
130
- process.exit(1);
131
- }
132
-
133
- // Check 2: active constraint violations
134
- try {
135
- execSync('brainclaw check-constraints --staged', { stdio: 'inherit' });
136
- } catch (e) {
137
- if (e.status) process.exit(e.status);
138
- }
139
- " 2>&1 || exit $?
116
+ return `#!/bin/sh
117
+ # brainclaw pre-commit hook — generated by brainclaw install-hooks
118
+ # Runs via node to avoid sh.exe SIGPIPE issues on Windows.
119
+ exec node -e "
120
+ const { execSync } = require('child_process');
121
+ const staged = execSync('git diff --cached --name-only', { encoding: 'utf-8' }).trim();
122
+ if (!staged) process.exit(0);
123
+
124
+ // Check 1: reject staged .brainclaw/ files
125
+ const brainclawFiles = staged.split('\\\\n').filter(f => f.startsWith('.brainclaw/'));
126
+ if (brainclawFiles.length > 0) {
127
+ process.stderr.write('\\\\nbrainclaw: .brainclaw/ files are staged — blocked.\\\\n');
128
+ brainclawFiles.forEach(f => process.stderr.write(' ' + f + '\\\\n'));
129
+ process.stderr.write(' Fix: git reset HEAD .brainclaw/\\\\n\\\\n');
130
+ process.exit(1);
131
+ }
132
+
133
+ // Check 2: active constraint violations
134
+ try {
135
+ execSync('brainclaw check-constraints --staged', { stdio: 'inherit' });
136
+ } catch (e) {
137
+ if (e.status) process.exit(e.status);
138
+ }
139
+ " 2>&1 || exit $?
140
140
  `;
141
141
  }
142
142
  //# sourceMappingURL=install-hooks.js.map
@@ -284,6 +284,7 @@ export function handleBclawLoop(options) {
284
284
  input: req.input,
285
285
  dispatch: req.dispatch,
286
286
  assignment_id: req.assignment_id,
287
+ claim_id: req.claim_id,
287
288
  actor,
288
289
  }, options.cwd);
289
290
  const newEvents = findNewLoopEvents(loop.id, beforeEvents, options.cwd);
@@ -309,6 +310,9 @@ export function handleBclawLoop(options) {
309
310
  : undefined,
310
311
  actor,
311
312
  caller_agent_id: req.agentId,
313
+ // pln#562 step 4 — a dispatched instance proves itself via its
314
+ // claim env; claim-bound slots reject same-named siblings.
315
+ caller_claim_id: process.env.BRAINCLAW_CLAIM_ID?.trim() || undefined,
312
316
  }, options.cwd);
313
317
  const newEvents = findNewLoopEvents(loop.id, beforeEvents, options.cwd);
314
318
  return successResponse('complete_turn', { loop, next_expected: computeNextExpected(loop) }, [loopArtifactEntry(loop.id), ...loopEventArtifacts(newEvents)], [sideEffectUpdate('loop', loop.id), ...loopEventSideEffects(newEvents)], [], Date.now() - startMs, summarizeLoop(loop));