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 +1 -0
- package/dist/commands/claim.js +2 -1
- package/dist/commands/context-diff.js +62 -4
- package/dist/commands/export.js +40 -2
- package/dist/commands/init.js +41 -0
- package/dist/commands/mcp.js +37 -5
- package/dist/commands/runtime-note.js +1 -0
- package/dist/core/schema.js +8 -0
- package/docs/cli.md +7 -5
- package/docs/concepts/plans-and-claims.md +10 -0
- package/docs/integrations/agents.md +2 -1
- package/docs/integrations/mcp.md +1 -1
- package/package.json +1 -1
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')
|
package/dist/commands/claim.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
28
|
-
return;
|
|
63
|
+
lines.push(`Memory: no changes since ${diff.since?.slice(0, 16).replace('T', ' ')}.`);
|
|
29
64
|
}
|
|
30
|
-
|
|
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
|
package/dist/commands/export.js
CHANGED
|
@@ -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 --
|
|
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) {
|
package/dist/commands/init.js
CHANGED
|
@@ -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) {
|
package/dist/commands/mcp.js
CHANGED
|
@@ -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
|
|
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
|
-
`${
|
|
1332
|
-
...
|
|
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:
|
|
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);
|
package/dist/core/schema.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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
|
|
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
|
|
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 --
|
|
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.
|
package/docs/integrations/mcp.md
CHANGED
|
@@ -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
|
|
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 |
|