brainclaw 0.19.5 → 0.19.7

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 (151) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +22 -20
  3. package/dist/cli.js +0 -0
  4. package/dist/commands/accept.js +102 -104
  5. package/dist/commands/adapter-openclaw-import.js +0 -0
  6. package/dist/commands/add-step.js +3 -5
  7. package/dist/commands/agent-board.js +0 -0
  8. package/dist/commands/audit.js +0 -0
  9. package/dist/commands/bootstrap.js +0 -0
  10. package/dist/commands/capability.js +3 -5
  11. package/dist/commands/changes.js +0 -0
  12. package/dist/commands/check-constraints.js +0 -0
  13. package/dist/commands/claim-resource.js +0 -0
  14. package/dist/commands/claim.js +14 -12
  15. package/dist/commands/complete-step.js +3 -5
  16. package/dist/commands/constraint.js +3 -5
  17. package/dist/commands/context-diff.js +0 -0
  18. package/dist/commands/context.js +0 -0
  19. package/dist/commands/decision.js +3 -6
  20. package/dist/commands/delete-plan.js +3 -5
  21. package/dist/commands/diff.js +0 -0
  22. package/dist/commands/doctor.js +0 -0
  23. package/dist/commands/enable-agent.js +0 -0
  24. package/dist/commands/env.js +0 -0
  25. package/dist/commands/estimation-report.js +0 -0
  26. package/dist/commands/explore.js +0 -0
  27. package/dist/commands/export.js +0 -0
  28. package/dist/commands/handoff.js +3 -5
  29. package/dist/commands/history.js +0 -0
  30. package/dist/commands/hooks.js +0 -0
  31. package/dist/commands/init.js +0 -0
  32. package/dist/commands/install-hooks.js +0 -0
  33. package/dist/commands/instruction.js +16 -9
  34. package/dist/commands/list-agents.js +0 -0
  35. package/dist/commands/list-claims.js +0 -0
  36. package/dist/commands/list-instructions.js +0 -0
  37. package/dist/commands/list-plans.js +0 -0
  38. package/dist/commands/mcp-worker.js +0 -0
  39. package/dist/commands/mcp.js +11 -21
  40. package/dist/commands/memory.js +4 -7
  41. package/dist/commands/metrics.js +0 -0
  42. package/dist/commands/plan-resource.js +0 -0
  43. package/dist/commands/plan.js +3 -5
  44. package/dist/commands/prune-candidates.js +0 -0
  45. package/dist/commands/prune.js +27 -25
  46. package/dist/commands/pull.js +0 -0
  47. package/dist/commands/push.js +0 -0
  48. package/dist/commands/rebuild.js +0 -0
  49. package/dist/commands/reflect-runtime-note.js +0 -0
  50. package/dist/commands/reflect.js +3 -5
  51. package/dist/commands/register-agent.js +0 -0
  52. package/dist/commands/reject.js +0 -0
  53. package/dist/commands/release-claim.js +23 -20
  54. package/dist/commands/release-claims.js +22 -21
  55. package/dist/commands/review.js +0 -0
  56. package/dist/commands/rollback.js +2 -2
  57. package/dist/commands/runtime-note.js +0 -0
  58. package/dist/commands/runtime-status.js +0 -0
  59. package/dist/commands/search.js +0 -0
  60. package/dist/commands/session-end.js +0 -0
  61. package/dist/commands/session-start.js +0 -0
  62. package/dist/commands/set-trust.js +0 -0
  63. package/dist/commands/setup.js +0 -0
  64. package/dist/commands/show-candidate.js +0 -0
  65. package/dist/commands/star-candidate.js +0 -0
  66. package/dist/commands/status.js +0 -0
  67. package/dist/commands/sync.js +0 -0
  68. package/dist/commands/tool.js +3 -5
  69. package/dist/commands/trap.js +3 -5
  70. package/dist/commands/update-handoff.js +3 -5
  71. package/dist/commands/update-plan.js +3 -5
  72. package/dist/commands/upgrade.js +2 -2
  73. package/dist/commands/use-candidate.js +0 -0
  74. package/dist/commands/version.js +0 -0
  75. package/dist/commands/watch.js +0 -0
  76. package/dist/commands/whoami.js +0 -0
  77. package/dist/core/agent-context.js +0 -0
  78. package/dist/core/agent-files.js +0 -0
  79. package/dist/core/agent-integrations.js +0 -0
  80. package/dist/core/agent-inventory.js +0 -0
  81. package/dist/core/agent-registry.js +0 -0
  82. package/dist/core/ai-agent-detection.js +0 -0
  83. package/dist/core/audit.js +25 -25
  84. package/dist/core/bootstrap.js +0 -0
  85. package/dist/core/brainclaw-version.js +0 -0
  86. package/dist/core/candidates.js +10 -6
  87. package/dist/core/circuit-breaker.js +0 -0
  88. package/dist/core/claims.js +10 -8
  89. package/dist/core/config.js +0 -0
  90. package/dist/core/context-diff.js +0 -0
  91. package/dist/core/context.js +0 -0
  92. package/dist/core/contradictions.js +0 -0
  93. package/dist/core/coordination.js +2 -2
  94. package/dist/core/cross-project.js +0 -0
  95. package/dist/core/duplicates.js +0 -0
  96. package/dist/core/event-log.js +0 -0
  97. package/dist/core/events.js +0 -0
  98. package/dist/core/execution-context.js +0 -0
  99. package/dist/core/freshness.js +0 -0
  100. package/dist/core/global-registry.js +0 -0
  101. package/dist/core/host.js +0 -0
  102. package/dist/core/identity.js +0 -0
  103. package/dist/core/ids.js +0 -0
  104. package/dist/core/input-validation.js +0 -0
  105. package/dist/core/instructions.js +4 -2
  106. package/dist/core/io.js +8 -0
  107. package/dist/core/json-store.js +0 -0
  108. package/dist/core/lifecycle.js +0 -0
  109. package/dist/core/lock.js +18 -2
  110. package/dist/core/logger.js +0 -0
  111. package/dist/core/machine-profile.js +0 -0
  112. package/dist/core/markdown.js +0 -0
  113. package/dist/core/memory-git.js +0 -0
  114. package/dist/core/migration.js +0 -0
  115. package/dist/core/project-registry.js +0 -0
  116. package/dist/core/reflection-safety.js +0 -0
  117. package/dist/core/repo-analysis.js +0 -0
  118. package/dist/core/reputation.js +0 -0
  119. package/dist/core/runtime.js +18 -14
  120. package/dist/core/schema.js +0 -0
  121. package/dist/core/search.js +0 -0
  122. package/dist/core/security.js +0 -0
  123. package/dist/core/setup-state.js +0 -0
  124. package/dist/core/state.js +21 -4
  125. package/dist/core/store-resolution.js +0 -0
  126. package/dist/core/sync-remote.js +0 -0
  127. package/dist/core/traps.js +0 -0
  128. package/docs/adapters/openclaw.md +43 -0
  129. package/docs/cli.md +1230 -0
  130. package/docs/concepts/coordination.md +52 -0
  131. package/docs/concepts/memory.md +87 -0
  132. package/docs/concepts/plans-and-claims.md +139 -0
  133. package/docs/concepts/runtime-notes.md +38 -0
  134. package/docs/concepts/workspace-bootstrapping.md +40 -0
  135. package/docs/context-format-changelog.md +35 -0
  136. package/docs/context-format.md +48 -0
  137. package/docs/integrations/agents.md +169 -0
  138. package/docs/integrations/claude-code.md +23 -0
  139. package/docs/integrations/codex.md +23 -0
  140. package/docs/integrations/copilot.md +21 -0
  141. package/docs/integrations/cursor.md +23 -0
  142. package/docs/integrations/mcp.md +51 -0
  143. package/docs/integrations/overview.md +61 -0
  144. package/docs/mcp-schema-changelog.md +108 -0
  145. package/docs/product/positioning.md +97 -0
  146. package/docs/quickstart.md +99 -0
  147. package/docs/reputation.md +52 -0
  148. package/docs/review.md +43 -0
  149. package/docs/security.md +53 -0
  150. package/docs/storage.md +81 -0
  151. package/package.json +7 -6
