brainclaw 1.5.4 → 1.6.0

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 (60) hide show
  1. package/README.md +52 -28
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +159 -12
  4. package/dist/commands/assignment-resource.js +182 -0
  5. package/dist/commands/bootstrap-loop.js +206 -0
  6. package/dist/commands/init.js +158 -22
  7. package/dist/commands/loop.js +156 -0
  8. package/dist/commands/loops-handlers.js +110 -55
  9. package/dist/commands/mcp-read-handlers.js +45 -4
  10. package/dist/commands/mcp.js +628 -205
  11. package/dist/commands/questions.js +180 -0
  12. package/dist/commands/reply.js +190 -0
  13. package/dist/commands/session-end.js +105 -3
  14. package/dist/commands/session-start.js +32 -53
  15. package/dist/commands/setup.js +87 -48
  16. package/dist/commands/switch.js +21 -1
  17. package/dist/core/agentrun-reconciler.js +65 -0
  18. package/dist/core/agentruns.js +10 -0
  19. package/dist/core/assignments.js +29 -10
  20. package/dist/core/claims.js +29 -0
  21. package/dist/core/context.js +1 -1
  22. package/dist/core/coordination.js +1 -1
  23. package/dist/core/dispatch-status.js +219 -0
  24. package/dist/core/entity-operations.js +166 -10
  25. package/dist/core/entity-registry.js +11 -10
  26. package/dist/core/execution-adapters.js +38 -2
  27. package/dist/core/facade-schema.js +55 -0
  28. package/dist/core/federation-cloud.js +27 -12
  29. package/dist/core/federation-materialize.js +57 -0
  30. package/dist/core/instruction-templates.js +2 -0
  31. package/dist/core/loops/bootstrap-acquire.js +195 -0
  32. package/dist/core/loops/facade-schema.js +68 -1
  33. package/dist/core/loops/hooks/bootstrap-write.js +144 -0
  34. package/dist/core/loops/hooks/notify-operator.js +148 -0
  35. package/dist/core/loops/hooks/survey-source-reader.js +256 -0
  36. package/dist/core/loops/index.js +8 -2
  37. package/dist/core/loops/next-expected.js +63 -0
  38. package/dist/core/loops/presets/bootstrap.js +75 -0
  39. package/dist/core/loops/presets/index.js +16 -0
  40. package/dist/core/loops/store.js +224 -4
  41. package/dist/core/loops/types.js +346 -1
  42. package/dist/core/loops/verbs.js +739 -6
  43. package/dist/core/schema.js +31 -2
  44. package/dist/core/state.js +62 -0
  45. package/dist/core/store-resolution.js +26 -16
  46. package/dist/facts.js +7 -5
  47. package/dist/facts.json +6 -4
  48. package/docs/cli.md +115 -30
  49. package/docs/concepts/dispatch-lifecycle.md +228 -0
  50. package/docs/concepts/loop-engine.md +55 -0
  51. package/docs/concepts/multi-agent-workflows.md +167 -166
  52. package/docs/concepts/troubleshooting.md +10 -2
  53. package/docs/integrations/agents.md +14 -14
  54. package/docs/integrations/codex.md +15 -12
  55. package/docs/integrations/mcp.md +10 -4
  56. package/docs/integrations/overview.md +11 -0
  57. package/docs/playbooks/productivity/index.md +3 -3
  58. package/docs/quickstart-existing-project.md +48 -28
  59. package/docs/quickstart.md +42 -28
  60. package/package.json +1 -1
@@ -232,6 +232,17 @@ export const HandoffSchema = z.object({
232
232
  */
233
233
  superseded_by: z.string().optional(),
234
234
  supersedes: z.string().optional(),
235
+ /**
236
+ * pln#365 finalization: opt-in cloud federation. Optional (no default) so
237
+ * existing on-disk handoffs without the field continue to parse, AND so
238
+ * an unset value means "stay local" rather than "implicitly shared". To
239
+ * opt a handoff into cloud push, set `visibility: 'shared'` explicitly
240
+ * when building it. Session-end push uses literal `visibility === 'shared'`
241
+ * (cf. session-end.ts:isExplicitlyShared). Risk it mitigates: a session
242
+ * handoff with `snapshot.diff` carrying secrets would otherwise leak the
243
+ * moment cloud_sync flips on, by virtue of being created at all.
244
+ */
245
+ visibility: MemoryVisibilitySchema.optional(),
235
246
  });
