brainclaw 1.7.5 → 1.9.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.
- package/README.md +28 -11
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/cli.js +139 -13
- package/dist/commands/add-step.js +1 -1
- package/dist/commands/bootstrap.js +2 -26
- package/dist/commands/check-security-mcp.js +50 -33
- package/dist/commands/check-security.js +86 -43
- package/dist/commands/claim.js +22 -21
- package/dist/commands/confirm.js +26 -0
- package/dist/commands/context-diff.js +1 -1
- package/dist/commands/dispatch-watch.js +142 -0
- package/dist/commands/doctor.js +113 -2
- package/dist/commands/estimation-report.js +115 -16
- package/dist/commands/harvest.js +502 -16
- package/dist/commands/init.js +123 -21
- package/dist/commands/loops-handlers.js +4 -0
- package/dist/commands/mcp-read-handlers.js +198 -29
- package/dist/commands/mcp.js +615 -92
- package/dist/commands/memory.js +21 -17
- package/dist/commands/migrate.js +81 -17
- package/dist/commands/prune.js +78 -4
- package/dist/commands/reflect.js +26 -20
- package/dist/commands/register-agent.js +57 -1
- package/dist/commands/repair.js +20 -0
- package/dist/commands/session-end.js +15 -6
- package/dist/commands/session-start.js +18 -1
- package/dist/commands/setup-security.js +39 -18
- package/dist/commands/setup.js +26 -27
- package/dist/commands/stale.js +16 -2
- package/dist/commands/uninstall.js +126 -34
- package/dist/commands/update-step.js +6 -0
- package/dist/commands/worktree.js +60 -0
- package/dist/core/actions.js +12 -3
- package/dist/core/agent-capability.js +11 -13
- package/dist/core/agent-files.js +844 -547
- package/dist/core/agent-integrations.js +0 -3
- package/dist/core/agent-inventory.js +67 -0
- package/dist/core/agent-registry.js +163 -29
- package/dist/core/agentrun-reconciler.js +33 -2
- package/dist/core/agentruns.js +7 -1
- package/dist/core/ai-agent-detection.js +31 -44
- package/dist/core/archival.js +15 -9
- package/dist/core/assignment-reconciler.js +56 -0
- package/dist/core/assignment-sweeper.js +127 -4
- package/dist/core/assignments.js +69 -11
- package/dist/core/bootstrap.js +233 -67
- package/dist/core/brainclaw-version.js +22 -0
- package/dist/core/candidates.js +21 -1
- package/dist/core/claims.js +313 -150
- package/dist/core/config.js +6 -1
- package/dist/core/context-diff.js +148 -20
- package/dist/core/context.js +129 -8
- package/dist/core/coordination.js +22 -3
- package/dist/core/dispatch-status.js +109 -5
- package/dist/core/dispatcher.js +65 -11
- package/dist/core/entity-operations.js +45 -24
- package/dist/core/entity-registry.js +31 -5
- package/dist/core/event-log.js +138 -21
- package/dist/core/events/checkpoint.js +258 -0
- package/dist/core/events/genesis.js +220 -0
- package/dist/core/events/journal.js +507 -0
- package/dist/core/events/materialize.js +126 -0
- package/dist/core/events/registry-post-image.js +110 -0
- package/dist/core/events/verify.js +109 -0
- package/dist/core/execution-adapters.js +23 -0
- package/dist/core/execution.js +25 -0
- package/dist/core/facade-schema.js +48 -0
- package/dist/core/gc-semantic.js +130 -5
- package/dist/core/handoff-snapshot.js +68 -0
- package/dist/core/ids.js +19 -8
- package/dist/core/instruction-templates.js +34 -115
- package/dist/core/io.js +39 -3
- package/dist/core/json-store.js +10 -1
- package/dist/core/lock.js +153 -28
- package/dist/core/loops/bootstrap-acquire.js +25 -1
- package/dist/core/loops/facade-schema.js +2 -0
- package/dist/core/loops/hooks/survey-signals-baseline.js +36 -0
- package/dist/core/loops/index.js +1 -0
- package/dist/core/loops/presets/bootstrap.js +7 -0
- package/dist/core/loops/store.js +17 -0
- package/dist/core/loops/verbs.js +24 -1
- package/dist/core/markdown.js +8 -76
- package/dist/core/mcp-command-resolution.js +245 -0
- package/dist/core/memory-compactor.js +5 -3
- package/dist/core/memory-lifecycle.js +282 -0
- package/dist/core/merge-risk.js +150 -0
- package/dist/core/messaging.js +8 -1
- package/dist/core/migration.js +11 -1
- package/dist/core/observer-mode.js +26 -0
- package/dist/core/operations/memory-mutation.js +90 -65
- package/dist/core/operations/plan.js +27 -1
- package/dist/core/protocol-skills.js +210 -0
- package/dist/core/reflection-safety.js +6 -7
- package/dist/core/reputation.js +84 -2
- package/dist/core/runtime-signals.js +71 -9
- package/dist/core/runtime.js +84 -1
- package/dist/core/schema.js +125 -0
- package/dist/core/security-detectors.js +125 -0
- package/dist/core/security-extract.js +189 -0
- package/dist/core/security-guard.js +107 -29
- package/dist/core/security-packages.js +121 -0
- package/dist/core/security-scoring.js +76 -9
- package/dist/core/security.js +34 -2
- package/dist/core/sequence.js +11 -2
- package/dist/core/setup-flow.js +141 -13
- package/dist/core/spawn-check.js +110 -4
- package/dist/core/staleness.js +109 -1
- package/dist/core/state.js +250 -54
- package/dist/core/store-resolution.js +19 -5
- package/dist/core/worktree.js +169 -7
- package/dist/facts.js +8 -8
- package/dist/facts.json +7 -7
- package/docs/PROTOCOL.md +223 -0
- package/docs/cli.md +11 -10
- package/docs/concepts/coordinator-runbook.md +129 -0
- package/docs/concepts/dispatch-lifecycle.md +17 -0
- package/docs/concepts/event-log-store-critique-A.md +333 -0
- package/docs/concepts/event-log-store-critique-B.md +353 -0
- package/docs/concepts/event-log-store-phase0-measurements.md +58 -0
- package/docs/concepts/event-log-store-proposal-A.md +365 -0
- package/docs/concepts/event-log-store-proposal-B.md +404 -0
- package/docs/concepts/event-log-store.md +928 -0
- package/docs/concepts/identity-model-proposal.md +371 -0
- package/docs/concepts/memory.md +5 -4
- package/docs/concepts/observer-protocol.md +361 -0
- package/docs/concepts/parallel-merge-protocol.md +71 -0
- package/docs/concepts/plans-and-claims.md +43 -0
- package/docs/concepts/skills.md +78 -0
- package/docs/concepts/workspace-bootstrapping.md +61 -0
- package/docs/integrations/agents.md +4 -4
- package/docs/integrations/cline.md +10 -11
- package/docs/integrations/codex.md +2 -2
- package/docs/integrations/continue.md +5 -5
- package/docs/integrations/copilot.md +14 -12
- package/docs/integrations/openclaw.md +7 -6
- package/docs/integrations/overview.md +7 -7
- package/docs/integrations/roo.md +3 -3
- package/docs/integrations/windsurf.md +6 -6
- package/docs/mcp-schema-changelog.md +51 -20
- package/docs/quickstart.md +48 -47
- package/docs/security.md +174 -15
- package/docs/storage.md +4 -2
- package/package.json +8 -6
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
# Observer Protocol — language-agnostic read-only surfaces
|
|
2
|
+
|
|
3
|
+
Status: spec (pln#560 step 1). Pivot deliverable: it serves the VS Code
|
|
4
|
+
extension, the JetBrains plugin, and any future surface identically. Companion
|
|
5
|
+
to `event-log-store.md` (the journal this protocol consumes) and the VS Code
|
|
6
|
+
vision §5 (the UX it powers).
|
|
7
|
+
|
|
8
|
+
## 1. The one rule
|
|
9
|
+
|
|
10
|
+
**An observability surface is a pure consumer of the event journal. It never
|
|
11
|
+
acquires a store lock, never writes inside `.brainclaw/`, never runs a polling
|
|
12
|
+
timer against the MCP server for display.** It tails the append-only journal,
|
|
13
|
+
projects board state in memory, and refreshes the affected section when a new
|
|
14
|
+
record arrives. The MCP server is reserved for *actions* (accept / release /
|
|
15
|
+
dispatch / transition) through a separate, lazily-created client.
|
|
16
|
+
|
|
17
|
+
Why this exists (2026-06-10 calibration): the prior extension "read" the board
|
|
18
|
+
by calling a path that mutated and git-committed the entire store under the
|
|
19
|
+
lock (`autoAcknowledge → persistState`, held >5s), ran the agent-run reconciler
|
|
20
|
+
twice per poll with locked writes, created ~120 locked "unverified" event files
|
|
21
|
+
per hour per run, and impersonated the parent shell's agent identity —
|
|
22
|
+
consuming that agent's cursor. A dashboard is not an agent. This protocol makes
|
|
23
|
+
that class of bug unrepresentable: a conforming observer *cannot* write.
|
|
24
|
+
|
|
25
|
+
## 2. What the observer reads
|
|
26
|
+
|
|
27
|
+
The journal defined in `event-log-store.md`:
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
.brainclaw/events/
|
|
31
|
+
meta.json # { next_seq, active_segment, entity_revs } — a cache
|
|
32
|
+
seg-<firstSeq>.jsonl # immutable once rolled; named by first seq it holds
|
|
33
|
+
seg-<firstSeq>.jsonl # active = lexicographically-last segment
|
|
34
|
+
checkpoints/ # NOT YET EMITTED by the writer (see §5) — directory
|
|
35
|
+
ckpt-<seq>.json # may be absent today; self-contained state manifest
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
**Segment naming is normative.** `firstSeq` is encoded as a **decimal,
|
|
39
|
+
zero-padded to 8 digits** (e.g. `seg-00018342.jsonl`) so directory-listing
|
|
40
|
+
lex-sort matches numeric seq order with no parsing. Implementations MUST emit
|
|
41
|
+
and accept exactly this format; any other padding (or none) breaks the
|
|
42
|
+
binary-search-by-filename in §5. The 8-digit field overflows at `seq > 1e8`;
|
|
43
|
+
at the historical write rate (~17k events to date) this is decades away, but
|
|
44
|
+
a journal that crosses the boundary requires a coordinated widen-and-pad
|
|
45
|
+
migration in writer + every observer (deferred until needed; flagged here so
|
|
46
|
+
no implementer assumes the pad width is incidental).
|
|
47
|
+
|
|
48
|
+
`meta.json` is advisory only (§4): the observer reads it to cheaply detect
|
|
49
|
+
"did anything change" but never trusts its `entity_revs` or `next_seq` for
|
|
50
|
+
correctness — those are derived from the journal tail itself.
|
|
51
|
+
|
|
52
|
+
Record envelope (v2), one JSON object per line:
|
|
53
|
+
|
|
54
|
+
```jsonc
|
|
55
|
+
{ "v": 2, "seq": 18342, "ts": "…", "writer": "w_…", "agent": "claude-code",
|
|
56
|
+
"action": "update", "item_type": "plan", "item_id": "pln_…",
|
|
57
|
+
"entity_rev": 7, "summary": "…", "payload": { /* full post-image */ } }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Action → class mapping (the observer needs the class, not a hardcoded verb
|
|
61
|
+
list — it is `ACTION_CLASS_BY_ACTION` in `event-log.ts`, and MUST be mirrored
|
|
62
|
+
in every implementation or fetched from a shared manifest):
|
|
63
|
+
|
|
64
|
+
| Class | Effect on the projection |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `entity-state` (`create`,`update`,`accept`,`reject`,`claim`,`release_claim`,`rollback`,`upgrade`,`backfill`) | upsert `payload` at `(item_type,item_id)` |
|
|
67
|
+
| `tombstone` (`delete`) | remove `(item_type,item_id)` |
|
|
68
|
+
| `journal-meta` (`checkpoint_ref`,`journal_note`,`seq_repair`,`federation_apply`) | ignore for state; `checkpoint_ref` is a bootstrap hint (§5) |
|
|
69
|
+
| `observability` (`session_start`,`session_end`,`assignment_offered`,`assignment_progress`,`run_progress`) | activity feed only — never a state upsert |
|
|
70
|
+
| `registry-lifecycle` (`assignment_*`,`run_*`) | upsert when `payload` present (phase 1.5+), else a status/activity signal |
|
|
71
|
+
|
|
72
|
+
The observer is **forward-compatible**: an unknown `action` whose class it
|
|
73
|
+
cannot resolve is applied as `entity-state` iff it carries a `payload` and an
|
|
74
|
+
`item_id`, else treated as an activity signal. Never crash on an unknown verb.
|
|
75
|
+
|
|
76
|
+
## 3. The cursor lives OUTSIDE the store
|
|
77
|
+
|
|
78
|
+
The observer's read position is a **seq watermark** persisted in *client*
|
|
79
|
+
storage, never in `.brainclaw/`:
|
|
80
|
+
|
|
81
|
+
- VS Code: `ExtensionContext.workspaceState`, key `bclaw.observer.cursor.<project_id>`.
|
|
82
|
+
- JetBrains: `PropertiesComponent` / project-scoped state, same key shape.
|
|
83
|
+
- Generic: any client-private kv keyed by `project_id`.
|
|
84
|
+
|
|
85
|
+
Shape: `{ seq: number, checkpoint_seq: number }`. `seq` = highest record seq
|
|
86
|
+
applied; `checkpoint_seq` = the checkpoint the in-memory projection was last
|
|
87
|
+
seeded from (for fast re-bootstrap). The store's own `.cursors/` directory is
|
|
88
|
+
the AGENTS' read position and is **off-limits** to observers — touching it is
|
|
89
|
+
the identity-leak bug this protocol forbids.
|
|
90
|
+
|
|
91
|
+
Rationale: a watermark survives segment rotation, compaction, and archival
|
|
92
|
+
(byte offsets do not). It is private to the surface, so N observers never
|
|
93
|
+
interfere with each other or with agents.
|
|
94
|
+
|
|
95
|
+
## 4. Change detection — a file watch, not a poll, not a lock
|
|
96
|
+
|
|
97
|
+
The observer watches the journal directory for growth and reacts:
|
|
98
|
+
|
|
99
|
+
1. Watch `.brainclaw/events/` (the active segment's size/mtime, and creation of
|
|
100
|
+
new `seg-*.jsonl`). VS Code: `FileSystemWatcher` on `events/seg-*.jsonl` +
|
|
101
|
+
`meta.json`. JetBrains: `VirtualFileListener` / NIO `WatchService`. Generic
|
|
102
|
+
fallback: stat the active segment on a *long* interval (≥10 s) — this is a
|
|
103
|
+
stat, not an MCP call, and acquires no lock.
|
|
104
|
+
2. On a growth signal, **tail forward** from `cursor.seq` (§5) and apply records
|
|
105
|
+
to the in-memory projection.
|
|
106
|
+
3. `meta.json` is advisory only; never trust it for correctness — the journal
|
|
107
|
+
tail is the truth (it may be a stale cache mid-write). Use it only to detect
|
|
108
|
+
"did anything change" cheaply.
|
|
109
|
+
|
|
110
|
+
There is no MCP server process for display. The watcher is OS-level; the read
|
|
111
|
+
is a file read. Under the 2026-06-10 load (3 workers + open surface) this yields
|
|
112
|
+
zero lock acquisitions by the surface — the validation gate (step 3).
|
|
113
|
+
|
|
114
|
+
## 5. Bootstrap and tail algorithm
|
|
115
|
+
|
|
116
|
+
**Status of checkpoint emission (2026-06-12, pln#543 step 4 landed):** the
|
|
117
|
+
writer does NOT yet produce `checkpoints/ckpt-*.json` files — checkpoint
|
|
118
|
+
emission ships with step 3/5 of pln#543. Until then, the empty-seed + full
|
|
119
|
+
tail path below is the **primary** cold-start path in production, not a
|
|
120
|
+
degenerate fallback. The checkpoint-first path is the spec the consumer must
|
|
121
|
+
implement for forward-compatibility; an observer that hard-requires a
|
|
122
|
+
checkpoint at activation is broken against today's store. The perf targets
|
|
123
|
+
in §10 assume checkpoint emission; until it ships, "activation → first
|
|
124
|
+
summary" is bounded by the full tail length instead (~10 MB of segments in
|
|
125
|
+
the typical case, sub-second in practice, but the budget no longer has
|
|
126
|
+
slack).
|
|
127
|
+
|
|
128
|
+
**Cold start (no cursor, or cursor below the oldest live segment):**
|
|
129
|
+
|
|
130
|
+
1. **If a verified checkpoint exists**, load the newest `ckpt-<S>.json` →
|
|
131
|
+
seed the in-memory projection (full post-image set at head `S`). Set
|
|
132
|
+
`cursor.checkpoint_seq = S`. (Today: this branch is dead until the
|
|
133
|
+
writer ships checkpoint emission.)
|
|
134
|
+
2. **Otherwise** (today's primary path), seed from the empty projection
|
|
135
|
+
with `cursor.checkpoint_seq = 0`.
|
|
136
|
+
3. Tail every record with `seq > checkpoint_seq` across segments in
|
|
137
|
+
(segment, file-line) order; apply by class (§2). With no checkpoint
|
|
138
|
+
this is a full replay from seq 1, bounded by retention (the
|
|
139
|
+
`events/archive/` floor — segments are park-don't-deleted past the
|
|
140
|
+
second-newest verified checkpoint; with no checkpoint, no segment is
|
|
141
|
+
ever eligible for archive, so "the journal" = "every segment ever
|
|
142
|
+
written" until checkpoint emission ships).
|
|
143
|
+
4. Set `cursor.seq` to the last applied seq. Render.
|
|
144
|
+
|
|
145
|
+
If the cursor's `seq` is **below the oldest non-archived segment's first
|
|
146
|
+
seq** (gap — segments archived past the watermark), discard the cursor and
|
|
147
|
+
cold-start: notifications degrade, state never does. Today no segment is
|
|
148
|
+
ever archived (gc requires a verified checkpoint floor, see §2.3 of the
|
|
149
|
+
store spec), so this branch is unreachable in production until checkpoint
|
|
150
|
+
emission ships — but the rule is normative regardless: an observer that
|
|
151
|
+
crashes on a gap is broken against any future store.
|
|
152
|
+
|
|
153
|
+
**Warm tail (cursor present, within live segments):**
|
|
154
|
+
|
|
155
|
+
1. Binary-search the segment whose name (`seg-<firstSeq>`) contains
|
|
156
|
+
`cursor.seq + 1` (filenames sort by first seq).
|
|
157
|
+
2. Stream forward from that point across segments; apply by class.
|
|
158
|
+
3. A **torn tail** (final line unparseable or missing trailing `\n`) is expected
|
|
159
|
+
crash residue mid-write by an agent — skip it; it reappears complete on the
|
|
160
|
+
next growth signal. Never block on it.
|
|
161
|
+
4. A mid-file unparseable line is logged and skipped (do not halt the tail).
|
|
162
|
+
5. Advance `cursor.seq` only over records actually applied.
|
|
163
|
+
|
|
164
|
+
Replay order is always (segment order, then file-line order) — never sorted by
|
|
165
|
+
seq (matches the store's own reducer; a dup `seq` from a lock-steal applies
|
|
166
|
+
later-line-wins, harmlessly, in a read-only projection).
|
|
167
|
+
|
|
168
|
+
## 6. Board projection — which records touch which section
|
|
169
|
+
|
|
170
|
+
The in-memory projection is `Map<item_type, Map<item_id, payload>>` plus a
|
|
171
|
+
bounded recent-activity ring (observability + registry signals, last N). The
|
|
172
|
+
board sections are derived; a record invalidates only the sections its
|
|
173
|
+
`item_type` feeds, and only those re-render (push-by-affected-section, §5.3):
|
|
174
|
+
|
|
175
|
+
| `item_type` | Invalidates sections |
|
|
176
|
+
|---|---|
|
|
177
|
+
| `plan` | IN_PROGRESS, SPRINTS, BACKLOG, ATTENTION (badge), SYSTEM (counts) |
|
|
178
|
+
| `claim` | IN_PROGRESS, AGENTS (roster freshness) |
|
|
179
|
+
| `assignment` | IN_PROGRESS, ATTENTION (blocked/failed), "Recently terminal" |
|
|
180
|
+
| `agent_run` | IN_PROGRESS (worker rows), AGENTS, "Recently terminal" |
|
|
181
|
+
| `candidate` | ATTENTION (human-review), CANDIDATES |
|
|
182
|
+
| `action` | ATTENTION (the dominant attention input) |
|
|
183
|
+
| `constraint`/`decision`/`trap` | SYSTEM (counts), TRAPS |
|
|
184
|
+
| `handoff` | ACTIVITY, SYSTEM (counts) |
|
|
185
|
+
| `sequence` | SPRINTS |
|
|
186
|
+
| `session`/`*_progress` (observability) | ACTIVITY feed only — never a section state change |
|
|
187
|
+
|
|
188
|
+
`attention_required` is computed by the observer from the projection (actions +
|
|
189
|
+
human candidates + blocked/failed assignments + failed runs + evidence-
|
|
190
|
+
contradicted terminals), matching what the server-side composite returns — the
|
|
191
|
+
surface must not under-count by reading "actions only" (the pln#559 fix, now in
|
|
192
|
+
the projection rule).
|
|
193
|
+
|
|
194
|
+
### 6.1 Dual-mode coverage gap (CLOSED by pln#568 phase 1.5)
|
|
195
|
+
|
|
196
|
+
> **Status (pln#568):** the writer-side gap below is **closed**. The
|
|
197
|
+
> registry / coordination families (claim, assignment, agent_run,
|
|
198
|
+
> action_required [journaled under item_type `state`], candidate, sequence,
|
|
199
|
+
> and SHARED runtime_note) now emit full entity-state **post-images** on their
|
|
200
|
+
> persist chokepoint (`src/core/events/registry-post-image.ts`), and the
|
|
201
|
+
> observer materializer projects them (`board-projection.ts` ARRAY_SLOT).
|
|
202
|
+
>
|
|
203
|
+
> **Cutover signal (O2, resolved):** an observer switches a registry family
|
|
204
|
+
> from the MCP `board_summary` seed to the journal only once the journal
|
|
205
|
+
> carries the `journal_note` kind **`registry_genesis`** marker — emitted by
|
|
206
|
+
> `runRegistryGenesisSupplement` (run via `brainclaw migrate --enable-journal`)
|
|
207
|
+
> after it backfills every pre-existing registry entity. The marker is the
|
|
208
|
+
> safety gate: without a complete backfill a partially-journaled store would
|
|
209
|
+
> undercount the attention badge (trp#559). `BoardObserver.registryAuthoritative()`
|
|
210
|
+
> tracks the marker (sticky, re-derived on cold start by replaying from the
|
|
211
|
+
> checkpoint floor); `mergeCounts(journal, seed, journalActive, registryAuthoritative)`
|
|
212
|
+
> takes claims/assignments/runs/actions from the journal when it is set, and
|
|
213
|
+
> from the seed otherwise. `agents`/`sessions` are never journaled → always seed.
|
|
214
|
+
> A store that has NOT run the supplement keeps the seed (no regression).
|
|
215
|
+
>
|
|
216
|
+
> The historical (pre-pln#568) description below is kept for context.
|
|
217
|
+
|
|
218
|
+
The journal classifies records into five classes (§2). In phase 1 / `dual`
|
|
219
|
+
mode — what runs today after pln#543 step 4 — **registry-lifecycle records
|
|
220
|
+
are payload-OPTIONAL** (event-log-store.md §2.1.1, J4); the dual-write path
|
|
221
|
+
in `src/core/event-log.ts:152` forwards `assignment_*` and `run_*` events to
|
|
222
|
+
the journal with `item_id` only, no `payload`. The §2 rule "upsert when
|
|
223
|
+
payload present, else a status/activity signal" means today's journal carries
|
|
224
|
+
**no post-images for `assignment` or `agent_run`**: the in-memory projection
|
|
225
|
+
has zero rows for those item_types, and the materializer
|
|
226
|
+
(`src/core/events/materialize.ts`) only enumerates the 5 memory families
|
|
227
|
+
(constraint/decision/trap/handoff/plan).
|
|
228
|
+
|
|
229
|
+
Consequence for the §6 mapping table: until phase 1.5 ships, the rows that
|
|
230
|
+
the table claims `assignment` / `agent_run` / `claim` populate (IN_PROGRESS
|
|
231
|
+
worker rows, ATTENTION blocked/failed, Recently terminal under IN_PROGRESS)
|
|
232
|
+
cannot be drawn from the journal alone. A conforming observer in dual mode
|
|
233
|
+
MUST:
|
|
234
|
+
|
|
235
|
+
- Seed those sections at activation from a **single observer-flagged
|
|
236
|
+
`bclaw_context(kind: "board_summary")`** call (no timer, no poll) — that
|
|
237
|
+
read is lock-free under the §8 observer contract (validated against
|
|
238
|
+
`getDispatchStatus` and `loadAssignment`/`loadAgentRun`, which are pure
|
|
239
|
+
projection reads — `mcp-read-handlers.ts:1916`, `json-store.ts:47`); and
|
|
240
|
+
- Mark those sections "live-view degraded" in the tooltip until phase 1.5,
|
|
241
|
+
so the operator can tell journal-driven sections (memory entities,
|
|
242
|
+
attention badges) from MCP-seeded sections (workers, lifecycle).
|
|
243
|
+
|
|
244
|
+
Memory-entity sections (plan / constraint / decision / trap / handoff /
|
|
245
|
+
sequence / handoff-derived ACTIVITY) ARE journal-driven today via the
|
|
246
|
+
per-entity diff in `persistState` (`src/core/state.ts:400`) — the protocol
|
|
247
|
+
delivers its full value for them.
|
|
248
|
+
|
|
249
|
+
### 6.2 Section ID glossary
|
|
250
|
+
|
|
251
|
+
The §6 table uses display names; the canonical IDs in
|
|
252
|
+
`vscode-extension/src/board-tree.ts:321` are `attention | in-progress |
|
|
253
|
+
sprints | backlog | system | agents | candidates | activity | plans | claims
|
|
254
|
+
| assignments | runs | actions | handoffs | sprint | traps | cross-project`.
|
|
255
|
+
"Recently terminal" is **not** a top-level section — it is a sub-node
|
|
256
|
+
rendered under `in-progress`. The board also surfaces `cross-project`
|
|
257
|
+
(federation incoming signals) and `linked_projects`, neither of which has a
|
|
258
|
+
single journal `item_type` today: cross-project signals arrive via the
|
|
259
|
+
handoff/candidate streams (already covered), `linked_projects` is derived
|
|
260
|
+
from project config and is intentionally NOT a journal concern.
|
|
261
|
+
|
|
262
|
+
The projection is **state**, not administrative belief: a worker row's health
|
|
263
|
+
comes from evidence in the records (commits/fs signals carried on
|
|
264
|
+
registry-lifecycle payloads when present), not from a bare status field that the
|
|
265
|
+
2026-06-10 log proved lies. Where richer evidence requires it, the surface MAY
|
|
266
|
+
call `bclaw_dispatch_status` through the actions client (§7) — that is a
|
|
267
|
+
read-only MCP call, used sparingly (per visible terminal row), not a poll.
|
|
268
|
+
|
|
269
|
+
## 7. Actions go through a separate, lazy MCP client
|
|
270
|
+
|
|
271
|
+
Mutations (accept candidate, release claim, dispatch, transition, complete step)
|
|
272
|
+
are the *only* reason an observer talks to the MCP server. Rules:
|
|
273
|
+
|
|
274
|
+
- One lazily-created MCP client per project, spun up on first action, idle-timed
|
|
275
|
+
out after inactivity. Never created just to display.
|
|
276
|
+
- Distinct from any agent session: the client identifies as an **observer
|
|
277
|
+
principal** (see §8), so its calls never adopt an agent's claim/cursor.
|
|
278
|
+
- After an action, the observer does NOT optimistically mutate its projection;
|
|
279
|
+
it waits for the resulting journal record(s) to arrive via the tail (§5) and
|
|
280
|
+
re-projects. Single source of truth, no split-brain. (A short-lived "pending"
|
|
281
|
+
affordance on the clicked item is a UI concern, not projection state.)
|
|
282
|
+
- `bclaw_dispatch_status` and other read-only facades are permitted through this
|
|
283
|
+
client for on-demand evidence enrichment, but are never on a timer.
|
|
284
|
+
|
|
285
|
+
## 8. Observer identity (no impersonation, no side effects)
|
|
286
|
+
|
|
287
|
+
The surface declares itself an observer so the server suppresses every write a
|
|
288
|
+
read would otherwise trigger:
|
|
289
|
+
|
|
290
|
+
- Transport signal: `BRAINCLAW_OBSERVER=1` in the action client's env, and/or
|
|
291
|
+
MCP `clientInfo.name = "brainclaw-observer/<surface>"`.
|
|
292
|
+
- Server contract (already implemented, pln#558): observer reads do not
|
|
293
|
+
`autoAcknowledge`, do not run agent-run reconciliation, do not advance
|
|
294
|
+
`readUnseenEvents` cursors, do not implicit-heartbeat or auto-register an
|
|
295
|
+
identity. This protocol is the client half of that contract: even the read-
|
|
296
|
+
only facade calls in §7 carry the observer flag.
|
|
297
|
+
- The observer never presents an agent name as the actor of anything. Actions
|
|
298
|
+
the human triggers are attributed to the human operator principal, not to a
|
|
299
|
+
spawned agent.
|
|
300
|
+
|
|
301
|
+
## 9. Failure modes and degradation
|
|
302
|
+
|
|
303
|
+
| Condition | Behavior |
|
|
304
|
+
|---|---|
|
|
305
|
+
| `events/` absent (journal off / not migrated) | Fall back to a single MCP `board_summary` read at activation (no timer); show a "journal off — limited live view" hint. The surface still works, just not push-driven. |
|
|
306
|
+
| Cursor gap (archived past watermark) | Cold-start from newest checkpoint (§5); silent — state is correct, only missed-activity history is lost. |
|
|
307
|
+
| Checkpoint missing/corrupt | Fall back to the previous checkpoint, replay more segments (the two-checkpoint floor guarantees one exists); if none, seed empty + full tail. |
|
|
308
|
+
| Torn / unparseable line | Skip, keep tailing (§5). |
|
|
309
|
+
| Active segment shrinks / meta regresses | Trust the journal tail, re-derive; never write a "repair" (that is an agent/doctor job). |
|
|
310
|
+
| Watch unavailable (network FS, sandbox) | Degrade to a long-interval stat of the active segment; still zero locks. |
|
|
311
|
+
|
|
312
|
+
## 10. Performance budget (vision §5.3, restated as observer obligations)
|
|
313
|
+
|
|
314
|
+
| Operation | Target | Hard limit | How the protocol meets it |
|
|
315
|
+
|---|---|---|---|
|
|
316
|
+
| Activation → first summary | 500 ms | 2 s | seed from newest checkpoint, no full replay |
|
|
317
|
+
| Summary refresh | 300 ms | 1 s | apply only the new tail records |
|
|
318
|
+
| Section expand (warm) | 50 ms | 200 ms | projection is in memory; expand reads the map |
|
|
319
|
+
| Section expand (cold) | 500 ms | 2 s | first projection build from checkpoint+tail |
|
|
320
|
+
| Action round-trip | 500 ms | 2 s | lazy MCP client; result observed via tail |
|
|
321
|
+
|
|
322
|
+
Out of budget → surface in tooltip + a "performance degraded" status-bar
|
|
323
|
+
indicator (never escalate by calling a heavier path — that is the contention-
|
|
324
|
+
breeds-contention bug this protocol exists to kill).
|
|
325
|
+
|
|
326
|
+
## 11. Language-agnostic conformance checklist
|
|
327
|
+
|
|
328
|
+
A surface in any language conforms iff:
|
|
329
|
+
|
|
330
|
+
1. It reads only files under `.brainclaw/events/` (+ checkpoints) and writes
|
|
331
|
+
nothing under `.brainclaw/`.
|
|
332
|
+
2. Its cursor is a seq watermark in client-private storage, keyed by
|
|
333
|
+
`project_id`, never in the store's `.cursors/`.
|
|
334
|
+
3. It seeds from the newest verified checkpoint and tails by (segment, line)
|
|
335
|
+
order, applying records by action *class*, tolerant of unknown verbs and torn
|
|
336
|
+
tails.
|
|
337
|
+
4. Change detection is an OS file watch (or long-interval stat) — never an MCP
|
|
338
|
+
poll, never a lock.
|
|
339
|
+
5. Mutations go through a separate lazy MCP client flagged as an observer
|
|
340
|
+
principal; the projection updates only from the resulting journal records.
|
|
341
|
+
6. `attention_required` and worker health are computed from journal evidence,
|
|
342
|
+
not from administrative status fields alone.
|
|
343
|
+
|
|
344
|
+
Reference implementation: the VS Code extension (pln#560 step 2). The JetBrains
|
|
345
|
+
plugin (next plan) implements this same checklist in Kotlin — its existence is
|
|
346
|
+
the cross-language validation that this protocol, not the TypeScript code, is
|
|
347
|
+
the contract.
|
|
348
|
+
|
|
349
|
+
## 12. OPEN QUESTIONS
|
|
350
|
+
|
|
351
|
+
Carried from the 2026-06-12 symmetric review (pln#560 step 1, this branch).
|
|
352
|
+
Each is something the spec text cannot close on its own; one or more must
|
|
353
|
+
be answered before the JetBrains plugin (Kotlin) ships.
|
|
354
|
+
|
|
355
|
+
| # | Sev | Question |
|
|
356
|
+
|---|---|---|
|
|
357
|
+
| O1 | MED | **Shared `ACTION_CLASS_BY_ACTION` manifest.** §2 says implementations MUST mirror the table "or fetch it from a shared manifest." Today only the TS version exists (`src/core/events/journal.ts:66`); a Kotlin implementer would re-type 42 entries by hand and silently drift on the 43rd. Should this ship as a generated JSON next to `event-log-store.md` (single source of truth, both runtimes load it) or as part of a versioned schema bundle? Recommend the generated JSON — the table is small and changes per spec revision, not per release. |
|
|
358
|
+
| O2 | RESOLVED (pln#568) | **Phase-1.5 cutover signal for §6.1.** Resolved with a `journal_note` kind **`registry_genesis`** marker emitted by `runRegistryGenesisSupplement` after it backfills every pre-existing registry entity (`brainclaw migrate --enable-journal`). Observers detect it (`BoardObserver.registryAuthoritative()`, sticky + re-derived on cold start) and switch the registry counts from the MCP seed to the journal via `mergeCounts(..., registryAuthoritative)`. Chosen over a `meta.json` version bump because meta is a rebuildable cache (§2.3) — the marker is a durable journal record, the source of truth, and survives a meta rebuild. Open follow-up: when checkpoints start emitting (today `checkpoint_seq=0`), the checkpoint must encode the capability so a cold start past the marker's segment still re-derives authority. |
|
|
359
|
+
| O3 | LOW | **`bclaw_dispatch_status` enrichment scope.** §6 + §7 allow it "per visible terminal row" but the wording is ambiguous between "terminal-state row" (Recently terminal) and "row currently visible in the terminal UI" (every IN_PROGRESS row). Settle: probably the first (only failed/silent_death rows want the evidence digest) — but the contract must say so, otherwise an implementor renders an O(workers) burst on every refresh. |
|
|
360
|
+
| O4 | LOW | **Segment pad-width upgrade path.** §2 pins 8-digit decimal padding; the writer is 8-digit too (`src/core/events/journal.ts:214 SEGMENT_PAD=8`). At ~17k events historical, the 1e8 ceiling is decades out — but a future widen would require coordinated writer + every observer roll-out. Carry the migration recipe (pad-width in `meta.json`?) here so a future maintainer doesn't have to rediscover it. |
|
|
361
|
+
| O5 | LOW | **File watch semantics on Windows network mounts.** §4 falls back to a "long-interval stat" when the watcher is unavailable. VS Code's `FileSystemWatcher` on a junction-linked worktree (the brainclaw dispatch substrate) may fire on the link target's mtime but not the source-of-truth segment writes from another process; verify against the dispatch worktree machinery (`pln#498` junctions) before declaring the watch path universal. |
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Parallel-lane merge protocol
|
|
2
|
+
|
|
3
|
+
Status: operational (pln#396). When a sequence runs multiple lanes in parallel
|
|
4
|
+
worktrees, their branches must land back on the base without silently
|
|
5
|
+
overwriting each other. This is the minimum protocol; `brainclaw worktree
|
|
6
|
+
check` is its tool.
|
|
7
|
+
|
|
8
|
+
## The risk
|
|
9
|
+
|
|
10
|
+
Each lane is a worktree branched from the base (master) at dispatch time. Two
|
|
11
|
+
lanes editing the same file will, on the second merge, either conflict
|
|
12
|
+
(visible, recoverable) or — worse — produce a clean-but-wrong merge where one
|
|
13
|
+
lane's change is silently dropped or a file is parasitically deleted
|
|
14
|
+
(trp_merge_wipes_node_modules class). File-level overlap between lanes is the
|
|
15
|
+
predictor; `worktree check` surfaces it before `git merge`, not after.
|
|
16
|
+
|
|
17
|
+
## Before merging any lane
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
brainclaw worktree check
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
It reports, per live worktree lane: the files it changes (committed since base
|
|
24
|
+
+ uncommitted tracked), the owning claim / session / agent, and — the payload —
|
|
25
|
+
**which files are touched by more than one lane**. Exit code:
|
|
26
|
+
|
|
27
|
+
- `0` — lanes are disjoint. Merge in any order; no cross-lane conflict possible.
|
|
28
|
+
- `3` — overlapping files exist. Follow the ordering rule below.
|
|
29
|
+
|
|
30
|
+
`brainclaw worktree merge <branch>` runs the same check inline and prints an
|
|
31
|
+
advisory warning if the branch overlaps another live lane (it never blocks —
|
|
32
|
+
the operator decides).
|
|
33
|
+
|
|
34
|
+
## Ordering rule when lanes overlap
|
|
35
|
+
|
|
36
|
+
1. **Merge the overlapping lanes one at a time**, never as a batch.
|
|
37
|
+
2. After merging lane A, **rebase (or re-create) the still-pending overlapping
|
|
38
|
+
lanes onto the new base** so they see A's change, then re-run `worktree
|
|
39
|
+
check`. The overlap on the merged file should now be gone (the pending lane
|
|
40
|
+
either already has A's change or will conflict explicitly on rebase, where
|
|
41
|
+
it is resolvable in isolation).
|
|
42
|
+
3. Disjoint lanes (no shared files with anything merged) can merge freely at any
|
|
43
|
+
point — `check` confirms they carry no risk.
|
|
44
|
+
4. Prefer merging the **smallest / most foundational** overlapping lane first
|
|
45
|
+
(fewer files, or the one others build on), so the rebases that follow are
|
|
46
|
+
the cheap direction.
|
|
47
|
+
|
|
48
|
+
## When automatic reconciliation is not possible
|
|
49
|
+
|
|
50
|
+
`worktree check` is a *predictor*, and `worktree merge` auto-restores parasitic
|
|
51
|
+
deletions but does **not** resolve real content conflicts. Escalate to a human
|
|
52
|
+
(or a single coordinator session doing the merge serially) when:
|
|
53
|
+
|
|
54
|
+
- Two lanes changed overlapping *hunks* of the same file (not just the same
|
|
55
|
+
file) — git will conflict; resolve in the main worktree, do not `--force`.
|
|
56
|
+
- A lane's worktree carries **uncommitted** changes to a shared file (it spawned
|
|
57
|
+
from HEAD; those edits never reach the merge). `check` flags these as
|
|
58
|
+
`(+N uncommitted)` — harvest or discard them deliberately before merging
|
|
59
|
+
(a dead worker's stranded edits are the feedback_review_loop_symmetric_fixer
|
|
60
|
+
/ trp#545 case).
|
|
61
|
+
- The overlap is in a generated / high-churn file (lockfiles, `dist/`) — prefer
|
|
62
|
+
regenerating post-merge over merging both sides.
|
|
63
|
+
|
|
64
|
+
## Invariants
|
|
65
|
+
|
|
66
|
+
- The check is pure-read: only `git diff` / `git status`, no store lock, no
|
|
67
|
+
mutation — safe to run anytime, even mid-dispatch with workers live.
|
|
68
|
+
- `.brainclaw/` and `.gitignore` are never counted as conflict surface (store-
|
|
69
|
+
internal + birth noise).
|
|
70
|
+
- A flagged overlap that turns out disjoint at the hunk level costs one glance;
|
|
71
|
+
the protocol deliberately over-reports rather than miss a real conflict.
|
|
@@ -75,6 +75,49 @@ task with estimate est:30min actual:45min [ratio:1.5x]
|
|
|
75
75
|
|
|
76
76
|
A ratio below 1.0 means the task finished faster than expected (early). Above 1.0 means it took longer (over).
|
|
77
77
|
|
|
78
|
+
### Step-level estimation (pln#495)
|
|
79
|
+
|
|
80
|
+
Estimation can be captured per **step**, not just per plan — which removes a real
|
|
81
|
+
source of noise. A plan's wall-clock span (`created_at`→`completed_at`) counts
|
|
82
|
+
the idle time *between* steps as if it were work: if steps 1–5 finish in a
|
|
83
|
+
morning and step 6 lands the next day, the plan-level elapsed smears an 18h gap
|
|
84
|
+
that was never effort. Summing per-step durations excludes those gaps.
|
|
85
|
+
|
|
86
|
+
Set step estimates and actuals via `add-step` / `update-step`:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
brainclaw add-step <plan-id> "write unit tests" --estimate 30
|
|
90
|
+
brainclaw update-step <plan-id> <step-id> --status in_progress # stamps started_at
|
|
91
|
+
brainclaw update-step <plan-id> <step-id> --status done # stamps completed_at
|
|
92
|
+
# or record an explicit actual:
|
|
93
|
+
brainclaw update-step <plan-id> <step-id> --actual-effort 45m
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`estimated_effort` accepts the same forms as the plan-level `--estimate` (an
|
|
97
|
+
integer of minutes, or a legacy duration string like `2h` / `30m`).
|
|
98
|
+
|
|
99
|
+
`estimation-report` then prefers step-level data and tags each plan with its
|
|
100
|
+
**measurement source**:
|
|
101
|
+
|
|
102
|
+
- **`step`** — the highest quality: `estimated_minutes` is the sum of step
|
|
103
|
+
estimates (used only when *every* step has one), and `elapsed_minutes` is the
|
|
104
|
+
sum of per-step durations (used only when *every* step is measurable, via an
|
|
105
|
+
explicit `actual_effort` or both `started_at`+`completed_at`). Idle gaps
|
|
106
|
+
between steps are excluded.
|
|
107
|
+
- **`plan_string`** — fell back to the plan-level `actual_effort` string.
|
|
108
|
+
- **`plan_wallclock`** — fell back to the plan's `created_at`→`completed_at`
|
|
109
|
+
span (the noisiest; what older plans use).
|
|
110
|
+
|
|
111
|
+
The report's summary breaks the median ratio down per source
|
|
112
|
+
(`step-derived: 1.0x · plan-wallclock: 0.4x …`) so you can see how much
|
|
113
|
+
calibration error was wall-clock contamination vs real estimation drift, and the
|
|
114
|
+
chart tags each line (`✓step` / `~wall`).
|
|
115
|
+
|
|
116
|
+
**Migration:** none required. A plan whose steps carry no estimation data — or a
|
|
117
|
+
plan with no steps at all — keeps working exactly as before via the fallback
|
|
118
|
+
chain. Mixed plans (some steps estimated, some not) fall back to plan-level
|
|
119
|
+
entirely rather than reporting a misleading partial sum.
|
|
120
|
+
|
|
78
121
|
## Claims
|
|
79
122
|
|
|
80
123
|
Claims make current ownership explicit.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Skills — agent-profile vs workflow-protocol
|
|
2
|
+
|
|
3
|
+
Brainclaw writes two orthogonal kinds of agent skill. The same agent can load
|
|
4
|
+
both; they answer different questions.
|
|
5
|
+
|
|
6
|
+
## Agent-profile skills
|
|
7
|
+
|
|
8
|
+
The agent's **landing page** for brainclaw — one per agent profile
|
|
9
|
+
(`openclaw`, `nanoclaw`, `nemoclaw`, `picoclaw`, `zeroclaw`) plus the universal
|
|
10
|
+
`.agents/skills/brainclaw/SKILL.md` discovered by every agent that honors the
|
|
11
|
+
shared `.agents/skills/` convention (Cursor, Copilot, Roo, OpenCode, Codex,
|
|
12
|
+
Kilo, Mistral…). It answers *"what is brainclaw and how do I load context here?"*
|
|
13
|
+
and points at `bclaw_work` as the entry verb.
|
|
14
|
+
|
|
15
|
+
Source: `src/core/agent-files.ts` (`ensureUniversalBrainclawSkill`, the per-profile
|
|
16
|
+
writers). These files are **generated, not committed** — they are gitignored and
|
|
17
|
+
materialized by `brainclaw export` / setup, so the source of truth is the code,
|
|
18
|
+
never a checked-in `SKILL.md`.
|
|
19
|
+
|
|
20
|
+
## Workflow-protocol skills (pln#519)
|
|
21
|
+
|
|
22
|
+
**Workflow-decomposed** skills that package a critical brainclaw protocol so the
|
|
23
|
+
agent loads *the right one at the right moment* instead of skimming a monolithic
|
|
24
|
+
AGENTS.md. Three ship today, namespaced `brainclaw-*`:
|
|
25
|
+
|
|
26
|
+
| Skill | Trigger |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `brainclaw-session` | starting / resuming / closing a session; before claiming a scope |
|
|
29
|
+
| `brainclaw-memory-capture` | recording a decision / constraint / trap / handoff at the right type |
|
|
30
|
+
| `brainclaw-multi-agent` | delegating, reviewing, dispatching, driving a loop |
|
|
31
|
+
|
|
32
|
+
They carry `metadata.protocol: true` in frontmatter so skill-loader UIs can list
|
|
33
|
+
protocols separately from profile skills, and `metadata.brainclaw_version` (set
|
|
34
|
+
to `package.json:version` at write time) so a loader can detect a cached skill
|
|
35
|
+
that predates a brainclaw upgrade. Each follows the "process not prose" shape:
|
|
36
|
+
**When to use → Workflow → Anti-rationalizations → Red flags → Verification**.
|
|
37
|
+
|
|
38
|
+
Source: `src/core/protocol-skills.ts` (single source of truth; content is
|
|
39
|
+
embedded, not read from a repo file, so it installs identically from source or
|
|
40
|
+
an npm install). Written to `.agents/skills/<id>/SKILL.md` by
|
|
41
|
+
`ensureProtocolSkills`, wired into `writeDetectedAgentAutoConfig` for every agent
|
|
42
|
+
whose capability profile declares `hasSkills: true`. Generated + gitignored, like
|
|
43
|
+
the profile skills.
|
|
44
|
+
|
|
45
|
+
### Design invariants
|
|
46
|
+
|
|
47
|
+
- **No dynamic state.** A protocol-skill never embeds a concrete `claim_id` /
|
|
48
|
+
`loop_id` / `plan_id` — it tells the agent *when* to call a facade and *how to
|
|
49
|
+
read* live state, never *what the current state is*. (Enforced by a test.)
|
|
50
|
+
- **Facade-only.** Skills reference canonical-grammar / facade verbs by name;
|
|
51
|
+
they never re-implement `mcp.ts` logic. A protocol change updates the skill,
|
|
52
|
+
not the other way round.
|
|
53
|
+
- **Both MCP and CLI.** Each workflow shows the MCP call AND the `brainclaw …`
|
|
54
|
+
CLI fallback, because MCP is not always wired (cold start; a dispatched worker
|
|
55
|
+
in a worktree without `.brainclaw/`, trp#336).
|
|
56
|
+
- **Capped at 3.** Setup and troubleshooting protocols are deferred until an
|
|
57
|
+
empirical friction shows the three are insufficient (design §E.2). A 4th
|
|
58
|
+
protocol needs a runtime_note documenting the gap it closes.
|
|
59
|
+
|
|
60
|
+
## Namespace claim
|
|
61
|
+
|
|
62
|
+
Brainclaw owns the `brainclaw-*` prefix under `.agents/skills/`. Other tools that
|
|
63
|
+
install skills into the shared directory must avoid `brainclaw-` ids to prevent
|
|
64
|
+
collisions.
|
|
65
|
+
|
|
66
|
+
## Supply chain
|
|
67
|
+
|
|
68
|
+
Protocol-skills ship **inside the npm package**. Brainclaw does **not** currently
|
|
69
|
+
support installing external skills (no `brainclaw skill install <url>`, no loading
|
|
70
|
+
from arbitrary paths). If external installs are ever added they will require a
|
|
71
|
+
deliberate trust boundary (local-only or brainclaw-signed); that is out of scope
|
|
72
|
+
today.
|
|
73
|
+
|
|
74
|
+
## Staleness
|
|
75
|
+
|
|
76
|
+
If `brainclaw --version` reports newer than a skill's `brainclaw_version`,
|
|
77
|
+
re-run `brainclaw export --all --write` to regenerate. The version tag lets a
|
|
78
|
+
caching loader detect drift; it does not self-heal.
|
|
@@ -25,6 +25,26 @@ It establishes the first shared memory foundation for the workspace:
|
|
|
25
25
|
- writes to the detected agent's native instruction file (Cursor, Claude Code, Windsurf, etc.)
|
|
26
26
|
- creates `AGENTS.md` and `.github/copilot-instructions.md`
|
|
27
27
|
|
|
28
|
+
## Empty memory: one rule
|
|
29
|
+
|
|
30
|
+
"Bootstrap" historically named three different systems (init scaffolding, the
|
|
31
|
+
`bclaw_bootstrap` brownfield extractor, and the bootstrap ideation loop). When
|
|
32
|
+
the memory store is empty, every surface — the `bclaw_work` hint, the
|
|
33
|
+
`bclaw_setup` quick-init preview, and the `brainclaw init` preflight — now
|
|
34
|
+
emits the same decision rule (`resolveEmptyMemoryRecommendation`):
|
|
35
|
+
|
|
36
|
+
- **Repo with existing content** → run `bclaw_bootstrap` (CLI: `brainclaw bootstrap`)
|
|
37
|
+
to extract initial context from docs, manifests, native agent files, and git
|
|
38
|
+
history.
|
|
39
|
+
- **Greenfield repo** (nothing to extract) → open a bootstrap loop to ideate
|
|
40
|
+
the project vision: `bclaw_coordinate(intent='ideate', preset='bootstrap')`
|
|
41
|
+
(CLI: `brainclaw bootstrap-loop`).
|
|
42
|
+
|
|
43
|
+
The two routes are chainable in either order: extract first, then open a loop
|
|
44
|
+
for whatever vision the docs could not provide — or ideate first, then extract
|
|
45
|
+
once content exists. On greenfield, the brownfield preflight scan is skipped
|
|
46
|
+
entirely (there is nothing to harvest yet).
|
|
47
|
+
|
|
28
48
|
## Good integration pattern
|
|
29
49
|
|
|
30
50
|
1. check whether the workspace is initialized
|
|
@@ -39,6 +59,47 @@ It may simply mean the workspace has not been onboarded yet.
|
|
|
39
59
|
|
|
40
60
|
This lets a single machine support multiple very different workspaces without forcing one static instruction layer to fit all of them equally well.
|
|
41
61
|
|
|
62
|
+
## init = single project entry point
|
|
63
|
+
|
|
64
|
+
`brainclaw init` is the single code path for turning a project into a
|
|
65
|
+
brainclaw-aware workspace, whether invoked from a terminal, from the
|
|
66
|
+
`bclaw_setup` MCP tool's quick-init step, or from a multi-repo
|
|
67
|
+
`brainclaw setup`. After detecting the local AI agent, init runs the
|
|
68
|
+
per-agent slice of the machine prerequisites (the same writes `setup`
|
|
69
|
+
performs at machine scope, scoped to the detected agent) so an agent
|
|
70
|
+
landing in the carte-blanche / fresh-repo case does not need a separate
|
|
71
|
+
shell-out + session reload. The slice is idempotent — each `ensure*`
|
|
72
|
+
function returns "skipped" when the agent's user-scope config doesn't
|
|
73
|
+
exist, and the writes are short-circuited in `BRAINCLAW_TEST_MODE` or
|
|
74
|
+
when `--skip-agent-bootstrap` is passed. `setup` is rescoped to
|
|
75
|
+
multi-repo / machine-bootstrap; `setup-machine` is the explicit
|
|
76
|
+
machine-only path.
|
|
77
|
+
|
|
78
|
+
### `init --force`
|
|
79
|
+
|
|
80
|
+
`--force` rebuilds managed identity fields (project_id, current_agent,
|
|
81
|
+
storage_dir, topology) but **merges through the existing config** so
|
|
82
|
+
curator personalisations (redaction patterns, sensitive paths,
|
|
83
|
+
governance overrides, claim TTL, cross-project links, custom markdown
|
|
84
|
+
caps) survive the reset. Before any write, a sibling backup is taken at
|
|
85
|
+
`.brainclaw.bak-<timestamp>/` — the standard recovery-backups pattern
|
|
86
|
+
used by `brainclaw upgrade`. Recovery: `brainclaw upgrade --rollback`.
|
|
87
|
+
|
|
88
|
+
## Solo-agent fresh defaults
|
|
89
|
+
|
|
90
|
+
A fresh `brainclaw init` seeds `governance.curators` with the human
|
|
91
|
+
running init. Without this, the default `approval_policy: 'review'`
|
|
92
|
+
combined with `curators: []` trapped every reflective note in pending
|
|
93
|
+
forever — a surprise that doesn't show up until enough memory has
|
|
94
|
+
accumulated to notice. The merge logic preserves any explicit curator
|
|
95
|
+
list on an existing store, so this only takes effect on fresh installs.
|
|
96
|
+
|
|
97
|
+
On an empty store, `bclaw_work` carries an explicit
|
|
98
|
+
`bclaw_create(entity='plan')` hint in `next_actions` alongside the
|
|
99
|
+
bootstrap recommendation: the bootstrap covers *vision*, the plan
|
|
100
|
+
affordance covers *work* itself. The two are independent — both can
|
|
101
|
+
appear simultaneously.
|
|
102
|
+
|
|
42
103
|
## Multi-project workspaces
|
|
43
104
|
|
|
44
105
|
A workspace may contain multiple brainclaw-initialized child projects (each with its own `.brainclaw/` store). In this topology:
|
|
@@ -80,10 +80,10 @@ The agent can use `bclaw_setup` to walk through the process interactively.
|
|
|
80
80
|
### Per-agent manual setup
|
|
81
81
|
|
|
82
82
|
```bash
|
|
83
|
-
brainclaw enable-agent claude-code
|
|
84
|
-
brainclaw enable-agent cursor
|
|
85
|
-
brainclaw export --format claude-md --write
|
|
86
|
-
brainclaw export --detect --write # auto-detect and write
|
|
83
|
+
brainclaw enable-agent claude-code
|
|
84
|
+
brainclaw enable-agent cursor
|
|
85
|
+
brainclaw export --format claude-md --write
|
|
86
|
+
brainclaw export --detect --write # auto-detect and write the current agent format
|
|
87
87
|
```
|
|
88
88
|
|
|
89
89
|
### Regenerating after changes
|