brainclaw 0.24.0 → 0.25.3

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.
package/dist/cli.js CHANGED
@@ -963,6 +963,7 @@ program
963
963
  .description('Export memory as instructions for IDE/AI tools')
964
964
  .option('--format <format>', 'Format: copilot-instructions, cursor-rules, agents-md, claude-md, gemini-md, windsurf, cline, roo, continue')
965
965
  .option('--detect', 'Auto-detect agent environment and write to its native file')
966
+ .option('--all', 'Write all known agent instruction files at once (claude-md, agents-md, copilot-instructions, cursor-rules, etc.)')
966
967
  .option('--write', 'Write to canonical file path instead of stdout (when --format is given); local files are gitignored by default')
967
968
  .option('--shared', 'Keep the main exported instruction file versionable instead of auto-ignoring it (companions remain local)')
968
969
  .option('--output <file>', 'Write to a specific file path instead of stdout')
@@ -5,7 +5,7 @@ import { saveClaim, generateClaimId, listClaims } from '../core/claims.js';
5
5
  import { rebuildProjectMd } from '../core/markdown.js';
6
6
  import { loadState, saveState } from '../core/state.js';
7
7
  import { nowISO } from '../core/ids.js';
8
- import { requireMinimumTrustLevel, requireRegisteredAgentIdentity } from '../core/agent-registry.js';
8
+ import { requireMinimumTrustLevel, requireRegisteredAgentIdentity, resolveCurrentModel } from '../core/agent-registry.js';
9
9
  import { validateCliTtl } from '../core/input-validation.js';
10
10
  import { resolveTargetStore } from '../core/store-resolution.js';