236
247
  export const PlanStatusSchema = z.enum(['todo', 'in_progress', 'blocked', 'done', 'dropped']);
237
248
  export const PlanStepStatusSchema = z.enum(['todo', 'in_progress', 'testing', 'done', 'blocked']);
@@ -243,7 +254,8 @@ export const PlanStepSchema = z.object({
243
254
  created_at: z.string(),
244
255
  updated_at: z.string(),
245
256
  });
246
- export const PlanTypeSchema = z.enum(['feat', 'fix', 'chore', 'spike', 'doc']).default('feat');
257
+ export const PlanTypeEnumSchema = z.enum(['feat', 'fix', 'chore', 'spike', 'doc']);
258
+ export const PlanTypeSchema = PlanTypeEnumSchema.default('feat');
247
259
  export const PlanItemSchema = z.object({
248
260
  schema_version: z.number().int().positive().optional(),
249
261
  id: z.string(),
@@ -532,6 +544,13 @@ export const CandidateSchema = z.preprocess(candidatePreprocess, z.object({
532
544
  resolved_by: z.string().optional(),
533
545
  resolution_reason: z.string().optional(),
534
546
  provenance: ProvenancePassthroughSchema,
547
+ /**
548
+ * pln#365 finalization: opt-in cloud federation. Mirrors HandoffSchema —
549
+ * optional (no default) so unset means "stay local" and an agent must
550
+ * explicitly set `visibility: 'shared'` to opt a candidate into cloud
551
+ * push. Conservative because candidate.text can carry secrets.
552
+ */
553
+ visibility: MemoryVisibilitySchema.optional(),
535
554
  }));
536
555
  export const ReflectiveMemoryConfigSchema = z.object({
537
556
  enabled: z.boolean().default(true),
@@ -598,6 +617,7 @@ export const AssignmentStatusSchema = z.enum([
598
617
  'accepted', // Worker acknowledged receipt
599
618
  'started', // Worker reports active work begun
600
619
  'completed', // Worker reports successful completion
620
+ 'cancelled', // Supervisor/admin aborted the assignment explicitly
601
621
  'failed', // Worker reports failure
602
622
  'blocked', // Worker reports external blocker
603
623
  'timed_out', // Sweeper detected no heartbeat within TTL
@@ -642,6 +662,7 @@ export const AssignmentSchema = z.object({
642
662
  accepted_at: z.string().optional(),
643
663
  started_at: z.string().optional(),
644
664
  completed_at: z.string().optional(),
665
+ cancelled_at: z.string().optional(),
645
666
  failed_at: z.string().optional(),
646
667
  blocked_at: z.string().optional(),
647
668
  timed_out_at: z.string().optional(),
@@ -754,6 +775,7 @@ export const ActionRequiredSchema = z.object({
754
775
  tags: TagsWithDefaultSchema,
755
776
  });
756
777
  // --- Runtime notes schemas ---
778
+ export const RuntimeNoteTypeSchema = z.enum(['observation', 'session_start', 'session_end']);
757
779
  export const RuntimeNoteSchema = z.object({
758
780
  schema_version: z.number().int().positive().optional(),
759
781
  id: z.string(),
@@ -769,7 +791,7 @@ export const RuntimeNoteSchema = z.object({
769
791
  visibility: MemoryVisibilitySchema.default('shared'),
770
792
  host_id: z.string().optional(),
771
793
  expires_at: z.string().optional(),
772
- note_type: z.enum(['observation', 'session_start', 'session_end']).default('observation'),
794
+ note_type: RuntimeNoteTypeSchema.default('observation'),
773
795
  model: z.string().optional(),
774
796
  provenance: ProvenancePassthroughSchema,
775
797
  });
@@ -814,6 +836,7 @@ export const RuntimeEventTypeSchema = z.enum([
814
836
  'assignment_started',
815
837
  'assignment_progress',
816
838
  'assignment_completed',
839
+ 'assignment_cancelled',
817
840
  'assignment_failed',
818
841
  'assignment_blocked',
819
842
  'assignment_timed_out',
@@ -934,6 +957,11 @@ export const RemoteSyncSchema = z.object({
934
957
  ssh_key_path: z.string().optional(),
935
958
  sync_strategy: z.enum(['pull-only', 'push-pull', 'pr-based']).default('push-pull'),
936
959
  });
960
+ export const CloudSyncConfigSchema = z.object({
961
+ enabled: z.boolean().default(false),
962
+ endpoint: z.string().default('https://app.brainclaw.dev'),
963
+ api_key: z.string().optional(),
964
+ });
937
965
  export const SessionSnapshotSchema = z.object({
938
966
  schema_version: z.number().int().positive().optional(),
939
967
  session_id: z.string(),
@@ -1229,6 +1257,7 @@ export const ConfigSchema = z.object({
1229
1257
  target_audience: z.enum(['human', 'agent']).optional().default('human'),
1230
1258
  openclaw_bridge: z.boolean().optional().default(false),
1231
1259
  remote_sync: RemoteSyncSchema.optional(),
1260
+ cloud_sync: CloudSyncConfigSchema.optional(),
1232
1261
  telemetry: z.literal(false),
1233
1262
  allow_network: z.literal(false),
1234
1263
  redaction: RedactionConfigSchema,
@@ -37,6 +37,68 @@ function loadDirectoryItems(dirPath, schema, documentType) {
37
37
  }
38
38
  return items;
39
39
  }
40
+ const ENTITY_LOAD_CONFIG = {
41
+ constraint: { subdir: 'constraints', documentType: 'constraint', recursive: false },
42
+ decision: { subdir: 'decisions', documentType: 'decision', recursive: false },
43
+ trap: { subdir: 'traps', documentType: 'trap', recursive: false },
44
+ handoff: { subdir: 'handoffs', documentType: 'handoff', recursive: false },
45
+ plan: { subdir: 'plans', documentType: 'plan', recursive: false },
46
+ candidate: { subdir: 'inbox', documentType: 'candidate', recursive: false },
47
+ claim: { subdir: 'claims', documentType: 'claim', recursive: false },
48
+ assignment: { subdir: 'assignments', documentType: 'assignment', recursive: false },
49
+ agent_run: { subdir: 'runs', documentType: 'agent_run', recursive: false },
50
+ action: { subdir: 'actions', documentType: 'action_required', recursive: false },
51
+ runtime_note: { subdir: 'runtime', documentType: 'runtime_note', recursive: true },
52
+ };
53
+ function listJsonFiles(dirPath, recursive) {
54
+ if (!fs.existsSync(dirPath))
55
+ return [];
56
+ const files = [];
57
+ for (const entry of fs.readdirSync(dirPath).sort()) {
58
+ const fullPath = path.join(dirPath, entry);
59
+ const stat = fs.statSync(fullPath);
60
+ if (stat.isDirectory()) {
61
+ if (recursive)
62
+ files.push(...listJsonFiles(fullPath, true));
63
+ continue;
64
+ }
65
+ if (entry.endsWith('.json'))
66
+ files.push(fullPath);
67
+ }
68
+ return files;
69
+ }
70
+ function validationErrorsFrom(error) {
71
+ if (error && typeof error === 'object' && 'issues' in error && Array.isArray(error.issues)) {
72
+ return (error.issues).map((issue) => {
73
+ const issuePath = Array.isArray(issue.path) && issue.path.length > 0 ? `${issue.path.join('.')}: ` : '';
74
+ return `${issuePath}${issue.message ?? 'validation failed'}`;
75
+ });
76
+ }
77
+ return [error instanceof Error ? error.message : String(error)];
78
+ }
79
+ export function collectLoadValidationWarnings(entity, cwd) {
80
+ const config = ENTITY_LOAD_CONFIG[entity];
81
+ if (!config)
82
+ return [];
83
+ const effectiveCwd = cwd ?? process.cwd();
84
+ const dirPath = resolveEntityDir(config.subdir, effectiveCwd, 'read');
85
+ return listJsonFiles(dirPath, config.recursive).flatMap((filepath) => {
86
+ try {
87
+ loadVersionedJsonFile(config.documentType, filepath);
88
+ return [];
89
+ }
90
+ catch (error) {
91
+ return [{
92
+ entity_id: path.basename(filepath, '.json'),
93
+ validation_errors: validationErrorsFrom(error),
94
+ path: filepath,
95
+ }];
96
+ }
97
+ });
98
+ }
99
+ export function findLoadValidationWarning(entity, id, cwd) {
100
+ return collectLoadValidationWarnings(entity, cwd).find((warning) => warning.entity_id === id);
101
+ }
40
102
  export function loadState(cwd) {
41
103
  // Load from entity-aligned directories (with legacy fallback)
42
104
  const effectiveCwd = cwd ?? process.cwd();
@@ -91,48 +91,53 @@ export function resolveTargetStore(cwd = process.cwd(), target = 'local', option
91
91
  *
92
92
  * Priority:
93
93
  * 1. explicitCwd (--cwd flag)
94
- * 2. BRAINCLAW_CWD env var → absolute workspace path injected by MCP configs
95
- * 3. BRAINCLAW_PROJECT env var → resolved by name/path from workspace
96
- * 4. Session-scoped active project (from .current-session)
94
+ * 2. BRAINCLAW_CWD env var → workspace anchor injected by MCP configs
95
+ * 3. BRAINCLAW_PROJECT env var → resolved by name/path from workspace anchor
96
+ * 4. Session-scoped active project (from .current-session under the anchor)
97
97
  * 5. Global active-project.json in workspace root
98
- * 6. process.cwd()
98
+ * 6. Workspace anchor or process.cwd()
99
99
  */
100
100
  export function resolveEffectiveCwd(options = {}) {
101
+ const baseCwd = path.resolve(options.baseCwd ?? process.cwd());
101
102
  // 1. Explicit --cwd flag
102
103
  if (options.explicitCwd) {
103
104
  return path.resolve(options.explicitCwd);
104
105
  }
105
- // 2. BRAINCLAW_CWD env var — set by MCP configs to bind to the workspace
106
- // regardless of the IDE's process.cwd() at launch time
106
+ // 2. BRAINCLAW_CWD env var — set by MCP configs to anchor resolution to the
107
+ // workspace regardless of the IDE's process.cwd() at launch time. It is a
108
+ // workspace anchor, not the final answer: session/global active project
109
+ // state still overrides it.
110
+ let anchorCwd = baseCwd;
107
111
  const envCwd = process.env.BRAINCLAW_CWD?.trim();
108
- if (envCwd && fs.existsSync(path.join(path.resolve(envCwd), MEMORY_DIR, 'config.yaml'))) {
109
- return path.resolve(envCwd);
112
+ const hasEnvWorkspace = !!envCwd && fs.existsSync(path.join(path.resolve(envCwd), MEMORY_DIR, 'config.yaml'));
113
+ if (hasEnvWorkspace) {
114
+ anchorCwd = path.resolve(envCwd);
110
115
  }
111
116
  // 3. BRAINCLAW_PROJECT env var
112
117
  const envProject = process.env.BRAINCLAW_PROJECT;
113
118
  if (envProject) {
114
- const resolved = resolveProjectRef(envProject, process.cwd(), options.storeChainOptions);
119
+ const resolved = resolveProjectRef(envProject, anchorCwd, options.storeChainOptions);
115
120
  if (resolved)
116
121
  return resolved;
117
122
  }
118
- // 3. Session-scoped active project (per-agent, no cross-agent interference)
119
- const session = loadCurrentSession(process.cwd());
123
+ // 4. Session-scoped active project (per-agent, no cross-agent interference)
124
+ const session = loadCurrentSession(anchorCwd);
120
125
  if (session?.active_project) {
121
126
  const sp = session.active_project;
122
127
  if (fs.existsSync(path.join(sp.path, MEMORY_DIR, 'config.yaml'))) {
123
128
  return sp.path;
124
129
  }
125
130
  }
126
- // 4. Global active-project.json from workspace root
127
- const wsRoot = resolveWorkspaceRoot(process.cwd(), options.storeChainOptions);
131
+ // 5. Global active-project.json from workspace root
132
+ const wsRoot = hasEnvWorkspace ? anchorCwd : resolveWorkspaceRoot(anchorCwd, options.storeChainOptions);
128
133
  if (wsRoot) {
129
134
  const active = loadActiveProject(wsRoot);
130
135
  if (active && fs.existsSync(path.join(active.path, MEMORY_DIR, 'config.yaml'))) {
131
136
  return active.path;
132
137
  }
133
138
  }
134
- // 5. Default
135
- return process.cwd();
139
+ // 6. Default
140
+ return anchorCwd;
136
141
  }
137
142
  /**
138
143
  * Find the workspace root (farthest store in the chain, or the one with
@@ -150,9 +155,14 @@ export function resolveWorkspaceRoot(cwd = process.cwd(), options = {}) {
150
155
  * Returns undefined when the reference cannot be resolved to a valid brainclaw project.
151
156
  */
152
157
  export function resolveProjectRef(ref, cwd = process.cwd(), storeChainOptions) {
158
+ const envWorkspace = process.env.BRAINCLAW_CWD?.trim();
159
+ const workspaceAnchor = envWorkspace && fs.existsSync(path.join(path.resolve(envWorkspace), MEMORY_DIR, 'config.yaml'))
160
+ ? path.resolve(envWorkspace)
161
+ : undefined;
153
162
  // Walk UP from real cwd to find the outermost .brainclaw/ — this avoids
154
163
  // circular resolution when an active project narrows the workspace view.
155
- const wsRoot = findOutermostBrainclawRoot(process.cwd())
164
+ const wsRoot = workspaceAnchor
165
+ ?? findOutermostBrainclawRoot(cwd)
156
166
  ?? resolveWorkspaceRoot(cwd, storeChainOptions);
157
167
  if (!wsRoot)
158
168
  return undefined;
package/dist/facts.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // Generated by scripts/emit-site-facts.mjs at build time. Do not edit manually.
2
- // Source: brainclaw v1.5.4 on 2026-05-10T22:45:47.168Z
2
+ // Source: brainclaw v1.6.0 on 2026-05-22T22:24:08.363Z
3
3
  export const FACTS = {
4
- "version": "1.5.4",
5
- "generated_at": "2026-05-10T22:45:47.168Z",
4
+ "version": "1.6.0",
5
+ "generated_at": "2026-05-22T22:24:08.363Z",
6
6
  "tools": {
7
- "count": 60,
8
- "published_count": 59,
7
+ "count": 62,
8
+ "published_count": 61,
9
9
  "names": [
10
10
  "bclaw_bootstrap",
11
11
  "bclaw_release_notes",
@@ -30,10 +30,12 @@ export const FACTS = {
30
30
  "bclaw_check_security",
31
31
  "bclaw_read_inbox",
32
32
  "bclaw_get_thread",
33
+ "bclaw_dispatch_status",
33
34
  "bclaw_dispatch",
34
35
  "bclaw_send_message",
35
36
  "bclaw_ack_message",
36
37
  "bclaw_setup",
38
+ "bclaw_init_project",
37
39
  "bclaw_write_note",
38
40
  "bclaw_quick_capture",
39
41
  "bclaw_claim",
package/dist/facts.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
- "version": "1.5.4",
3
- "generated_at": "2026-05-10T22:45:47.168Z",
2
+ "version": "1.6.0",
3
+ "generated_at": "2026-05-22T22:24:08.363Z",
4
4
  "tools": {
5
- "count": 60,
6
- "published_count": 59,
5
+ "count": 62,
6
+ "published_count": 61,
7
7
  "names": [
8
8
  "bclaw_bootstrap",
9
9
  "bclaw_release_notes",
@@ -28,10 +28,12 @@
28
28
  "bclaw_check_security",
29
29
  "bclaw_read_inbox",
30
30
  "bclaw_get_thread",
31
+ "bclaw_dispatch_status",
31
32
  "bclaw_dispatch",
32
33
  "bclaw_send_message",
33
34
  "bclaw_ack_message",
34
35
  "bclaw_setup",
36
+ "bclaw_init_project",
35
37
  "bclaw_write_note",
36
38
  "bclaw_quick_capture",
37
39
  "bclaw_claim",
package/docs/cli.md CHANGED
@@ -62,9 +62,9 @@ brainclaw --cwd /other/path status # one-off override without switching
62
62
 
63
63
  ## Initialize and Inspect
64
64
 
65
- ### `brainclaw setup`
66
-
67
- Global onboarding wizard — detects AI agents, installs global Brainclaw prerequisites, installs agent/MCP config, gitignores generated workspace-local integration files, and initialises multiple repositories in one pass. This is the required machine-level bootstrap before `brainclaw init`. It scans each root itself plus its direct child repositories, and ignores internal Brainclaw memory repos such as `.brainclaw/`.
65
+ ### `brainclaw setup`
66
+
67
+ Global onboarding wizard — bootstraps the machine, detects AI agents, installs global Brainclaw prerequisites, writes agent/MCP config, gitignores generated workspace-local integration files, and initialises multiple repositories in one pass. It scans each root itself plus its direct child repositories, and ignores internal Brainclaw memory repos such as `.brainclaw/`.
68
68
 
69
69
  | Option | Description |
70
70
  |---|---|
@@ -80,32 +80,57 @@ brainclaw setup --roots ~/Projects --agents detected # scan ~/Projects, confi
80
80
  brainclaw setup --roots ~/Projects,~/work --agents all # all agents, multiple roots
81
81
  ```
82
82
 
83
- **MCP usage (agent-driven):** Use `bclaw_setup` with the resume pattern — call without `step` to start, then pass `step` + `choice` to advance through each stage (`project_roots` → `repo_selection` → `agent_selection`).
84
-
85
- ---
86
-
87
- ### `brainclaw init`
88
-
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
-
91
- | Option | Description |
92
- |---|---|
93
- | `-y, --yes` | Non-interactive, accept all defaults |
94
- | `--force` | Overwrite existing initialization |
95
- | `--compact` | Generate a compact instruction file |
96
- | `--topology <value>` | Storage topology (e.g. `sidecar` to store outside the repo) |
97
- | `--project-mode <value>` | Project mode (e.g. `multi-project`) |
83
+ **MCP usage (agent-driven):** Use `bclaw_setup` with the resume pattern — call without `step` to start, then pass `step` + `choice` to advance through each stage (`project_roots` → `repo_selection` → `agent_selection`).
84
+
85
+ ---
86
+
87
+ ### `brainclaw setup-machine`
88
+
89
+ Machine-only onboarding. Detects available agents, writes the machine-level MCP/user config Brainclaw manages, refreshes machine inventory, and stops there no repository scan, no `.brainclaw/` init in the current working tree.
90
+
91
+ | Option | Description |
92
+ |---|---|
93
+ | `--agents <agents>` | Agents to configure: `all`, `detected`, or comma-separated names |
94
+ | `-y, --yes` | Accept all defaults non-interactively |
95
+
96
+ ```bash
97
+ brainclaw setup-machine
98
+ brainclaw setup-machine --yes
99
+ brainclaw setup-machine --agents codex,cursor
100
+ ```
101
+
102
+ Use this when Brainclaw is new on the current machine and you want to make the MCP surface visible to your coding agent before touching any project. The usual follow-up is `brainclaw init` inside the project you want to create or refresh.
103
+
104
+ ---
105
+
106
+ ### `brainclaw init`
107
+
108
+ Create or refresh Brainclaw state for the current project root. Detects the AI agent environment, writes or refreshes its native instruction file, and installs a git post-merge hook for automatic claim release. `init` is now safe to rerun on an already initialized project: it preserves canonical memory and refreshes the managed Brainclaw and detected-agent files. Do not run `init` from inside `.brainclaw/`; that directory is Brainclaw's own memory store, not a project root.
109
+
110
+ | Option | Description |
111
+ |---|---|
112
+ | `-y, --yes` | Non-interactive, accept all defaults |
113
+ | `--force` | Rebuild managed initialization from Brainclaw defaults while preserving canonical memory data |
114
+ | `--compact` | Generate a compact instruction file |
115
+ | `--topology <value>` | Storage topology (e.g. `sidecar` to store outside the repo) |
116
+ | `--project-mode <value>` | Project mode (e.g. `multi-project`) |
98
117
  | `--project-strategy <value>` | Project strategy (e.g. `folder`) |
99
118
  | `--no-analyze-repo` | Skip automatic repository analysis |
100
119
  | `--scan` | Scan repository for existing conventions |
101
120
 
102
121
  ```bash
103
- brainclaw init
104
- brainclaw init -y
105
- brainclaw init --force
106
- brainclaw init --topology sidecar
107
- brainclaw init --project-mode multi-project --project-strategy folder
108
- ```
122
+ brainclaw init
123
+ brainclaw init -y
124
+ brainclaw init --force
125
+ brainclaw init --topology sidecar
126
+ brainclaw init --project-mode multi-project --project-strategy folder
127
+ ```
128
+
129
+ Common onboarding split:
130
+
131
+ - new machine → `brainclaw setup-machine --yes`
132
+ - current project (new or already using Brainclaw) → `brainclaw init`
133
+ - explicit second agent on an existing Brainclaw project → `brainclaw enable-agent <agent-name>`
109
134
 
110
135
  ### `brainclaw machine-profile`
111
136
 
@@ -758,9 +783,29 @@ brainclaw claim list --agent copilot --project auth
758
783
  brainclaw claim list --all --json
759
784
  ```
760
785
 
761
- Legacy alias: `brainclaw list-claims`
762
-
763
- ### `brainclaw list-agents`
786
+ Legacy alias: `brainclaw list-claims`
787
+
788
+ ### `brainclaw assignment list`
789
+
790
+ List assignments. By default this shows only non-terminal assignments; use `--all` to include `completed`, `cancelled`, `expired`, and `rerouted`.
791
+
792
+ | Option | Description |
793
+ |---|---|
794
+ | `--json` | Output as JSON |
795
+ | `--all` | Include terminal assignments |
796
+ | `--status <status>` | Filter by assignment status |
797
+ | `--agent <name>` | Filter by agent |
798
+ | `--claim <id>` | Filter by claim ID |
799
+ | `--plan <id>` | Filter by plan ID |
800
+ | `--sequence <id>` | Filter by sequence ID |
801
+
802
+ ```bash
803
+ brainclaw assignment list
804
+ brainclaw assignment list --status blocked
805
+ brainclaw assignment list --all --json
806
+ ```
807
+
808
+ ### `brainclaw list-agents`
764
809
 
765
810
  List registered agent and human identities.
766
811
 
@@ -1113,9 +1158,49 @@ brainclaw claim release clm_001
1113
1158
  brainclaw claim release clm_001 --plan-status done
1114
1159
  ```
1115
1160
 
1116
- Legacy alias: `brainclaw release-claim <id>`
1117
-
1118
- ### `brainclaw release-claims`
1161
+ Legacy alias: `brainclaw release-claim <id>`
1162
+
1163
+ ### `brainclaw assignment get <id>`
1164
+
1165
+ Show one assignment with its lifecycle timestamps and links.
1166
+
1167
+ | Option | Description |
1168
+ |---|---|
1169
+ | `--json` | Output as JSON |
1170
+
1171
+ ```bash
1172
+ brainclaw assignment get asgn_001
1173
+ brainclaw assignment get asgn_001 --json
1174
+ ```
1175
+
1176
+ ### `brainclaw assignment update <id>`
1177
+
1178
+ Advance an assignment to a supported lifecycle status through the canonical assignment FSM.
1179
+
1180
+ | Option | Description |
1181
+ |---|---|
1182
+ | `--status <status>` | Target assignment status |
1183
+ | `--reason <text>` | Optional status reason recorded on the assignment |
1184
+
1185
+ ```bash
1186
+ brainclaw assignment update asgn_001 --status started
1187
+ brainclaw assignment update asgn_001 --status cancelled --reason "Supervisor aborted the lane"
1188
+ ```
1189
+
1190
+ ### `brainclaw assignment cancel <id>`
1191
+
1192
+ Supervisor/admin shortcut for `brainclaw assignment update <id> --status cancelled`.
1193
+
1194
+ | Option | Description |
1195
+ |---|---|
1196
+ | `--reason <text>` | Optional cancellation reason recorded on the assignment |
1197
+
1198
+ ```bash
1199
+ brainclaw assignment cancel asgn_001
1200
+ brainclaw assignment cancel asgn_001 --reason "Superseded by reroute"
1201
+ ```
1202
+
1203
+ ### `brainclaw release-claims`
1119
1204
 
1120
1205
  Release multiple claims derived from a Git diff.
1121
1206