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
@@ -10,6 +10,30 @@ import { parsePorcelainZ, isSystemDirtyPath } from './dirty-scope.js';
10
10
  function gitPath(p) {
11
11
  return p.replace(/\\/g, '/');
12
12
  }
13
+ /**
14
+ * can_45316d5c — sanitize a scope-derived slug into a valid git branch
15
+ * component (`git check-ref-format` rules). Scopes like `.github/workflows`
16
+ * produced `feat/.github-workflows`, which git rejects (component starting
17
+ * with a dot), failing the whole worktree creation.
18
+ *
19
+ * Rules covered: no leading dots/dashes, no trailing dots, no `..`, no
20
+ * `@{`, no control/space/`~^:?*[\\` characters, no trailing `.lock`.
21
+ */
22
+ export function sanitizeBranchComponent(raw, fallback = 'scope') {
23
+ let slug = raw
24
+ .replace(/[\s~^:?*[\]\\]/g, '-') // chars forbidden by check-ref-format
25
+ .replace(/@\{/g, '-') // reflog syntax
26
+ .replace(/\.\.+/g, '.') // no double dots
27
+ .replace(/[^a-zA-Z0-9._-]/g, '-') // conservative whitelist for the rest
28
+ .replace(/-+/g, '-') // collapse dashes
29
+ .replace(/^[.-]+/, '') // no leading dot/dash
30
+ .replace(/[.-]+$/, ''); // no trailing dot/dash
31
+ if (/\.lock$/i.test(slug))
32
+ slug = slug.slice(0, -'.lock'.length);
33
+ if (!slug)
34
+ slug = fallback;
35
+ return slug.slice(0, 48);
36
+ }
13
37
  /**
14
38
  * Stack marker → shared directories mapping.
15
39
  * Maven/Gradle/Cargo intentionally excluded — their dep caches live
@@ -138,7 +162,15 @@ function canonicalizeScopePath(target) {
138
162
  * project even when two projects share the same repo name.
139
163
  */
140
164
  export function worktreesBaseDir(mainWorktreePath) {
141
- const hash = crypto.createHash('sha1').update(mainWorktreePath).digest('hex').slice(0, 12);
165
+ let stablePath = path.resolve(mainWorktreePath);
166
+ try {
167
+ stablePath = fs.realpathSync.native(stablePath);
168
+ }
169
+ catch { /* path may not exist yet; path.resolve is still deterministic */ }
170
+ if (process.platform === 'win32' || /^[a-zA-Z]:[\\/]/.test(mainWorktreePath)) {
171
+ stablePath = stablePath.toLowerCase();
172
+ }
173
+ const hash = crypto.createHash('sha1').update(stablePath).digest('hex').slice(0, 12);
142
174
  return path.join(os.homedir(), '.brainclaw', 'worktrees', hash);
143
175
  }
144
176
  /**
@@ -244,7 +276,7 @@ export function commitWorktreeOnBehalf(worktreePath, message, options = {}) {
244
276
  if (!add.ok) {
245
277
  return { committed: false, files_changed: [], reason: `git add failed: ${add.stderr.trim()}` };
246
278
  }
247
- runGit(['reset', '-q', '--', 'LANE-RESULT.json', '.brainclaw'], worktreePath);
279
+ runGit(['reset', '-q', '--', 'LANE-RESULT.json', '.brainclaw', '.brainclaw-heartbeat-*'], worktreePath);
248
280
  // The files actually staged for this commit (post-exclusion) — also the
249
281
  // truthful files_changed report.
250
282
  const staged = runGit(['diff', '--cached', '--name-only'], worktreePath);
@@ -320,6 +352,7 @@ export function resetWorktreeToRef(worktreePath, ref) {
320
352
  const norm = p.replace(/\\/g, '/');
321
353
  return norm !== '.brainclaw-worktree.json'
322
354
  && !norm.startsWith('.brainclaw/')
355
+ && !norm.startsWith('.brainclaw-heartbeat-')
323
356
  && !norm.startsWith('.git/');
324
357
  });
325
358
  if (residue.length > 0) {
@@ -420,14 +453,42 @@ export function createWorktree(mainWorktreePath, branchName, options = {}) {
420
453
  const branchCheck = runGit(['rev-parse', '--verify', branchName], mainWorktreePath);
421
454
  const branchExists = branchCheck.ok;
422
455
  const baseRef = options.baseRef ?? 'HEAD';
423
- if (branchExists && options.resetExistingBranch) {
456
+ if (branchExists) {
424
457
  const attachedWorktreePath = findWorktreePathForBranch(listWorktrees(mainWorktreePath), branchName);
425
458
  if (attachedWorktreePath) {
426
- throw new Error(`Cannot reset branch ${branchName}: it is checked out in worktree ${attachedWorktreePath}. Remove or merge that worktree first.`);
459
+ throw new Error(`Cannot reuse branch ${branchName}: it is checked out in worktree ${attachedWorktreePath}. Remove or merge that worktree first.`);
427
460
  }
428
- const reset = runGit(['branch', '--force', branchName, baseRef], mainWorktreePath);
429
- if (!reset.ok) {
430
- throw new Error(`git branch --force failed for ${branchName}: ${reset.stderr.trim()}`);
461
+ if (options.resetExistingBranch) {
462
+ const reset = runGit(['branch', '--force', branchName, baseRef], mainWorktreePath);
463
+ if (!reset.ok) {
464
+ throw new Error(`git branch --force failed for ${branchName}: ${reset.stderr.trim()}`);
465
+ }
466
+ }
467
+ else {
468
+ // can_2e282880 (worktree-as-contract at creation): a reused branch is a
469
+ // CONTRACT that the worker starts from the dispatch base, not from
470
+ // whatever stale base the branch happened to sit on (observed live: a
471
+ // June dispatch reused a feat/<scope> branch based on April master).
472
+ // - branch has NO commits ahead of the base → silently re-point it to
473
+ // the base (it carries nothing worth keeping);
474
+ // - branch HAS commits not on the base → REFUSE and name them: they
475
+ // are unharvested work — merging/harvesting first is the only safe
476
+ // move, a silent reset would destroy it and a silent reuse would
477
+ // run the worker on a stale base.
478
+ const ahead = runGit(['rev-list', '--count', `${baseRef}..${branchName}`], mainWorktreePath);
479
+ const aheadCount = ahead.ok ? parseInt(ahead.stdout.trim(), 10) : NaN;
480
+ if (!Number.isFinite(aheadCount)) {
481
+ throw new Error(`Cannot assess divergence of existing branch ${branchName} vs ${baseRef}: ${ahead.stderr.trim()}`);
482
+ }
483
+ if (aheadCount > 0) {
484
+ const commits = runGit(['log', '--oneline', '-n', '5', `${baseRef}..${branchName}`], mainWorktreePath);
485
+ throw new Error(`Refusing to reuse branch ${branchName}: it has ${aheadCount} commit(s) not on ${baseRef} (unharvested work). ` +
486
+ `Harvest/merge or delete the branch first. Divergent commits:\n${commits.stdout.trim()}`);
487
+ }
488
+ const reset = runGit(['branch', '--force', branchName, baseRef], mainWorktreePath);
489
+ if (!reset.ok) {
490
+ throw new Error(`git branch --force failed for ${branchName}: ${reset.stderr.trim()}`);
491
+ }
431
492
  }
432
493
  }
433
494
  // Use forward-slash paths for git on Windows
@@ -512,24 +573,24 @@ export const WORKTREE_HOOKS_DIRNAME = '.brainclaw-hooks';
512
573
  * blocking — a tooling gap must not trap a worker.
513
574
  */
514
575
  export function buildTypecheckPreCommitScript() {
515
- return `#!/bin/sh
516
- # brainclaw worktree typecheck gate (pln#479) — do not edit manually.
517
- # Blocks the commit when 'tsc --noEmit' fails. Bypass: git commit --no-verify.
518
- exec node -e "
519
- const fs = require('fs');
520
- const { execSync } = require('child_process');
521
- if (!fs.existsSync('tsconfig.json')) process.exit(0);
522
- if (!fs.existsSync('node_modules/typescript/bin/tsc')) {
523
- process.stderr.write('\\\\n[brainclaw] typecheck gate: typescript not found in worktree node_modules — skipping (commit allowed).\\\\n');
524
- process.exit(0);
525
- }
526
- try {
527
- execSync('node node_modules/typescript/bin/tsc --noEmit', { stdio: 'inherit' });
528
- } catch (e) {
529
- process.stderr.write('\\\\n[brainclaw] commit blocked: tsc --noEmit reported type errors (above). Fix them, or bypass with: git commit --no-verify\\\\n\\\\n');
530
- process.exit(1);
531
- }
532
- " 2>&1 || exit $?
576
+ return `#!/bin/sh
577
+ # brainclaw worktree typecheck gate (pln#479) — do not edit manually.
578
+ # Blocks the commit when 'tsc --noEmit' fails. Bypass: git commit --no-verify.
579
+ exec node -e "
580
+ const fs = require('fs');
581
+ const { execSync } = require('child_process');
582
+ if (!fs.existsSync('tsconfig.json')) process.exit(0);
583
+ if (!fs.existsSync('node_modules/typescript/bin/tsc')) {
584
+ process.stderr.write('\\\\n[brainclaw] typecheck gate: typescript not found in worktree node_modules — skipping (commit allowed).\\\\n');
585
+ process.exit(0);
586
+ }
587
+ try {
588
+ execSync('node node_modules/typescript/bin/tsc --noEmit', { stdio: 'inherit' });
589
+ } catch (e) {
590
+ process.stderr.write('\\\\n[brainclaw] commit blocked: tsc --noEmit reported type errors (above). Fix them, or bypass with: git commit --no-verify\\\\n\\\\n');
591
+ process.exit(1);
592
+ }
593
+ " 2>&1 || exit $?
533
594
  `;
534
595
  }
535
596
  /**
@@ -817,7 +878,10 @@ export function worktreeHasOnlyBirthNoise(statusZStdout) {
817
878
  const paths = parsePorcelainZ(statusZStdout);
818
879
  return paths.every((p) => {
819
880
  const norm = p.replace(/\\/g, '/');
820
- return WORKTREE_BIRTH_NOISE.has(norm) || isSystemDirtyPath(norm);
881
+ return WORKTREE_BIRTH_NOISE.has(norm)
882
+ || norm.startsWith('.brainclaw-heartbeat-') // worker liveness sentinel (sprint 1.5)
883
+ || norm === 'LANE-RESULT.json' // worker outcome report — harvested, never committed
884
+ || isSystemDirtyPath(norm);
821
885
  });
822
886
  }
823
887
  /**
package/dist/facts.js CHANGED
@@ -1,8 +1,8 @@
1
1
  // Generated by scripts/emit-site-facts.mjs at build time. Do not edit manually.
2
- // Source: brainclaw v1.8.0 on 2026-06-09T07:31:59.599Z
2
+ // Source: brainclaw v1.9.1 on 2026-06-18T15:15:04.496Z
3
3
  export const FACTS = {
4
- "version": "1.8.0",
5
- "generated_at": "2026-06-09T07:31:59.599Z",
4
+ "version": "1.9.1",
5
+ "generated_at": "2026-06-18T15:15:04.496Z",
6
6
  "tools": {
7
7
  "count": 62,
8
8
  "published_count": 61,
@@ -197,8 +197,8 @@ export const FACTS = {
197
197
  "workflow_model": "interactive",
198
198
  "tier": "A",
199
199
  "has_mcp": true,
200
- "has_hooks": true,
201
- "has_skills": true,
200
+ "has_hooks": false,
201
+ "has_skills": false,
202
202
  "has_rules": true,
203
203
  "instruction_file": ".clinerules/brainclaw.md",
204
204
  "mcp_config_scope": "project",
@@ -214,7 +214,7 @@ export const FACTS = {
214
214
  "workflow_model": "task-based",
215
215
  "tier": "A",
216
216
  "has_mcp": true,
217
- "has_hooks": true,
217
+ "has_hooks": false,
218
218
  "has_skills": true,
219
219
  "has_rules": true,
220
220
  "instruction_file": "AGENTS.md",
@@ -436,8 +436,8 @@ export const FACTS = {
436
436
  "workflow_model": "interactive",
437
437
  "tier": "A",
438
438
  "has_mcp": true,
439
- "has_hooks": true,
440
- "has_skills": true,
439
+ "has_hooks": false,
440
+ "has_skills": false,
441
441
  "has_rules": true,
442
442
  "instruction_file": ".windsurfrules",
443
443
  "mcp_config_scope": "machine",
package/dist/facts.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
- "version": "1.8.0",
3
- "generated_at": "2026-06-09T07:31:59.599Z",
2
+ "version": "1.9.1",
3
+ "generated_at": "2026-06-18T15:15:04.496Z",
4
4
  "tools": {
5
5
  "count": 62,
6
6
  "published_count": 61,
@@ -195,8 +195,8 @@
195
195
  "workflow_model": "interactive",
196
196
  "tier": "A",
197
197
  "has_mcp": true,
198
- "has_hooks": true,
199
- "has_skills": true,
198
+ "has_hooks": false,
199
+ "has_skills": false,
200
200
  "has_rules": true,
201
201
  "instruction_file": ".clinerules/brainclaw.md",
202
202
  "mcp_config_scope": "project",
@@ -212,7 +212,7 @@
212
212
  "workflow_model": "task-based",
213
213
  "tier": "A",
214
214
  "has_mcp": true,
215
- "has_hooks": true,
215
+ "has_hooks": false,
216
216
  "has_skills": true,
217
217
  "has_rules": true,
218
218
  "instruction_file": "AGENTS.md",
@@ -434,8 +434,8 @@
434
434
  "workflow_model": "interactive",
435
435
  "tier": "A",
436
436
  "has_mcp": true,
437
- "has_hooks": true,
438
- "has_skills": true,
437
+ "has_hooks": false,
438
+ "has_skills": false,
439
439
  "has_rules": true,
440
440
  "instruction_file": ".windsurfrules",
441
441
  "mcp_config_scope": "machine",
@@ -0,0 +1,223 @@
1
+ # Brainclaw Protocol — v0.1 (draft)
2
+
3
+ > Status: **draft** — pre-public RFC. Versioned in [docs/PROTOCOL.md](./PROTOCOL.md);
4
+ > brainclaw is the reference implementation.
5
+ >
6
+ > Feedback target: external OSS agent integrators (Cline, OpenCode, Hermes,
7
+ > Mistral Vibe, Continue) — see "Feedback wanted" at the bottom.
8
+
9
+ ## 1. What this spec is
10
+
11
+ Brainclaw runs a multi-agent coordination loop on top of a shared project
12
+ memory. The implementation has converged on a small grammar — entities, verbs,
13
+ lifecycle sentinels — that the rest of the system (CLI, MCP server, writers,
14
+ hooks) is just a delivery channel for.
15
+
16
+ This document carves out that grammar as a **transport-agnostic protocol** so
17
+ other agents and agent platforms can either:
18
+
19
+ - speak it natively (via brainclaw's MCP server, the reference transport), or
20
+ - implement it themselves and interoperate with brainclaw-managed projects.
21
+
22
+ The protocol does **not** standardize storage, file layouts, or the internal
23
+ state machine. Those are implementation details; brainclaw's are documented
24
+ under [`docs/concepts/`](./concepts/).
25
+
26
+ ## 2. Versioning
27
+
28
+ | Field | Rule |
29
+ |-------------------|-------------------------------------------------------------------------|
30
+ | `protocol.major` | Bumped only for breaking entity / verb / sentinel changes. |
31
+ | `protocol.minor` | Bumped for additive entities, verbs, sentinels, or new optional fields. |
32
+ | `protocol.patch` | Editorial / clarifying changes; no behavioral impact. |
33
+
34
+ Current draft: **0.1** — entity surface stable; verb surface stable on the
35
+ "canonical grammar" (see §4); lifecycle sentinels stable for sessions, claims,
36
+ plans, assignments. Coordination / loop verbs are explicitly experimental.
37
+
38
+ Implementers SHOULD advertise the maximum supported version via an
39
+ `X-Brainclaw-Protocol` header (HTTP transports) or a server-info field
40
+ (MCP transports). Brainclaw's MCP server returns `0.1` in `serverInfo.version`.
41
+
42
+ ## 3. Entities
43
+
44
+ The protocol recognises eight kinds of memory objects. Each has a unique `id`,
45
+ a canonical `kind`, and a small set of mutable fields. Storage of additional
46
+ fields is implementation-defined.
47
+
48
+ | Kind | Purpose | Lifecycle states |
49
+ |--------------|----------------------------------------------------------------------|---------------------------------------------------------|
50
+ | `constraint` | Active rule the project must respect. | `active` → `resolved` / `expired` |
51
+ | `decision` | Recorded architectural / process decision. | `pending` → `approved` / `rejected` / `deferred` |
52
+ | `trap` | Known failure mode; reminder for future work. | `active` → `resolved` / `expired` |
53
+ | `plan` | Unit of work tracked across agents. | `open` → `in_progress` → `done` / `cancelled` |
54
+ | `claim` | Mutex over a file scope. | `open` → `released` (or `expired` via TTL) |
55
+ | `handoff` | Asynchronous instruction from one agent to another. | `open` → `accepted` → `closed` |
56
+ | `candidate` | Proposed memory item awaiting review. | `proposed` → `accepted` / `rejected` / `merged` |
57
+ | `assignment` | Dispatched work item routed to a specific agent. | `offered` → `accepted` → `started` → `completed` / `failed` / `blocked` / `cancelled` |
58
+
59
+ Entities have these well-known fields (implementations MAY add more):
60
+
61
+ ```
62
+ id string // implementation-assigned, opaque, stable
63
+ kind string // one of the kinds above
64
+ status string // one of the lifecycle states above
65
+ text string? // human-readable summary
66
+ tags string[]?
67
+ created_at string // ISO-8601 UTC
68
+ updated_at string // ISO-8601 UTC
69
+ provenance object? // {kind: 'agent'|'human'|'auto'|'legacy', author, source}
70
+ ```
71
+
72
+ Brainclaw's full field set lives in [`src/core/schema.ts`](../src/core/schema.ts).
73
+ Future protocol minors will promote additional fields to "well-known" as they
74
+ prove portable across implementations.
75
+
76
+ ## 4. The canonical grammar (verbs)
77
+
78
+ The protocol exposes seven canonical verbs. Implementations MUST support these
79
+ in order to claim protocol compliance. They are deliberately narrow so the
80
+ surface stays small; richer ergonomic helpers are facades on top.
81
+
82
+ | Verb | Shape | Effect |
83
+ |-------------------|-----------------------------------------------------------------|---------------------------------------------------------|
84
+ | `work(intent)` | `intent: consult \| execute \| resume \| review` | Open a session; optionally claim a scope. |
85
+ | `context(kind)` | `kind: memory \| execution \| board \| delta` | Read shared state. |
86
+ | `find(entity, …)` | `entity, filter, limit` | Query entities. |
87
+ | `get(entity, id)` | `entity, id` (or `short_label`) | Fetch one entity by identifier. |
88
+ | `create(entity)` | `entity, data` | Insert a new entity (validated against schema). |
89
+ | `update(entity)` | `entity, id, patch` | Patch mutable fields. Status changes go via `transition`. |
90
+ | `transition(…)` | `entity, id, status` | Move an entity along its lifecycle. Triggers side-effects. |
91
+
92
+ The reference implementation surfaces these as MCP tools named
93
+ `bclaw_work`, `bclaw_context`, `bclaw_find`, `bclaw_get`, `bclaw_create`,
94
+ `bclaw_update`, `bclaw_transition`. The same names appear in
95
+ `src/commands/mcp.ts:MCP_CANONICAL_GRAMMAR_TOOL_NAMES` and are derived from
96
+ the tool catalog, not hand-curated. Hermes and other narrow-surface agents
97
+ include exactly this set in their MCP `tools.include`.
98
+
99
+ ### 4.1 Coordination verbs (experimental — protocol v0.2 candidates)
100
+
101
+ These are present in the reference implementation but **not yet stable**.
102
+ Implementations MAY support them but should expect breaking changes:
103
+
104
+ - `coordinate(intent: assign|consult|review|reroute)` — multi-agent routing.
105
+ - `dispatch(plan, agents)` — concrete spawn / claim ledger.
106
+ - `loop(kind: ideation|implementation|review)` — multi-round loops.
107
+
108
+ ## 5. Lifecycle sentinels
109
+
110
+ The protocol defines **named state transitions** so any compliant agent can
111
+ reason about another's progress without parsing free-form text. These are the
112
+ strings agents are expected to emit at protocol-defined moments.
113
+
114
+ ### 5.1 Session sentinels
115
+
116
+ | Moment | Sentinel |
117
+ |-----------------------|-----------------------------------------------------------------------|
118
+ | Agent reaches its loop | Filesystem heartbeat: `.brainclaw-heartbeat-<assignment_id>` |
119
+ | Session opens | `work(intent)` response carries the `session_id` and seed context. |
120
+ | Session ends | `work(intent: …)` is terminal; or implementation-specific close call. |
121
+
122
+ ### 5.2 Assignment sentinels
123
+
124
+ The lifecycle a coordinator can observe on a dispatched assignment:
125
+
126
+ ```
127
+ offered → accepted → started → (progress)* → completed
128
+ | failed
129
+ | blocked
130
+ | cancelled
131
+ ```
132
+
133
+ Each transition is emitted via `transition('assignment', id, <status>)`.
134
+ A worker that cannot reach the protocol transport (sandboxed) MAY drop a
135
+ `LANE-RESULT.json` file at the worktree root as the fallback signal — the
136
+ coordinator harvests it.
137
+
138
+ ### 5.3 Claim sentinels
139
+
140
+ ```
141
+ open → released (worker calls transition('claim', id, 'released'))
142
+ open → expired (TTL-driven; reaper marks expired)
143
+ ```
144
+
145
+ A claim that converged on `done` MAY carry a `planStatus` hint so the
146
+ coordinator updates the linked plan atomically with the release.
147
+
148
+ ### 5.4 Plan-step sentinels
149
+
150
+ Plans contain ordered steps with their own status. The grammar verbs
151
+ `update('plan', id, {steps:[…]})` and `transition('plan', id, 'done')`
152
+ operate over the whole plan; the canonical step sentinel is a step-level
153
+ `status: done`. Implementations MAY surface `bclaw_complete_step` as a
154
+ sugar on top.
155
+
156
+ ## 6. Conformance levels
157
+
158
+ | Level | What conformance means |
159
+ |-------|----------------------------------------------------------------------------------------|
160
+ | **L1 — Read** | Implementation can issue `work(intent: consult)` + `context` + `find` + `get` and respect active claims. Minimum bar for "I can run inside a brainclaw-managed project without breaking it." |
161
+ | **L2 — Write** | All of L1 plus `create` / `update` / `transition` on the entities above with valid lifecycle transitions. |
162
+ | **L3 — Coordinate** | All of L2 plus the experimental coordination verbs (§4.1) and assignment sentinels. Required for spawning / accepting dispatched work. |
163
+
164
+ Hermes and Mistral Vibe ship at L1 (narrow surface). Claude Code, Codex,
165
+ Copilot, and Cline are L3. The reference implementation enforces the
166
+ L3 contract via assignment-convergence tests (see
167
+ [`tests/unit/assignment-convergence.test.ts`](../tests/unit/assignment-convergence.test.ts)).
168
+
169
+ ## 7. Transport bindings
170
+
171
+ The protocol is transport-agnostic. The reference implementation ships an
172
+ MCP server (`brainclaw mcp`); other implementations MAY add JSON-RPC over
173
+ stdio, HTTP, or a local IPC socket without changing the entity / verb /
174
+ sentinel surface.
175
+
176
+ A transport binding MUST specify:
177
+
178
+ - how the seven canonical verbs are named (mapping to the binding's call shape),
179
+ - how entity identifiers are serialised (recommend opaque strings),
180
+ - how lifecycle sentinels are encoded (recommend `transition` calls,
181
+ not free-form status strings).
182
+
183
+ ## 8. Storage and federation
184
+
185
+ Out of scope for v0.1. The reference implementation uses git-backed
186
+ JSON/YAML in `.brainclaw/`. Multi-project federation is a planned
187
+ extension — see [docs/concepts/](./concepts/) and the brainclaw memory
188
+ files for the current direction. A future protocol version will define
189
+ the wire format for cross-project signaling.
190
+
191
+ ## 9. Reference implementation map
192
+
193
+ | Protocol concept | Reference implementation in brainclaw |
194
+ |-------------------------------|-----------------------------------------------------------------------|
195
+ | Entity schemas | [`src/core/schema.ts`](../src/core/schema.ts) |
196
+ | Canonical grammar tool set | [`src/commands/mcp.ts`](../src/commands/mcp.ts) — `MCP_CANONICAL_GRAMMAR_TOOL_NAMES` |
197
+ | MCP tool catalog | [`src/commands/mcp.ts`](../src/commands/mcp.ts) — `ALL_TOOLS` |
198
+ | Per-agent writer wiring | [`src/core/agent-files.ts`](../src/core/agent-files.ts) — `AGENT_WIRING_REGISTRY` |
199
+ | Capability profiles | [`src/core/agent-capability.ts`](../src/core/agent-capability.ts) |
200
+ | Assignment lifecycle | [`src/core/assignments.ts`](../src/core/assignments.ts) + [`tests/unit/assignment-convergence.test.ts`](../tests/unit/assignment-convergence.test.ts) |
201
+ | Claim lifecycle / TTL | [`src/core/claims.ts`](../src/core/claims.ts) |
202
+
203
+ ## 10. Feedback wanted
204
+
205
+ The following questions are open for v0.2. We're soliciting input from agent
206
+ integrators before declaring any of them stable:
207
+
208
+ 1. **Coordination verb shape (§4.1)** — should `coordinate(intent: assign|…)`
209
+ stay as a single verb with an intent enum, or split into named verbs
210
+ (`assign`, `reroute`, `review_request`) per L3 capability?
211
+ 2. **Sentinel transport for sandboxed workers** — the `LANE-RESULT.json`
212
+ fallback file is brainclaw-specific. Is there an interest in
213
+ standardising a "filesystem fallback" format so any coordinator can
214
+ harvest results from any sandboxed worker?
215
+ 3. **Entity field portability** — which fields beyond the well-known set
216
+ (§3) are universal enough to promote in v0.2? Candidates: `severity`,
217
+ `priority`, `category`, `effort_minutes`, `assignee`.
218
+ 4. **L1-only adoption surface** — would a CLI-only L1 reference (no MCP
219
+ dependency) lower the adoption bar for OSS agents that don't speak MCP
220
+ yet?
221
+
222
+ Open an issue, ping `support@brainclaw.dev`, or comment on the brainclaw plan
223
+ tracking this draft (pln#546).
@@ -1,43 +1,43 @@
1
- # OpenClaw Adapter Guide
2
-
3
- This adapter helps convert OpenClaw runtime traces into brainclaw candidates.
4
-
5
- ## Supported Inputs
6
-
7
- - Runtime event file: JSON array of events.
8
- - Runtime session import: events filtered by `metadata.session` from `.brainclaw/runtime/`.
9
-
10
- ## Basic Usage
11
-
12
- ```bash
13
- brainclaw adapter-openclaw-import ./openclaw-events.json
14
- brainclaw adapter-openclaw-import --session sess_42
15
- ```
16
-
17
- ## Dry-Run Workflow
18
-
19
- Use `--dry-run` to preview what would be ingested without writing any files:
20
-
21
- ```bash
22
- brainclaw adapter-openclaw-import ./openclaw-events.json --dry-run
23
- ```
24
-
25
- Dry-run is useful for CI checks and for validating mapping quality before modifying `.brainclaw/inbox/`.
26
-
27
- ## Event Mapping
28
-
29
- Current mapping converts events into reflective candidate types:
30
-
31
- - `risk_detected` -> `trap`
32
- - `handoff_requested` -> `handoff`
33
- - `observation` -> `decision`
34
- - `constraint_detected` -> `constraint`
35
-
36
- If an event type is unknown, it defaults to `decision`.
37
-
38
- ## Recommended Team Flow
39
-
40
- 1. Import events from file or session.
41
- 2. Run `brainclaw review --prioritized`.
42
- 3. Curators process with `brainclaw accept` or `brainclaw reject`.
43
- 4. Use `brainclaw doctor` or `brainclaw doctor --json` to monitor quality.
1
+ # OpenClaw Adapter Guide
2
+
3
+ This adapter helps convert OpenClaw runtime traces into brainclaw candidates.
4
+
5
+ ## Supported Inputs
6
+
7
+ - Runtime event file: JSON array of events.
8
+ - Runtime session import: events filtered by `metadata.session` from `.brainclaw/runtime/`.
9
+
10
+ ## Basic Usage
11
+
12
+ ```bash
13
+ brainclaw adapter-openclaw-import ./openclaw-events.json
14
+ brainclaw adapter-openclaw-import --session sess_42
15
+ ```
16
+
17
+ ## Dry-Run Workflow
18
+
19
+ Use `--dry-run` to preview what would be ingested without writing any files:
20
+
21
+ ```bash
22
+ brainclaw adapter-openclaw-import ./openclaw-events.json --dry-run
23
+ ```
24
+
25
+ Dry-run is useful for CI checks and for validating mapping quality before modifying `.brainclaw/inbox/`.
26
+
27
+ ## Event Mapping
28
+
29
+ Current mapping converts events into reflective candidate types:
30
+
31
+ - `risk_detected` -> `trap`
32
+ - `handoff_requested` -> `handoff`
33
+ - `observation` -> `decision`
34
+ - `constraint_detected` -> `constraint`
35
+
36
+ If an event type is unknown, it defaults to `decision`.
37
+
38
+ ## Recommended Team Flow
39
+
40
+ 1. Import events from file or session.
41
+ 2. Run `brainclaw review --prioritized`.
42
+ 3. Curators process with `brainclaw accept` or `brainclaw reject`.
43
+ 4. Use `brainclaw doctor` or `brainclaw doctor --json` to monitor quality.