11
11
  function parseTtl(ttl) {
@@ -72,6 +72,7 @@ export function runClaim(description, options) {
72
72
  plan_id: options.plan,
73
73
  status: 'active',
74
74
  expires_at: options.ttl ? parseTtl(options.ttl) : undefined,
75
+ model: resolveCurrentModel(options.cwd),
75
76
  };
76
77
  mutate({ cwd: options.cwd }, () => {
77
78
  if (plan) {
@@ -1,5 +1,14 @@
1
1
  import { buildContextDiff, resolveContextDiffSince } from '../core/context-diff.js';
2
+ import { listClaims, isClaimExpired } from '../core/claims.js';
3
+ import { loadInstructions, resolveInstructions } from '../core/instructions.js';
2
4
  import { memoryExists } from '../core/io.js';
5
+ import { loadState } from '../core/state.js';
6
+ import { isTrapActive } from '../core/traps.js';
7
+ /**
8
+ * Hybrid context-diff: always includes critical anchors (active claims,
9
+ * top traps, instructions) so the agent stays grounded, plus the memory
10
+ * delta since last context read.
11
+ */
3
12
  export function runContextDiff(options = {}) {
4
13
  if (!memoryExists(options.cwd)) {
5
14
  console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
@@ -20,13 +29,62 @@ export function runContextDiff(options = {}) {
20
29
  process.exit(1);
21
30
  }
22
31
  if (options.json) {
23
- console.log(JSON.stringify(diff, null, 2));
32
+ const anchors = buildCriticalAnchors(options.cwd);
33
+ console.log(JSON.stringify({ ...diff, anchors }, null, 2));
24
34
  return;
25
35
  }
36
+ const lines = [];
37
+ // --- Critical anchors (always present) ---
38
+ const anchors = buildCriticalAnchors(options.cwd);
39
+ if (anchors.claims.length > 0) {
40
+ lines.push('Active claims:');
41
+ for (const c of anchors.claims) {
42
+ lines.push(`- [${c.id}] ${c.agent} → ${c.scope}: ${c.description}`);
43
+ }
44
+ lines.push('');
45
+ }
46
+ if (anchors.instructions.length > 0) {
47
+ lines.push('Instructions:');
48
+ for (const ins of anchors.instructions) {
49
+ const scope = ins.scope ? `:${ins.scope}` : '';
50
+ lines.push(`- [${ins.id}] <${ins.layer}${scope}> ${ins.text}`);
51
+ }
52
+ lines.push('');
53
+ }
54
+ if (anchors.traps.length > 0) {
55
+ lines.push('Active traps:');
56
+ for (const t of anchors.traps) {
57
+ lines.push(`- [${t.id}] (${t.severity}) ${t.text}`);
58
+ }
59
+ lines.push('');
60
+ }
61
+ // --- Memory delta ---
26
62
  if (diff.counts.total === 0) {
27
- console.log(`${diff.summary} since ${diff.since}.`);
28
- return;
63
+ lines.push(`Memory: no changes since ${diff.since?.slice(0, 16).replace('T', ' ')}.`);
29
64
  }
30
- console.log(`${diff.summary} since ${diff.since}.`);
65
+ else {
66
+ lines.push(`Memory delta (${diff.summary}):`);
67
+ for (const item of diff.changed_items ?? []) {
68
+ lines.push(`- [${item.section}] [${item.id}] ${item.text}`);
69
+ }
70
+ }
71
+ console.log(lines.join('\n'));
72
+ }
73
+ function buildCriticalAnchors(cwd) {
74
+ const activeClaims = listClaims(cwd)
75
+ .filter((c) => c.status === 'active' && !isClaimExpired(c))
76
+ .map((c) => ({ id: c.id, agent: c.agent, scope: c.scope, description: c.description }));
77
+ const instructions = resolveInstructions(loadInstructions(cwd))
78
+ .map((ins) => ({ id: ins.id, layer: ins.layer, scope: ins.scope, text: ins.text }));
79
+ const state = loadState(cwd);
80
+ const traps = state.known_traps
81
+ .filter((t) => isTrapActive(t))
82
+ .sort((a, b) => {
83
+ const severityOrder = { high: 0, medium: 1, low: 2 };
84
+ return (severityOrder[a.severity] ?? 1) - (severityOrder[b.severity] ?? 1);
85
+ })
86
+ .slice(0, 5)
87
+ .map((t) => ({ id: t.id, severity: t.severity, text: t.text }));
88
+ return { claims: activeClaims, instructions, traps };
31
89
  }
32
90
  //# sourceMappingURL=context-diff.js.map
@@ -6,7 +6,7 @@ import { loadConfig, saveConfig } from '../core/config.js';
6
6
  import { isAgentIntegrationName, upsertAgentIntegrationDeclaration } from '../core/agent-integrations.js';
7
7
  import { resolveInstructions, loadInstructions } from '../core/instructions.js';
8
8
  import { detectAiAgent } from '../core/ai-agent-detection.js';
9
- import { resolveExportTarget, resolveExportTargetByFormat, writeExportFile, buildHygieneSection, describeAutoConfigWrite, writeExportCompanionFiles, collectExportGitignoreEntries, ensureGitignoreEntries, } from '../core/agent-files.js';
9
+ import { AGENT_EXPORT_REGISTRY, resolveExportTarget, resolveExportTargetByFormat, writeExportFile, buildHygieneSection, describeAutoConfigWrite, writeExportCompanionFiles, collectExportGitignoreEntries, ensureGitignoreEntries, } from '../core/agent-files.js';
10
10
  import { logger } from '../core/logger.js';
11
11
  import { getAgentCapabilityProfile } from '../core/agent-capability.js';
12
12
  import { renderBrainclawSection } from '../core/instruction-templates.js';
@@ -17,6 +17,10 @@ export function runExport(options) {
17
17
  console.error('Error: .brainclaw/ not found. Run `brainclaw init` first.');
18
18
  process.exit(1);
19
19
  }
20
+ if (options.all) {
21
+ runExportAll(cwd, options);
22
+ return;
23
+ }
20
24
  if (options.detect) {
21
25
  if (options.shared) {
22
26
  console.error('Error: --shared cannot be used with --detect. Use `brainclaw export --format <format> --write --shared` to publish a specific instruction file.');
@@ -26,7 +30,7 @@ export function runExport(options) {
26
30
  return;
27
31
  }
28
32
  if (!options.format) {
29
- console.error('Error: --format or --detect is required.');
33
+ console.error('Error: --format, --detect, or --all is required.');
30
34
  process.exit(1);
31
35
  }
32
36
  const content = generateExport(options.format, options, cwd);
@@ -90,6 +94,40 @@ function runExportDetect(cwd, options) {
90
94
  }
91
95
  }
92
96
  }
97
+ function runExportAll(cwd, options) {
98
+ // Deduplicate by format (e.g. codex and opencode both use agents-md)
99
+ const seen = new Set();
100
+ const targets = AGENT_EXPORT_REGISTRY.filter((t) => {
101
+ if (seen.has(t.format))
102
+ return false;
103
+ seen.add(t.format);
104
+ return true;
105
+ });
106
+ let written = 0;
107
+ const allGitignoreEntries = [];
108
+ for (const target of targets) {
109
+ try {
110
+ const content = generateExport(target.format, options, cwd);
111
+ const result = writeExportFile(content, target.relativePath, cwd);
112
+ const autoConfigs = writeExportCompanionFiles(target.format, cwd);
113
+ const gitignoreEntries = collectExportGitignoreEntries(cwd, target.relativePath, autoConfigs);
114
+ allGitignoreEntries.push(...gitignoreEntries);
115
+ declareAgentIntegrationFromTarget(cwd, target.agentName, 'manual');
116
+ console.log(`✔ ${target.relativePath} (${result.created ? 'created' : 'updated'})`);
117
+ written++;
118
+ }
119
+ catch (err) {
120
+ logger.debug(`Failed to export ${target.format}:`, err);
121
+ console.warn(`⚠ Skipped ${target.format}: ${err instanceof Error ? err.message : String(err)}`);
122
+ }
123
+ }
124
+ // Consolidate gitignore entries
125
+ if (allGitignoreEntries.length > 0) {
126
+ ensureGitignoreEntries(cwd, [...new Set(allGitignoreEntries)]);
127
+ console.log('✔ Updated .gitignore');
128
+ }
129
+ console.log(`✔ Exported ${written} agent file(s)`);
130
+ }
93
131
  export function writeAgentExportForAgent(agentName, cwd) {
94
132
  const rendered = renderAgentExportForAgent(agentName, cwd);
95
133
  if (!rendered) {
@@ -245,6 +245,8 @@ export async function runInit(options = {}) {
245
245
  if (initMemoryRepo(cwd)) {
246
246
  console.log('✔ Initialized memory git repo for versioning');
247
247
  }
248
+ // Install post-merge hook for auto-release of claims after merge
249
+ installPostMergeHookIfMissing(cwd);
248
250
  const onboardingPreflight = runBootstrapProfile({ cwd, refresh: true });
249
251
  console.log('');
250
252
  console.log('Onboarding preflight:');
@@ -268,6 +270,45 @@ export async function runInit(options = {}) {
268
270
  console.log('');
269
271
  console.log(`Tip: run 'brainclaw context --json' to load the shared memory into your agent session.`);
270
272
  }
273
+ function installPostMergeHookIfMissing(cwd) {
274
+ try {
275
+ let dir = path.resolve(cwd);
276
+ let gitRoot;
277
+ while (true) {
278
+ if (fs.existsSync(path.join(dir, '.git'))) {
279
+ gitRoot = dir;
280
+ break;
281
+ }
282
+ const parent = path.dirname(dir);
283
+ if (parent === dir)
284
+ break;
285
+ dir = parent;
286
+ }
287
+ if (!gitRoot)
288
+ return;
289
+ const hooksDir = path.join(gitRoot, '.git', 'hooks');
290
+ const hookPath = path.join(hooksDir, 'post-merge');
291
+ if (fs.existsSync(hookPath))
292
+ return; // don't overwrite existing hooks
293
+ if (!fs.existsSync(hooksDir))
294
+ fs.mkdirSync(hooksDir, { recursive: true });
295
+ const script = [
296
+ '#!/bin/sh',
297
+ '# brainclaw post-merge hook — auto-release claims on merged files',
298
+ 'BCLAW_CMD=""',
299
+ 'if command -v brainclaw >/dev/null 2>&1; then BCLAW_CMD="brainclaw"',
300
+ 'elif command -v bclaw >/dev/null 2>&1; then BCLAW_CMD="bclaw"',
301
+ 'else BCLAW_CMD="npx --no brainclaw"; fi',
302
+ '$BCLAW_CMD release-claims --from-git-diff 2>/dev/null || true',
303
+ '',
304
+ ].join('\n');
305
+ fs.writeFileSync(hookPath, script, { encoding: 'utf-8', mode: 0o755 });
306
+ console.log('✔ Installed post-merge hook for auto-release of claims');
307
+ }
308
+ catch {
309
+ // Non-critical — skip silently
310
+ }
311
+ }
271
312
  function resolveStorageDir(storageDir) {
272
313
  const candidate = (storageDir ?? MEMORY_DIR).trim();
273
314
  if (candidate !== MEMORY_DIR) {
@@ -18,7 +18,7 @@ import { acceptCandidate } from './accept.js';
18
18
  import { rejectCandidate } from './reject.js';
19
19
  import { startSession } from './session-start.js';
20
20
  import { endSession } from './session-end.js';
21
- import { agentCanWriteDirect, AgentIdentityResolutionError, AgentTrustError, listAgentIdentities, requireMinimumTrustLevel, requireRegisteredAgentIdentity, resolveAgentScope, resolveCurrentAgentIdentity, resolveCurrentAgentName, } from '../core/agent-registry.js';
21
+ import { agentCanWriteDirect, AgentIdentityResolutionError, AgentTrustError, listAgentIdentities, requireMinimumTrustLevel, requireRegisteredAgentIdentity, resolveAgentScope, resolveCurrentAgentIdentity, resolveCurrentAgentName, resolveCurrentModel, } from '../core/agent-registry.js';
22
22
  import { appendAuditEntry } from '../core/audit.js';
23
23
  import { nowISO, generateIdWithLabel, generateId } from '../core/ids.js';
24
24
  import { inferProjectFromTarget, loadInstructions, resolveInstructions } from '../core/instructions.js';
@@ -156,6 +156,10 @@ export const MCP_READ_TOOLS = [
156
156
  type: { type: 'string', description: 'Filter by plan type.' },
157
157
  assignee: { type: 'string', description: 'Filter by assignee name.' },
158
158
  project: { type: 'string', description: 'Filter by project namespace.' },
159
+ id: { type: 'string', description: 'Get a single plan by ID (exact match).' },
160
+ limit: { type: 'number', description: 'Maximum number of plans to return (default: 20).' },
161
+ offset: { type: 'number', description: 'Number of plans to skip (for pagination).' },
162
+ compact: { type: 'boolean', description: 'Return only key fields (id, short_label, text, status, priority) to reduce output size.' },
159
163
  },
160
164
  },
161
165
  },
@@ -1308,6 +1312,18 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
1308
1312
  }
1309
1313
  if (name === 'bclaw_list_plans') {
1310
1314
  let plans = loadState(cwd).plan_items;
1315
+ // Direct lookup by ID
1316
+ if (args.id) {
1317
+ const plan = plans.find((p) => p.id === String(args.id) || p.short_label === String(args.id));
1318
+ if (!plan) {
1319
+ return { content: [{ type: 'text', text: `Plan '${args.id}' not found.` }], structuredContent: { total: 0, plans: [] } };
1320
+ }
1321
+ return {
1322
+ content: [{ type: 'text', text: `[${plan.id}] ${plan.text} (${plan.status}, ${plan.priority})` }],
1323
+ structuredContent: { total: 1, plans: [plan] },
1324
+ };
1325
+ }
1326
+ // Filters
1311
1327
  if (!args.all) {
1312
1328
  plans = plans.filter((plan) => plan.status !== 'done' && plan.status !== 'dropped');
1313
1329
  }
@@ -1325,11 +1341,16 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
1325
1341
  const project = String(args.project).toLowerCase();
1326
1342
  plans = plans.filter((plan) => plan.project?.toLowerCase() === project);
1327
1343
  }
1328
- const lines = plans.length === 0
1344
+ const totalFiltered = plans.length;
1345
+ // Pagination
1346
+ const offset = Math.max(0, Number(args.offset) || 0);
1347
+ const limit = Math.max(1, Number(args.limit) || 20);
1348
+ const paginated = plans.slice(offset, offset + limit);
1349
+ const lines = paginated.length === 0
1329
1350
  ? ['No plan items found.']
1330
1351
  : [
1331
- `${plans.length} plan item(s):`,
1332
- ...plans.map((plan) => {
1352
+ `${totalFiltered} plan(s)${totalFiltered > paginated.length ? ` (showing ${offset + 1}-${offset + paginated.length})` : ''}:`,
1353
+ ...paginated.map((plan) => {
1333
1354
  const meta = [plan.type ?? 'feat', plan.status, plan.priority];
1334
1355
  if (plan.assignee)
1335
1356
  meta.push(`assignee ${plan.assignee}`);
@@ -1341,9 +1362,15 @@ export function handleMcpReadToolCall(name, args = {}, context = {}) {
1341
1362
  return `[${plan.id}] ${plan.text} (${meta.join(' · ')})${tags}`;
1342
1363
  }),
1343
1364
  ];
1365
+ // Compact mode: strip heavy fields
1366
+ const outputPlans = args.compact
1367
+ ? paginated.map(({ id, short_label, text, status, priority, tags, assignee, type }) => ({
1368
+ id, short_label, text, status, priority, tags, assignee, type,
1369
+ }))
1370
+ : paginated;
1344
1371
  return {
1345
1372
  content: [{ type: 'text', text: lines.join('\n') }],
1346
- structuredContent: { total: plans.length, plans },
1373
+ structuredContent: { total: totalFiltered, offset, limit, plans: outputPlans },
1347
1374
  };
1348
1375
  }
1349
1376
  if (name === 'bclaw_list_claims') {
@@ -1611,6 +1638,8 @@ export async function executeMcpToolCall(payload) {
1611
1638
  response: toolResponse(handleMcpReadToolCall(name, args, { cwd })),
1612
1639
  };
1613
1640
  }
1641
+ // Resolve model once for all write operations
1642
+ const currentModel = resolveCurrentModel(cwd);
1614
1643
  if (name === 'bclaw_setup') {
1615
1644
  const step = args.step;
1616
1645
  const choice = args.choice ?? '';
@@ -1794,6 +1823,7 @@ export async function executeMcpToolCall(payload) {
1794
1823
  autoReflect: args.autoReflect,
1795
1824
  cwd,
1796
1825
  sessionId: connectionSessionId,
1826
+ model: currentModel,
1797
1827
  }, false);
1798
1828
  return {
1799
1829
  response: toolResponse({
@@ -1846,6 +1876,7 @@ export async function executeMcpToolCall(payload) {
1846
1876
  category: type === 'constraint' ? args.category : undefined,
1847
1877
  outcome: type === 'decision' ? args.outcome : undefined,
1848
1878
  plan_id: candidatePlanId,
1879
+ model: currentModel,
1849
1880
  star_count: 0,
1850
1881
  starred_by: [],
1851
1882
  usage_count: 0,
@@ -1949,6 +1980,7 @@ export async function executeMcpToolCall(payload) {
1949
1980
  created_at: nowISO(),
1950
1981
  status: 'active',
1951
1982
  plan_id: args.planId,
1983
+ model: currentModel,
1952
1984
  }, claimCwd);
1953
1985
  appendAuditEntry({ actor: resolvedIdentity.agent_name, actor_id: resolvedIdentity.agent_id, action: 'claim', item_id: claimId, item_type: 'claim' }, claimCwd);
1954
1986
  const postClaimItems = getTriggeredItems('trigger:post-claim', claimCwd);
@@ -61,6 +61,7 @@ export function createRuntimeNote(text, options, printSuccess = false) {
61
61
  host_id: hostId,
62
62
  expires_at: expiresAt,
63
63
  note_type: 'observation',
64
+ model: options.model,
64
65
  };
65
66
  saveRuntimeNote(note, options.cwd);
66
67
  const result = maybeAutoReflectRuntimeNote(note, options);
@@ -164,6 +164,7 @@ export const InstructionEntrySchema = z.object({
164
164
  created_at: z.string(),
165
165
  updated_at: z.string(),
166
166
  author: z.string(),
167
+ model: z.string().optional(),
167
168
  tags: z.array(z.string()).default([]),
168
169
  active: z.boolean().default(true),
169
170
  supersedes: z.string().optional(),
@@ -184,6 +185,7 @@ export const ProjectCapabilitySchema = z.object({
184
185
  created_at: z.string(),
185
186
  author: z.string(),
186
187
  author_id: z.string().optional(),
188
+ model: z.string().optional(),
187
189
  });
188
190
  export const ToolTypeSchema = z.enum(['workflow', 'validator', 'generator', 'utility', 'explorer']);
189
191
  export const ProjectToolSchema = z.object({
@@ -204,6 +206,7 @@ export const ProjectToolSchema = z.object({
204
206
  created_at: z.string(),
205
207
  author: z.string(),
206
208
  author_id: z.string().optional(),
209
+ model: z.string().optional(),
207
210
  });
208
211
  // --- State schema ---
209
212
  export const StateSchema = z.object({
@@ -258,6 +261,7 @@ export const CandidateSchema = z.object({
258
261
  created_at: z.string(),
259
262
  author: z.string(),
260
263
  author_id: z.string().optional(),
264
+ model: z.string().optional(),
261
265
  project_id: z.string().optional(),
262
266
  host_id: z.string().optional(),
263
267
  session_id: z.string().optional(),
@@ -326,6 +330,7 @@ export const ClaimSchema = z.object({
326
330
  status: ClaimStatusSchema,
327
331
  released_at: z.string().optional(),
328
332
  expires_at: z.string().optional(),
333
+ model: z.string().optional(),
329
334
  });
330
335
  // --- Runtime notes schemas ---
331
336
  export const RuntimeNoteSchema = z.object({
@@ -344,6 +349,7 @@ export const RuntimeNoteSchema = z.object({
344
349
  host_id: z.string().optional(),
345
350
  expires_at: z.string().optional(),
346
351
  note_type: z.enum(['observation', 'session_start', 'session_end']).default('observation'),
352
+ model: z.string().optional(),
347
353
  });
348
354
  // --- AI surface task request schemas ---
349
355
  export const AiSurfaceTaskStatusSchema = z.enum(['queued', 'in_progress', 'completed', 'cancelled', 'failed']);
@@ -369,6 +375,7 @@ export const AiSurfaceTaskRequestSchema = z.object({
369
375
  claimed_at: z.string().optional(),
370
376
  completed_at: z.string().optional(),
371
377
  result_note: z.string().optional(),
378
+ model: z.string().optional(),
372
379
  });
373
380
  // --- Runtime event schemas ---
374
381
  export const RuntimeEventTypeSchema = z.enum([
@@ -398,6 +405,7 @@ export const RuntimeEventSchema = z.object({
398
405
  to: z.string().optional(),
399
406
  related_paths: z.array(z.string()).optional(),
400
407
  metadata: z.record(z.unknown()).optional(),
408
+ model: z.string().optional(),
401
409
  });
402
410
  // --- Profile schema ---
403
411
  export const ProfileSchema = z.enum(['dev', 'openclaw', 'ops', 'research']);
package/docs/cli.md CHANGED
@@ -86,7 +86,7 @@ brainclaw setup --roots ~/Projects,~/work --agents all # all agents, multiple r
86
86
 
87
87
  ### `brainclaw init`
88
88
 
89
- Initialize workspace state for the current project root. Detects the AI agent environment and writes to its native instruction file. `brainclaw setup` must have been run first on this machine. Do not run `init` from inside `.brainclaw/`; that directory is Brainclaw's own memory store, not a project root.
89
+ Initialize workspace state for the current project root. Detects the AI agent environment, writes to its native instruction file, and installs a git post-merge hook for automatic claim release. `brainclaw setup` must have been run first on this machine. Do not run `init` from inside `.brainclaw/`; that directory is Brainclaw's own memory store, not a project root.
90
90
 
91
91
  | Option | Description |
92
92
  |---|---|
@@ -993,13 +993,13 @@ brainclaw context --since-session --max-items 20
993
993
 
994
994
  ### `brainclaw context-diff`
995
995
 
996
- Show what has changed in shared memory since a reference point.
996
+ Hybrid context view for subsequent prompts: always includes **critical anchors** (active claims, resolved instructions, top 5 traps) plus the memory delta since a reference point. Used by the Claude Code UserPromptSubmit hook after the first prompt.
997
997
 
998
998
  | Option | Description |
999
999
  |---|---|
1000
1000
  | `--since <date>` | Start date for the diff |
1001
1001
  | `--session <id>` | Compare against a specific session start |
1002
- | `--json` | Output as JSON |
1002
+ | `--json` | Output as JSON (includes anchors + changed items) |
1003
1003
 
1004
1004
  ```bash
1005
1005
  brainclaw context-diff --session sess_42
@@ -1127,6 +1127,7 @@ Export memory as a native agent instruction file.
1127
1127
  |---|---|
1128
1128
  | `--format <format>` | Target format: `copilot-instructions`, `cursor-rules`, `agents-md`, `claude-md`, `gemini-md`, `windsurf`, `cline`, `roo`, or `continue` |
1129
1129
  | `--detect` | Auto-detect the running agent and write to its native file |
1130
+ | `--all` | Write all known agent instruction files at once (deduplicates by format) |
1130
1131
  | `--write` | Write output to the native file path (instead of stdout); generated workspace files are treated as local and added to `.gitignore` |
1131
1132
  | `--shared` | Keep the main exported instruction file versionable when used with `--write`; companion MCP/settings files stay local |
1132
1133
  | `--output <path>` | Write to a custom output path |
@@ -1146,6 +1147,7 @@ brainclaw export --format roo --write # .roo/rules/brainclaw.
1146
1147
  brainclaw export --format continue --write # .continue/rules/brainclaw.md
1147
1148
  brainclaw export --format claude-md --write --shared # publish CLAUDE.md intentionally
1148
1149
  brainclaw export --format claude-md # stdout
1150
+ brainclaw export --all # all 9 agent files at once
1149
1151
  ```
1150
1152
 
1151
1153
  `brainclaw export --write` is local-first by default: the generated workspace file and any companion MCP/settings files are added to `.gitignore`. Use `--shared` only when you intentionally want the main instruction file to be committed. `brainclaw export --detect` also writes companion MCP config where relevant, including `opencode.json` for OpenCode and `.gemini/antigravity/mcp_config.json` for Antigravity/Gemini when the local environment is available.
@@ -1174,7 +1176,7 @@ See [adapters/openclaw.md](adapters/openclaw.md).
1174
1176
 
1175
1177
  ### `brainclaw install-hooks`
1176
1178
 
1177
- Install Git hooks for constraint checking.
1179
+ Install Git hooks: pre-commit (constraint checking, sensitive content detection) and post-merge (auto-release of claims whose scope overlaps merged files).
1178
1180
 
1179
1181
  | Option | Description |
1180
1182
  |---|---|
@@ -1391,7 +1393,7 @@ brainclaw mcp
1391
1393
  | `bclaw_get_agent_board` | Live plan + claim board with active sessions |
1392
1394
  | `bclaw_search` | Full-text BM25 search across all memory items |
1393
1395
  | `bclaw_estimation_report` | Estimation accuracy report for completed plans |
1394
- | `bclaw_list_plans` | List plan items with the same filters as `brainclaw plan list` |
1396
+ | `bclaw_list_plans` | List plan items with filters, pagination (`limit`/`offset`), `compact` mode, and direct `id` lookup |
1395
1397
  | `bclaw_list_claims` | List claims with the same filters as `brainclaw claim list` |
1396
1398
  | `bclaw_list_agents` | List registered agents, optionally with bounded reputation summaries |
1397
1399
  | `bclaw_list_instructions` | List raw or resolved shared instructions |
@@ -106,6 +106,16 @@ brainclaw claim release <id>
106
106
 
107
107
  `claim list` shows who holds each claim and whether it is still active. If a claim has a `session_id`, the last 8 characters are shown so you can correlate with the agent session that created it.
108
108
 
109
+ ### Automatic claim release
110
+
111
+ Claims are automatically released after a `git merge` if the post-merge hook is installed (default since `brainclaw init` v0.25.3+). The hook matches merged file paths against active claim scopes and releases overlapping claims.
112
+
113
+ You can also install or reinstall the hook manually:
114
+
115
+ ```bash
116
+ brainclaw install-hooks
117
+ ```
118
+
109
119
  ## Why claims matter
110
120
 
111
121
  Without claims, multiple agents can easily touch the same area at once and generate conflicting changes.
@@ -83,7 +83,8 @@ brainclaw export --detect --write # auto-detect and write all formats
83
83
  When brainclaw memory changes (new constraints, resolved traps, updated plans), regenerate instruction files:
84
84
 
85
85
  ```bash
86
- brainclaw export --detect --write
86
+ brainclaw export --all # all 9 agent formats at once
87
+ brainclaw export --detect --write # only the detected agent
87
88
  ```
88
89
 
89
90
  For agents without MCP (Copilot), this is especially important — the instruction file is their only source of project context.
@@ -42,7 +42,7 @@ This keeps session continuity inside Brainclaw instead of pushing the agent back
42
42
  | `bclaw_write_note` | Record a runtime note, supports `autoReflect: true` |
43
43
  | `bclaw_read_handoff` | Read active handoffs |
44
44
  | `bclaw_get_agent_board` | Coordination snapshot |
45
- | `bclaw_list_plans` | Structured plan listing with CLI-equivalent filters |
45
+ | `bclaw_list_plans` | Structured plan listing with filters, pagination (`limit`/`offset`), `compact` mode, and `id` lookup |
46
46
  | `bclaw_list_claims` | Structured claim listing with CLI-equivalent filters |
47
47
  | `bclaw_list_agents` | Registered agent inventory, optionally with bounded reputation |
48
48
  | `bclaw_list_instructions` | Raw or resolved instruction listing |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "brainclaw",
3
- "version": "0.24.0",
3
+ "version": "0.25.3",
4
4
  "description": "Shared project memory for humans and coding agents.",
5
5
  "type": "module",
6
6
  "bin": {