File without changes
@@ -2,7 +2,7 @@ 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 } from './io.js';
5
+ import { resolveEntityDir, withStoreLock } from './io.js';
6
6
  import { nowISO, getNextShortLabel } from './ids.js';
7
7
  import { JsonStore } from './json-store.js';
8
8
  function inboxDir(cwd, mode = 'read') {
@@ -35,8 +35,10 @@ function candidateStore(dest = 'pending', cwd) {
35
35
  });
36
36
  }
37
37
  export function saveCandidate(candidate, cwd) {
38
- ensureInboxDirs(cwd);
39
- candidateStore('pending', cwd).save(CandidateSchema.parse(candidate));
38
+ withStoreLock(cwd, () => {
39
+ ensureInboxDirs(cwd);
40
+ candidateStore('pending', cwd).save(CandidateSchema.parse(candidate));
41
+ });
40
42
  }
41
43
  export function loadCandidate(id, cwd) {
42
44
  return candidateStore('pending', cwd).load(id);
@@ -49,9 +51,11 @@ export function listCandidates(status, cwd) {
49
51
  return status ? candidates.filter((candidate) => candidate.status === status) : candidates;
50
52
  }
51
53
  export function archiveCandidate(candidate, dest, cwd) {
52
- ensureInboxDirs(cwd);
53
- candidateStore(dest, cwd).save(CandidateSchema.parse(candidate));
54
- candidateStore('pending', cwd).delete(candidate.id);
54
+ withStoreLock(cwd, () => {
55
+ ensureInboxDirs(cwd);
56
+ candidateStore(dest, cwd).save(CandidateSchema.parse(candidate));
57
+ candidateStore('pending', cwd).delete(candidate.id);
58
+ });
55
59
  }
56
60
  export function listArchivedCandidates(dest, cwd) {
57
61
  return candidateStore(dest, cwd).list();
File without changes
@@ -1,7 +1,7 @@
1
1
  import crypto from 'node:crypto';
2
2
  import fs from 'node:fs';
3
3
  import { ClaimSchema } from './schema.js';
4
- import { resolveEntityDir } from './io.js';
4
+ import { resolveEntityDir, withStoreLock } from './io.js';
5
5
  import { nowISO } from './ids.js';
6
6
  import { JsonStore } from './json-store.js';
7
7
  function claimsDir(cwd, mode = 'read') {
@@ -22,14 +22,16 @@ function claimStore(cwd) {
22
22
  });
23
23
  }
24
24
  export function saveClaim(claim, cwd) {
25
- ensureClaimsDir(cwd);
26
- const writeStore = new JsonStore({
27
- dirPath: claimsDir(cwd, 'write'),
28
- documentType: 'claim',
29
- getId: (c) => c.id,
30
- sort: (a, b) => a.created_at.localeCompare(b.created_at),
25
+ withStoreLock(cwd, () => {
26
+ ensureClaimsDir(cwd);
27
+ const writeStore = new JsonStore({
28
+ dirPath: claimsDir(cwd, 'write'),
29
+ documentType: 'claim',
30
+ getId: (c) => c.id,
31
+ sort: (a, b) => a.created_at.localeCompare(b.created_at),
32
+ });
33
+ writeStore.save(ClaimSchema.parse(claim));
31
34
  });
32
- writeStore.save(ClaimSchema.parse(claim));
33
35
  }
34
36
  export function loadClaim(id, cwd) {
35
37
  return claimStore(cwd).load(id);
File without changes
File without changes
File without changes
File without changes
@@ -5,7 +5,7 @@ import { listClaims } from './claims.js';
5
5
  import { inferProjectFromTarget, loadInstructions, resolveInstructions } from './instructions.js';
6
6
  import { buildReputationSummary, findAgentReputationSummary } from './reputation.js';
7
7
  import { listRuntimeNotes } from './runtime.js';
8
- import { loadState, saveState } from './state.js';
8
+ import { loadState, persistState } from './state.js';
9
9
  export function buildCoordinationSnapshot(options = {}) {
10
10
  const config = loadConfig(options.cwd);
11
11
  const state = loadState(options.cwd);
@@ -58,7 +58,7 @@ export function buildCoordinationSnapshot(options = {}) {
58
58
  }
59
59
  }
60
60
  if (changed)
61
- saveState(state, options.cwd);
61
+ persistState(state, options.cwd);
62
62
  }
63
63
  return {
64
64
  project_id: config.project_id,
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
package/dist/core/host.js CHANGED
File without changes
File without changes
package/dist/core/ids.js CHANGED
File without changes
File without changes
@@ -1,5 +1,5 @@
1
1
  import fs from 'node:fs';
2
- import { resolveEntityDir } from './io.js';
2
+ import { resolveEntityDir, withStoreLock } from './io.js';
3
3
  import { generateId } from './ids.js';
4
4
  import { InstructionEntrySchema } from './schema.js';
5
5
  import { JsonStore } from './json-store.js';
@@ -19,7 +19,9 @@ export function loadInstructions(cwd) {
19
19
  return instructionStore(cwd).list();
20
20
  }
21
21
  export function saveInstruction(entry, cwd) {
22
- instructionStore(cwd, 'write').save(InstructionEntrySchema.parse(entry));
22
+ withStoreLock(cwd, () => {
23
+ instructionStore(cwd, 'write').save(InstructionEntrySchema.parse(entry));
24
+ });
23
25
  }
24
26
  export function createInstruction(text, options, cwd) {
25
27
  const entries = loadInstructions(cwd);
package/dist/core/io.js CHANGED
@@ -2,6 +2,7 @@ import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { withLock, cleanStaleLocks } from './lock.js';
4
4
  export const MEMORY_DIR = '.brainclaw';
5
+ const STORE_LOCK_BASENAME = '.store-mutation';
5
6
  const RETRYABLE_RENAME_ERROR_CODES = new Set(['EPERM', 'EBUSY', 'EACCES']);
6
7
  const DEFAULT_RENAME_RETRY_ATTEMPTS = 6;
7
8
  const DEFAULT_RENAME_RETRY_DELAY_MS = 25;
@@ -72,6 +73,9 @@ export function memoryDir(cwd = process.cwd(), preferredDirName) {
72
73
  export function memoryPath(filename, cwd, preferredDirName) {
73
74
  return path.join(memoryDir(cwd, preferredDirName), filename);
74
75
  }
76
+ export function storeLockPath(cwd, preferredDirName) {
77
+ return memoryPath(STORE_LOCK_BASENAME, cwd, preferredDirName);
78
+ }
75
79
  export function memoryExists(cwd, preferredDirName) {
76
80
  return fs.existsSync(memoryDir(cwd, preferredDirName));
77
81
  }
@@ -95,6 +99,10 @@ export function ensureMemoryDir(cwd, preferredDirName) {
95
99
  }
96
100
  }
97
101
  }
102
+ export function withStoreLock(cwd = process.cwd(), fn, preferredDirName) {
103
+ ensureMemoryDir(cwd, preferredDirName);
104
+ return withLock(storeLockPath(cwd, preferredDirName), fn);
105
+ }
98
106
  /** Check if a path is a file, or a directory with at least one entry. */
99
107
  function hasContent(p) {
100
108
  try {
File without changes
File without changes
package/dist/core/lock.js CHANGED
@@ -3,6 +3,7 @@ import path from 'node:path';
3
3
  const DEFAULT_TIMEOUT_MS = 2000;
4
4
  const LOCK_RETRY_INTERVAL_MS = 50;
5
5
  const LOCK_EXPIRY_MS = 5000;
6
+ const heldLocks = new Map();
6
7
  function lockFilePath(targetPath) {
7
8
  return targetPath + '.lock';
8
9
  }
@@ -59,22 +60,37 @@ function tryBreakLock(lockPath) {
59
60
  }
60
61
  export function acquireLock(targetPath, timeoutMs = DEFAULT_TIMEOUT_MS) {
61
62
  const lockPath = lockFilePath(targetPath);
63
+ const heldCount = heldLocks.get(lockPath);
64
+ if (heldCount) {
65
+ heldLocks.set(lockPath, heldCount + 1);
66
+ return true;
67
+ }
62
68
  const deadline = Date.now() + timeoutMs;
63
69
  const dir = path.dirname(lockPath);
64
70
  if (!fs.existsSync(dir)) {
65
71
  fs.mkdirSync(dir, { recursive: true });
66
72
  }
67
73
  while (Date.now() < deadline) {
68
- if (tryCreateLock(lockPath))
74
+ if (tryCreateLock(lockPath)) {
75
+ heldLocks.set(lockPath, 1);
69
76
  return true;
70
- if (tryBreakLock(lockPath))
77
+ }
78
+ if (tryBreakLock(lockPath)) {
79
+ heldLocks.set(lockPath, 1);
71
80
  return true;
81
+ }
72
82
  syncSleep(Math.min(LOCK_RETRY_INTERVAL_MS, deadline - Date.now()));
73
83
  }
74
84
  return false;
75
85
  }
76
86
  export function releaseLock(targetPath) {
77
87
  const lockPath = lockFilePath(targetPath);
88
+ const heldCount = heldLocks.get(lockPath);
89
+ if (heldCount && heldCount > 1) {
90
+ heldLocks.set(lockPath, heldCount - 1);
91
+ return;
92
+ }
93
+ heldLocks.delete(lockPath);
78
94
  try {
79
95
  if (fs.existsSync(lockPath)) {
80
96
  fs.unlinkSync(lockPath);
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
@@ -2,7 +2,7 @@ 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 } from './io.js';
5
+ import { resolveEntityDir, withStoreLock } from './io.js';
6
6
  import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
7
7
  import { RuntimeNoteSchema } from './schema.js';
8
8
  import { commitMemoryChange } from './memory-git.js';
@@ -40,13 +40,15 @@ export function saveRuntimeNote(note, cwd) {
40
40
  const persistedNote = visibility === 'shared'
41
41
  ? { ...note, visibility, host_id: hostId }
42
42
  : { ...note, visibility, host_id: hostId };
43
- ensureRuntimeDir(note.agent, cwd, visibility, hostId);
44
- const filepath = visibility === 'shared'
45
- ? path.join(sharedAgentDir(note.agent, cwd, 'write'), `${note.id}.json`)
46
- : path.join(hostAgentDir(visibility, hostId, note.agent, cwd, 'write'), `${note.id}.json`);
47
- saveVersionedJsonFile('runtime_note', filepath, RuntimeNoteSchema.parse(persistedNote));
48
- appendEvent({ action: 'create', item_type: 'runtime_note', item_id: note.id, agent: note.agent, agent_id: note.agent_id }, cwd);
49
- commitMemoryChange(`runtime note: ${note.note_type ?? 'note'} (${note.agent})`, cwd);
43
+ withStoreLock(cwd, () => {
44
+ ensureRuntimeDir(note.agent, cwd, visibility, hostId);
45
+ const filepath = visibility === 'shared'
46
+ ? path.join(sharedAgentDir(note.agent, cwd, 'write'), `${note.id}.json`)
47
+ : path.join(hostAgentDir(visibility, hostId, note.agent, cwd, 'write'), `${note.id}.json`);
48
+ saveVersionedJsonFile('runtime_note', filepath, RuntimeNoteSchema.parse(persistedNote));
49
+ appendEvent({ action: 'create', item_type: 'runtime_note', item_id: note.id, agent: note.agent, agent_id: note.agent_id }, cwd);
50
+ commitMemoryChange(`runtime note: ${note.note_type ?? 'note'} (${note.agent})`, cwd);
51
+ });
50
52
  }
51
53
  export function runtimeNotePath(note, cwd) {
52
54
  const visibility = note.visibility ?? 'shared';
@@ -56,12 +58,14 @@ export function runtimeNotePath(note, cwd) {
56
58
  : path.join(hostAgentDir(visibility, hostId, note.agent, cwd), `${note.id}.json`);
57
59
  }
58
60
  export function deleteRuntimeNote(note, cwd) {
59
- const filepath = runtimeNotePath(note, cwd);
60
- if (!fs.existsSync(filepath)) {
61
- return false;
62
- }
63
- fs.unlinkSync(filepath);
64
- return true;
61
+ return withStoreLock(cwd, () => {
62
+ const filepath = runtimeNotePath(note, cwd);
63
+ if (!fs.existsSync(filepath)) {
64
+ return false;
65
+ }
66
+ fs.unlinkSync(filepath);
67
+ return true;
68
+ });
65
69
  }
66
70
  function readAgentNotes(dir, agent) {
67
71
  if (!fs.existsSync(dir))
File without changes
File without changes
File without changes
File without changes
@@ -1,10 +1,11 @@
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, resolveEntityDir } from './io.js';
4
+ import { ensureMemoryDir, memoryPath, resolveEntityDir, withStoreLock, writeFileAtomic } from './io.js';
5
5
  import { commitMemoryChange } from './memory-git.js';
6
6
  import { appendEvent } from './event-log.js';
7
7
  import { loadVersionedJsonFile, saveVersionedJsonFile } from './migration.js';
8
+ import { generateMarkdown } from './markdown.js';
8
9
  export function emptyState() {
9
10
  return {
10
11
  version: 1,
@@ -69,15 +70,31 @@ function syncDirectory(dirPath, items, documentType) {
69
70
  }
70
71
  }
71
72
  export function saveState(state, cwd) {
73
+ persistState(state, cwd, { writeProjectMarkdown: false });
74
+ }
75
+ function writeStateDirectories(state, cwd) {
72
76
  ensureMemoryDir(cwd);
73
77
  const effectiveCwd = cwd ?? process.cwd();
74
- // Write to entity-aligned directories
75
78
  syncDirectory(resolveEntityDir('constraints', effectiveCwd, 'write'), state.active_constraints, 'constraint');
76
79
  syncDirectory(resolveEntityDir('decisions', effectiveCwd, 'write'), state.recent_decisions, 'decision');
77
80
  syncDirectory(resolveEntityDir('traps', effectiveCwd, 'write'), state.known_traps, 'trap');
78
81
  syncDirectory(resolveEntityDir('handoffs', effectiveCwd, 'write'), state.open_handoffs, 'handoff');
79
82
  syncDirectory(resolveEntityDir('plans', effectiveCwd, 'write'), state.plan_items, 'plan');
80
- appendEvent({ action: 'update', item_type: 'state', agent: 'system' }, cwd);
81
- commitMemoryChange('state update', cwd);
83
+ }
84
+ export function persistState(state, cwd, options = {}) {
85
+ const effectiveCwd = cwd ?? process.cwd();
86
+ withStoreLock(effectiveCwd, () => {
87
+ writeStateDirectories(state, effectiveCwd);
88
+ if (options.writeProjectMarkdown ?? true) {
89
+ writeFileAtomic(memoryPath('project.md', effectiveCwd), generateMarkdown(state, effectiveCwd));
90
+ }
91
+ appendEvent({
92
+ action: options.eventAction ?? 'update',
93
+ item_type: 'state',
94
+ agent: 'system',
95
+ summary: options.eventSummary,
96
+ }, effectiveCwd);
97
+ commitMemoryChange(options.commitMessage ?? 'state update', effectiveCwd);
98
+ });
82
99
  }
83
100
  //# sourceMappingURL=state.js.map
File without changes
File without changes
File without changes
@@ -0,0 +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.