brainclaw 0.23.1 → 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/accept.js +5 -2
- package/dist/commands/claim.js +7 -5
- 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/instruction.js +5 -4
- package/dist/commands/mcp.js +64 -5
- package/dist/commands/prune.js +5 -4
- package/dist/commands/reflect.js +2 -0
- package/dist/commands/release-claim.js +4 -4
- package/dist/commands/release-claims.js +5 -4
- package/dist/commands/runtime-note.js +1 -0
- package/dist/core/ai-surface-tasks.js +3 -2
- package/dist/core/audit.js +3 -2
- package/dist/core/bootstrap.js +7 -6
- package/dist/core/candidates.js +4 -3
- package/dist/core/claims.js +3 -2
- package/dist/core/instructions.js +3 -2
- package/dist/core/io.js +1 -0
- package/dist/core/lock.js +2 -2
- package/dist/core/markdown.js +18 -0
- package/dist/core/mutation-pipeline.js +39 -0
- package/dist/core/runtime.js +4 -3
- package/dist/core/schema.js +8 -0
- package/dist/core/state.js +5 -4
- package/docs/cli.md +7 -5
- package/docs/concepts/memory.md +4 -3
- package/docs/concepts/plans-and-claims.md +10 -0
- package/docs/integrations/agents.md +2 -1
- package/docs/integrations/claude-code.md +1 -1
- package/docs/integrations/codex.md +1 -1
- package/docs/integrations/copilot.md +1 -1
- package/docs/integrations/cursor.md +1 -1
- package/docs/integrations/mcp.md +16 -6
- package/docs/integrations/overview.md +2 -2
- package/docs/quickstart.md +3 -1
- package/docs/storage.md +51 -24
- package/package.json +1 -1
package/dist/core/bootstrap.js
CHANGED
|
@@ -4,7 +4,8 @@ import path from 'node:path';
|
|
|
4
4
|
import { spawnSync } from 'node:child_process';
|
|
5
5
|
import { JsonStore } from './json-store.js';
|
|
6
6
|
import { generateId, generateIdWithLabel, nowISO } from './ids.js';
|
|
7
|
-
import {
|
|
7
|
+
import { resolveEntityDir } from './io.js';
|
|
8
|
+
import { mutate } from './mutation-pipeline.js';
|
|
8
9
|
import { BootstrapApplicationReceiptSchema, BootstrapInterviewAnswerSchema, BootstrapInterviewPlanSchema, BootstrapInterviewQuestionSchema, BootstrapImportPlanDocumentSchema, BootstrapProfileDocumentSchema, BootstrapSuggestionDocumentSchema, MemorySeedDocumentSchema, } from './schema.js';
|
|
9
10
|
import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
|
|
10
11
|
import { analyzeRepository } from './repo-analysis.js';
|
|
@@ -13,7 +14,7 @@ import { buildAgentToolingContext } from './agent-context.js';
|
|
|
13
14
|
import { createInstruction, loadInstructions, saveInstruction } from './instructions.js';
|
|
14
15
|
import { resolveCurrentAgentName } from './agent-registry.js';
|
|
15
16
|
import { loadState, persistState } from './state.js';
|
|
16
|
-
import {
|
|
17
|
+
import { rebuildProjectMd } from './markdown.js';
|
|
17
18
|
const README_CANDIDATES = ['README.md', 'README', 'README.txt', 'README.mdx'];
|
|
18
19
|
const DOC_HINTS = ['docs', 'doc'];
|
|
19
20
|
const MAKEFILE_NAME = 'Makefile';
|
|
@@ -1241,7 +1242,7 @@ export function applyBootstrapImport(options = {}) {
|
|
|
1241
1242
|
const managedArtifacts = [];
|
|
1242
1243
|
let createdCount = 0;
|
|
1243
1244
|
let skippedCount = 0;
|
|
1244
|
-
|
|
1245
|
+
mutate({ cwd }, () => {
|
|
1245
1246
|
const state = loadState(cwd);
|
|
1246
1247
|
const activeInstructionKeys = new Set(loadInstructions(cwd)
|
|
1247
1248
|
.filter((entry) => entry.active)
|
|
@@ -1380,7 +1381,7 @@ export function applyBootstrapImport(options = {}) {
|
|
|
1380
1381
|
persistState(state, cwd, { writeProjectMarkdown: false });
|
|
1381
1382
|
}
|
|
1382
1383
|
if (createdCount > 0) {
|
|
1383
|
-
|
|
1384
|
+
rebuildProjectMd(loadState(cwd), cwd);
|
|
1384
1385
|
}
|
|
1385
1386
|
});
|
|
1386
1387
|
const receipt = BootstrapApplicationReceiptSchema.parse({
|
|
@@ -1414,7 +1415,7 @@ export function uninstallBootstrapImport(cwd) {
|
|
|
1414
1415
|
let deactivatedCount = 0;
|
|
1415
1416
|
let deletedCount = 0;
|
|
1416
1417
|
let skippedCount = 0;
|
|
1417
|
-
|
|
1418
|
+
mutate({ cwd: resolvedCwd }, () => {
|
|
1418
1419
|
const state = loadState(resolvedCwd);
|
|
1419
1420
|
const instructions = loadInstructions(resolvedCwd);
|
|
1420
1421
|
let stateChanged = false;
|
|
@@ -1459,7 +1460,7 @@ export function uninstallBootstrapImport(cwd) {
|
|
|
1459
1460
|
persistState(state, resolvedCwd, { writeProjectMarkdown: false });
|
|
1460
1461
|
}
|
|
1461
1462
|
if (deactivatedCount > 0 || deletedCount > 0) {
|
|
1462
|
-
|
|
1463
|
+
rebuildProjectMd(loadState(resolvedCwd), resolvedCwd);
|
|
1463
1464
|
}
|
|
1464
1465
|
});
|
|
1465
1466
|
const nextReceipt = BootstrapApplicationReceiptSchema.parse({
|
package/dist/core/candidates.js
CHANGED
|
@@ -2,7 +2,8 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { CandidateSchema } from './schema.js';
|
|
5
|
-
import { resolveEntityDir
|
|
5
|
+
import { resolveEntityDir } from './io.js';
|
|
6
|
+
import { mutate } from './mutation-pipeline.js';
|
|
6
7
|
import { nowISO, getNextShortLabel } from './ids.js';
|
|
7
8
|
import { JsonStore } from './json-store.js';
|
|
8
9
|
function inboxDir(cwd, mode = 'read') {
|
|
@@ -35,7 +36,7 @@ function candidateStore(dest = 'pending', cwd) {
|
|
|
35
36
|
});
|
|
36
37
|
}
|
|
37
38
|
export function saveCandidate(candidate, cwd) {
|
|
38
|
-
|
|
39
|
+
mutate({ cwd }, () => {
|
|
39
40
|
ensureInboxDirs(cwd);
|
|
40
41
|
candidateStore('pending', cwd).save(CandidateSchema.parse(candidate));
|
|
41
42
|
});
|
|
@@ -51,7 +52,7 @@ export function listCandidates(status, cwd) {
|
|
|
51
52
|
return status ? candidates.filter((candidate) => candidate.status === status) : candidates;
|
|
52
53
|
}
|
|
53
54
|
export function archiveCandidate(candidate, dest, cwd) {
|
|
54
|
-
|
|
55
|
+
mutate({ cwd }, () => {
|
|
55
56
|
ensureInboxDirs(cwd);
|
|
56
57
|
candidateStore(dest, cwd).save(CandidateSchema.parse(candidate));
|
|
57
58
|
candidateStore('pending', cwd).delete(candidate.id);
|
package/dist/core/claims.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import crypto from 'node:crypto';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { ClaimSchema } from './schema.js';
|
|
4
|
-
import { resolveEntityDir
|
|
4
|
+
import { resolveEntityDir } from './io.js';
|
|
5
|
+
import { mutate } from './mutation-pipeline.js';
|
|
5
6
|
import { nowISO } from './ids.js';
|
|
6
7
|
import { JsonStore } from './json-store.js';
|
|
7
8
|
function claimsDir(cwd, mode = 'read') {
|
|
@@ -22,7 +23,7 @@ function claimStore(cwd) {
|
|
|
22
23
|
});
|
|
23
24
|
}
|
|
24
25
|
export function saveClaim(claim, cwd) {
|
|
25
|
-
|
|
26
|
+
mutate({ cwd }, () => {
|
|
26
27
|
ensureClaimsDir(cwd);
|
|
27
28
|
const writeStore = new JsonStore({
|
|
28
29
|
dirPath: claimsDir(cwd, 'write'),
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
-
import { resolveEntityDir
|
|
2
|
+
import { resolveEntityDir } from './io.js';
|
|
3
|
+
import { mutate } from './mutation-pipeline.js';
|
|
3
4
|
import { generateId } from './ids.js';
|
|
4
5
|
import { InstructionEntrySchema } from './schema.js';
|
|
5
6
|
import { JsonStore } from './json-store.js';
|
|
@@ -19,7 +20,7 @@ export function loadInstructions(cwd) {
|
|
|
19
20
|
return instructionStore(cwd).list();
|
|
20
21
|
}
|
|
21
22
|
export function saveInstruction(entry, cwd) {
|
|
22
|
-
|
|
23
|
+
mutate({ cwd }, () => {
|
|
23
24
|
instructionStore(cwd, 'write').save(InstructionEntrySchema.parse(entry));
|
|
24
25
|
});
|
|
25
26
|
}
|
package/dist/core/io.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { withLock, cleanStaleLocks } from './lock.js';
|
|
4
|
+
export { mutate } from './mutation-pipeline.js';
|
|
4
5
|
export const MEMORY_DIR = '.brainclaw';
|
|
5
6
|
const STORE_LOCK_BASENAME = '.store-mutation';
|
|
6
7
|
const RETRYABLE_RENAME_ERROR_CODES = new Set(['EPERM', 'EBUSY', 'EACCES']);
|
package/dist/core/lock.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
const DEFAULT_TIMEOUT_MS =
|
|
3
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
4
4
|
const LOCK_RETRY_INTERVAL_MS = 50;
|
|
5
|
-
const LOCK_EXPIRY_MS =
|
|
5
|
+
const LOCK_EXPIRY_MS = 10000;
|
|
6
6
|
const heldLocks = new Map();
|
|
7
7
|
function lockFilePath(targetPath) {
|
|
8
8
|
return targetPath + '.lock';
|
package/dist/core/markdown.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { listClaims } from './claims.js';
|
|
2
2
|
import { loadInstructions } from './instructions.js';
|
|
3
|
+
import { memoryPath, writeFileAtomic } from './io.js';
|
|
3
4
|
import { isTrapActive } from './traps.js';
|
|
5
|
+
import { logger } from './logger.js';
|
|
4
6
|
export function generateMarkdown(state, cwd) {
|
|
5
7
|
const lines = ['# Project Memory', ''];
|
|
6
8
|
const instructions = loadInstructions(cwd).filter((entry) => entry.active);
|
|
@@ -117,4 +119,20 @@ export function generateMarkdown(state, cwd) {
|
|
|
117
119
|
lines.push('');
|
|
118
120
|
return lines.join('\n');
|
|
119
121
|
}
|
|
122
|
+
/**
|
|
123
|
+
* Rebuild `.brainclaw/project.md` from canonical state.
|
|
124
|
+
*
|
|
125
|
+
* This is a **derived view** — it can always be regenerated from the
|
|
126
|
+
* canonical JSON files. Call this once at the end of a top-level mutation,
|
|
127
|
+
* not inside every nested helper. Best-effort: failures are logged but
|
|
128
|
+
* never propagate to the caller.
|
|
129
|
+
*/
|
|
130
|
+
export function rebuildProjectMd(state, cwd) {
|
|
131
|
+
try {
|
|
132
|
+
writeFileAtomic(memoryPath('project.md', cwd), generateMarkdown(state, cwd));
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
logger.debug('Failed to rebuild project.md:', err);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
120
138
|
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Mutation pipeline — single entry point for all .brainclaw/ store mutations.
|
|
3
|
+
*
|
|
4
|
+
* Every write operation against the store MUST go through `mutate()`.
|
|
5
|
+
* This ensures:
|
|
6
|
+
* 1. Store-wide serialization via the advisory file lock
|
|
7
|
+
* 2. Consistent error handling and timeout behavior
|
|
8
|
+
* 3. Observable mutation metadata for debugging and auditing
|
|
9
|
+
*
|
|
10
|
+
* @module
|
|
11
|
+
*/
|
|
12
|
+
import { ensureMemoryDir, storeLockPath } from './io.js';
|
|
13
|
+
import { withLock } from './lock.js';
|
|
14
|
+
import { logger } from './logger.js';
|
|
15
|
+
/** Default timeout for store-wide lock acquisition (ms). */
|
|
16
|
+
export const STORE_LOCK_TIMEOUT_MS = 5_000;
|
|
17
|
+
export function mutate(optionsOrFn, maybeFn) {
|
|
18
|
+
const options = typeof optionsOrFn === 'function' ? {} : optionsOrFn;
|
|
19
|
+
const fn = typeof optionsOrFn === 'function' ? optionsOrFn : maybeFn;
|
|
20
|
+
const cwd = options.cwd ?? process.cwd();
|
|
21
|
+
const timeoutMs = options.timeoutMs ?? STORE_LOCK_TIMEOUT_MS;
|
|
22
|
+
ensureMemoryDir(cwd, options.preferredDirName);
|
|
23
|
+
const lockTarget = storeLockPath(cwd, options.preferredDirName);
|
|
24
|
+
const start = performance.now();
|
|
25
|
+
try {
|
|
26
|
+
const value = withLock(lockTarget, () => fn(cwd), timeoutMs);
|
|
27
|
+
const durationMs = performance.now() - start;
|
|
28
|
+
if (durationMs > 1_000) {
|
|
29
|
+
logger.debug(`Slow mutation: ${durationMs.toFixed(0)}ms (cwd=${cwd})`);
|
|
30
|
+
}
|
|
31
|
+
return value;
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
const durationMs = performance.now() - start;
|
|
35
|
+
logger.debug(`Mutation failed after ${durationMs.toFixed(0)}ms: ${err instanceof Error ? err.message : String(err)}`);
|
|
36
|
+
throw err;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=mutation-pipeline.js.map
|
package/dist/core/runtime.js
CHANGED
|
@@ -2,7 +2,8 @@ import crypto from 'node:crypto';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import { resolveCurrentHostId, sanitizeHostId } from './host.js';
|
|
5
|
-
import { resolveEntityDir
|
|
5
|
+
import { resolveEntityDir } from './io.js';
|
|
6
|
+
import { mutate } from './mutation-pipeline.js';
|
|
6
7
|
import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
|
|
7
8
|
import { RuntimeNoteSchema } from './schema.js';
|
|
8
9
|
import { commitMemoryChange } from './memory-git.js';
|
|
@@ -40,7 +41,7 @@ export function saveRuntimeNote(note, cwd) {
|
|
|
40
41
|
const persistedNote = visibility === 'shared'
|
|
41
42
|
? { ...note, visibility, host_id: hostId }
|
|
42
43
|
: { ...note, visibility, host_id: hostId };
|
|
43
|
-
|
|
44
|
+
mutate({ cwd }, () => {
|
|
44
45
|
ensureRuntimeDir(note.agent, cwd, visibility, hostId);
|
|
45
46
|
const filepath = visibility === 'shared'
|
|
46
47
|
? path.join(sharedAgentDir(note.agent, cwd, 'write'), `${note.id}.json`)
|
|
@@ -58,7 +59,7 @@ export function runtimeNotePath(note, cwd) {
|
|
|
58
59
|
: path.join(hostAgentDir(visibility, hostId, note.agent, cwd), `${note.id}.json`);
|
|
59
60
|
}
|
|
60
61
|
export function deleteRuntimeNote(note, cwd) {
|
|
61
|
-
return
|
|
62
|
+
return mutate({ cwd }, () => {
|
|
62
63
|
const filepath = runtimeNotePath(note, cwd);
|
|
63
64
|
if (!fs.existsSync(filepath)) {
|
|
64
65
|
return false;
|
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/dist/core/state.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { ConstraintSchema, DecisionSchema, TrapSchema, HandoffSchema, PlanItemSchema } from './schema.js';
|
|
4
|
-
import { ensureMemoryDir,
|
|
4
|
+
import { ensureMemoryDir, resolveEntityDir } from './io.js';
|
|
5
|
+
import { mutate } from './mutation-pipeline.js';
|
|
5
6
|
import { commitMemoryChange } from './memory-git.js';
|
|
6
7
|
import { appendEvent } from './event-log.js';
|
|
7
8
|
import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
|
|
8
|
-
import {
|
|
9
|
+
import { rebuildProjectMd } from './markdown.js';
|
|
9
10
|
export function emptyState() {
|
|
10
11
|
return {
|
|
11
12
|
version: 1,
|
|
@@ -83,10 +84,10 @@ function writeStateDirectories(state, cwd) {
|
|
|
83
84
|
}
|
|
84
85
|
export function persistState(state, cwd, options = {}) {
|
|
85
86
|
const effectiveCwd = cwd ?? process.cwd();
|
|
86
|
-
|
|
87
|
+
mutate({ cwd: effectiveCwd }, () => {
|
|
87
88
|
writeStateDirectories(state, effectiveCwd);
|
|
88
89
|
if (options.writeProjectMarkdown ?? true) {
|
|
89
|
-
|
|
90
|
+
rebuildProjectMd(state, effectiveCwd);
|
|
90
91
|
}
|
|
91
92
|
appendEvent({
|
|
92
93
|
action: options.eventAction ?? 'update',
|
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 |
|
package/docs/concepts/memory.md
CHANGED
|
@@ -32,7 +32,7 @@ Examples: constraints, decisions, traps, completed plans, handoffs.
|
|
|
32
32
|
|
|
33
33
|
Shared traps now have a lifecycle too: `active`, `resolved`, or `expired`. Active views such as generated context, status, and `project.md` prioritize only active traps so old machine-setup issues stop polluting the current working set, while the canonical memory still keeps resolved traps for audit and search.
|
|
34
34
|
|
|
35
|
-
These live
|
|
35
|
+
These live as individual JSON files under `.brainclaw/memory/` (constraints, decisions, traps, instructions) and `.brainclaw/coordination/` (plans, claims, handoffs). They are versioned in `.brainclaw/.git` and shared via Git.
|
|
36
36
|
|
|
37
37
|
### Runtime memory
|
|
38
38
|
Operational observations that may be short-lived, host-specific, or private.
|
|
@@ -59,8 +59,9 @@ brainclaw makes this context visible and versionable.
|
|
|
59
59
|
|
|
60
60
|
brainclaw keeps:
|
|
61
61
|
|
|
62
|
-
- canonical structured JSON as the source of truth (`.brainclaw/
|
|
63
|
-
- a
|
|
62
|
+
- canonical structured JSON as the source of truth (individual files under `.brainclaw/memory/` and `.brainclaw/coordination/`)
|
|
63
|
+
- a derived readable view (`project.md`) regenerated best-effort from canonical state
|
|
64
|
+
- native agent instruction files (`CLAUDE.md`, `.cursor/rules/brainclaw.md`, etc.) generated via `brainclaw export`
|
|
64
65
|
|
|
65
66
|
This balances machine reliability with human readability.
|
|
66
67
|
|
|
@@ -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.
|
|
@@ -14,7 +14,7 @@ brainclaw export --format claude-md --write
|
|
|
14
14
|
|
|
15
15
|
- use MCP as the default runtime path for dynamic retrieval and writes
|
|
16
16
|
- keep `CLAUDE.md` lightweight and behavioral: it should tell Claude Code when to call Brainclaw, not carry all mutable workspace state
|
|
17
|
-
- use `.brainclaw/project.md` as a readable fallback
|
|
17
|
+
- use `.brainclaw/project.md` as a readable fallback (it is a derived view, regenerated best-effort — run `brainclaw rebuild` if stale)
|
|
18
18
|
- use hooks or workflow checks when a stronger reminder is needed
|
|
19
19
|
|
|
20
20
|
## Key idea
|
|
@@ -14,7 +14,7 @@ brainclaw export --format agents-md --write
|
|
|
14
14
|
|
|
15
15
|
- use MCP as the default runtime path for fresh context, plans, claims, and runtime notes
|
|
16
16
|
- keep `AGENTS.md` lightweight and behavioral: it should remind Codex how to use Brainclaw, not duplicate live state
|
|
17
|
-
- use `.brainclaw/project.md` only as a readable fallback
|
|
17
|
+
- use `.brainclaw/project.md` only as a readable fallback (derived view, regenerated best-effort — run `brainclaw rebuild` if stale)
|
|
18
18
|
- encourage plans, claims, and handoffs during multi-step work
|
|
19
19
|
|
|
20
20
|
## Good role for brainclaw here
|
|
@@ -14,7 +14,7 @@ brainclaw export --format copilot-instructions --write
|
|
|
14
14
|
|
|
15
15
|
- use MCP whenever the Copilot surface supports it for fresh context and coordination views
|
|
16
16
|
- keep `.github/copilot-instructions.md` lightweight and behavioral
|
|
17
|
-
- use `.brainclaw/project.md` as readable fallback,
|
|
17
|
+
- use `.brainclaw/project.md` as readable fallback (derived view, regenerated best-effort — may need `brainclaw rebuild` if stale)
|
|
18
18
|
- use plans, claims, and handoffs to reduce ambiguity across sessions
|
|
19
19
|
|
|
20
20
|
## Why this matters
|
|
@@ -14,7 +14,7 @@ brainclaw export --format cursor-rules --write
|
|
|
14
14
|
|
|
15
15
|
- use MCP as the default dynamic path for context, board state, plans, and claims
|
|
16
16
|
- let the generated `.cursor/rules/brainclaw.md` tell Cursor when to consult Brainclaw and how to stay inside the workflow
|
|
17
|
-
- use `.brainclaw/project.md` only as readable fallback
|
|
17
|
+
- use `.brainclaw/project.md` only as readable fallback (derived view, may be stale — run `brainclaw rebuild` to refresh)
|
|
18
18
|
- rely on claims and plans when multiple agents or humans are active in the same repo
|
|
19
19
|
|
|
20
20
|
## Key point
|
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 |
|
|
@@ -58,7 +58,7 @@ This keeps session continuity inside Brainclaw instead of pushing the agent back
|
|
|
58
58
|
| Runtime writes with session continuity | MCP |
|
|
59
59
|
| Local behavioral reminders inside the agent UI | native agent files |
|
|
60
60
|
| Human inspection or scripting | CLI |
|
|
61
|
-
| Simple readable fallback | `.brainclaw/project.md` |
|
|
61
|
+
| Simple readable fallback | `.brainclaw/project.md` (derived view, may be stale) |
|
|
62
62
|
|
|
63
63
|
## Starting The Server
|
|
64
64
|
|
|
@@ -87,16 +87,26 @@ Interview answers are keyed by question ID and may contain:
|
|
|
87
87
|
- `response_boolean`
|
|
88
88
|
- optional explicit `suggestions` when the agent wants to confirm exact canonical memory items
|
|
89
89
|
|
|
90
|
+
## Mutation Safety
|
|
91
|
+
|
|
92
|
+
The MCP server serializes all mutations through a single-writer queue (`McpTaskRunner`). When an agent calls a write tool (e.g. `bclaw_claim`, `bclaw_write_note`, `bclaw_create_plan`), the request is enqueued and executed one at a time. This guarantees:
|
|
93
|
+
|
|
94
|
+
- no concurrent writes from the same MCP connection
|
|
95
|
+
- no partial state from interleaved mutations
|
|
96
|
+
- deterministic ordering of operations
|
|
97
|
+
|
|
98
|
+
A secondary file-based lock (`mutate()`) provides cross-process safety in case CLI commands run alongside MCP. But for agents, MCP is the safe path by design — no extra precautions needed.
|
|
99
|
+
|
|
90
100
|
## Important Rule
|
|
91
101
|
|
|
92
|
-
If the agent has MCP available, do not treat the CLI as the primary runtime interface.
|
|
102
|
+
If the agent has MCP available, do not treat the CLI as the primary runtime interface. All agent mutations MUST go through MCP tools.
|
|
93
103
|
|
|
94
104
|
The CLI remains valuable for:
|
|
95
105
|
|
|
96
|
-
- setup
|
|
106
|
+
- setup and initialization
|
|
97
107
|
- bootstrap by a human operator
|
|
98
|
-
- scripting
|
|
108
|
+
- scripting and automation
|
|
99
109
|
- release and packaging
|
|
100
110
|
- debugging and fallback access
|
|
101
111
|
|
|
102
|
-
But for capable agents, MCP
|
|
112
|
+
But for capable agents, MCP is the first-class path for both reads and writes.
|
|
@@ -87,9 +87,9 @@ The developer can dial back individual surfaces if needed, but the default is fu
|
|
|
87
87
|
|
|
88
88
|
## Sequential collaboration, not parallel editing
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
brainclaw's store mutations are serialized (MCP single-writer queue + file-based lock), so memory writes are safe even under contention. However, running multiple agents in parallel on the same checkout can still cause Git conflicts and confusing file-level state.
|
|
91
91
|
|
|
92
|
-
|
|
92
|
+
For now, brainclaw works best when one agent works at a time in a given checkout. The next agent can pick up where the previous one stopped, using shared plans, claims, handoffs, and memory. Git worktree isolation per agent is planned but not yet available.
|
|
93
93
|
|
|
94
94
|
## Next reads
|
|
95
95
|
|
package/docs/quickstart.md
CHANGED
|
@@ -74,7 +74,9 @@ This keeps non-code work visible to the project without overloading the active c
|
|
|
74
74
|
|
|
75
75
|
## Important: one agent at a time
|
|
76
76
|
|
|
77
|
-
|
|
77
|
+
brainclaw serializes all store mutations (file lock + MCP single-writer queue), so writes are safe. But running multiple agents in parallel on the same checkout can still cause Git conflicts and confusing state transitions.
|
|
78
|
+
|
|
79
|
+
Use brainclaw for sequential collaboration: one agent works, finishes, and the next one picks up from shared context. Use `bclaw_session_end` to hand off cleanly.
|
|
78
80
|
|
|
79
81
|
## Next reads
|
|
80
82
|
|