brainclaw 1.8.0 → 1.9.1

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 (178) hide show
  1. package/README.md +592 -505
  2. package/dist/brainclaw-vscode.vsix +0 -0
  3. package/dist/cli.js +138 -13
  4. package/dist/commands/add-step.js +1 -1
  5. package/dist/commands/bootstrap.js +2 -26
  6. package/dist/commands/check-security-mcp.js +50 -33
  7. package/dist/commands/check-security.js +86 -43
  8. package/dist/commands/claim.js +22 -21
  9. package/dist/commands/confirm.js +26 -0
  10. package/dist/commands/context-diff.js +1 -1
  11. package/dist/commands/dispatch-watch.js +142 -0
  12. package/dist/commands/doctor.js +113 -2
  13. package/dist/commands/estimation-report.js +115 -16
  14. package/dist/commands/harvest.js +286 -23
  15. package/dist/commands/hooks.js +73 -73
  16. package/dist/commands/init.js +124 -22
  17. package/dist/commands/install-hooks.js +78 -78
  18. package/dist/commands/loops-handlers.js +4 -0
  19. package/dist/commands/mcp-read-handlers.js +253 -41
  20. package/dist/commands/mcp.js +664 -102
  21. package/dist/commands/memory.js +21 -17
  22. package/dist/commands/migrate.js +81 -17
  23. package/dist/commands/prune.js +78 -4
  24. package/dist/commands/reflect.js +26 -20
  25. package/dist/commands/register-agent.js +57 -1
  26. package/dist/commands/repair.js +20 -0
  27. package/dist/commands/session-end.js +15 -6
  28. package/dist/commands/session-start.js +18 -1
  29. package/dist/commands/setup-security.js +39 -18
  30. package/dist/commands/setup.js +26 -27
  31. package/dist/commands/stale.js +16 -2
  32. package/dist/commands/switch.js +26 -5
  33. package/dist/commands/uninstall.js +126 -34
  34. package/dist/commands/update-step.js +6 -0
  35. package/dist/commands/version.js +1 -1
  36. package/dist/commands/worktree.js +60 -0
  37. package/dist/core/actions.js +12 -3
  38. package/dist/core/agent-capability.js +30 -17
  39. package/dist/core/agent-files.js +963 -666
  40. package/dist/core/agent-integrations.js +0 -3
  41. package/dist/core/agent-inventory.js +67 -0
  42. package/dist/core/agent-registry.js +163 -29
  43. package/dist/core/agentrun-reconciler.js +33 -2
  44. package/dist/core/agentruns.js +7 -1
  45. package/dist/core/ai-agent-detection.js +31 -44
  46. package/dist/core/archival.js +15 -9
  47. package/dist/core/assignment-reconciler.js +56 -0
  48. package/dist/core/assignment-sweeper.js +127 -4
  49. package/dist/core/assignments.js +69 -11
  50. package/dist/core/bootstrap.js +233 -67
  51. package/dist/core/brainclaw-version.js +22 -0
  52. package/dist/core/candidates.js +21 -1
  53. package/dist/core/claims.js +313 -150
  54. package/dist/core/codev-prompts.js +38 -38
  55. package/dist/core/config.js +6 -1
  56. package/dist/core/context-diff.js +148 -20
  57. package/dist/core/context.js +129 -8
  58. package/dist/core/coordination.js +22 -3
  59. package/dist/core/default-profiles/doctor.yaml +11 -11
  60. package/dist/core/default-profiles/janitor.yaml +11 -11
  61. package/dist/core/default-profiles/onboarder.yaml +11 -11
  62. package/dist/core/default-profiles/reviewer.yaml +13 -13
  63. package/dist/core/dispatch-status.js +79 -5
  64. package/dist/core/dispatcher.js +65 -12
  65. package/dist/core/entity-operations.js +74 -27
  66. package/dist/core/entity-registry.js +31 -5
  67. package/dist/core/event-log.js +138 -21
  68. package/dist/core/events/checkpoint.js +258 -0
  69. package/dist/core/events/genesis.js +220 -0
  70. package/dist/core/events/journal.js +507 -0
  71. package/dist/core/events/materialize.js +126 -0
  72. package/dist/core/events/registry-post-image.js +110 -0
  73. package/dist/core/events/verify.js +109 -0
  74. package/dist/core/execution-adapters.js +23 -0
  75. package/dist/core/execution.js +1 -1
  76. package/dist/core/facade-schema.js +38 -0
  77. package/dist/core/gc-semantic.js +130 -5
  78. package/dist/core/handoff-snapshot.js +68 -0
  79. package/dist/core/ids.js +19 -8
  80. package/dist/core/instruction-templates.js +34 -115
  81. package/dist/core/io.js +39 -3
  82. package/dist/core/json-store.js +10 -1
  83. package/dist/core/lock.js +153 -28
  84. package/dist/core/loops/bootstrap-acquire.js +25 -1
  85. package/dist/core/loops/facade-schema.js +2 -0
  86. package/dist/core/loops/hooks/survey-signals-baseline.js +36 -0
  87. package/dist/core/loops/index.js +1 -0
  88. package/dist/core/loops/presets/bootstrap.js +7 -0
  89. package/dist/core/loops/store.js +17 -0
  90. package/dist/core/loops/verbs.js +24 -2
  91. package/dist/core/markdown.js +8 -76
  92. package/dist/core/mcp-command-resolution.js +245 -0
  93. package/dist/core/memory-compactor.js +5 -3
  94. package/dist/core/memory-lifecycle.js +282 -0
  95. package/dist/core/merge-risk.js +150 -0
  96. package/dist/core/messaging.js +10 -3
  97. package/dist/core/migration.js +11 -1
  98. package/dist/core/observer-mode.js +26 -0
  99. package/dist/core/operations/memory-mutation.js +90 -65
  100. package/dist/core/operations/plan.js +27 -1
  101. package/dist/core/protocol-skills.js +210 -0
  102. package/dist/core/reflection-safety.js +6 -7
  103. package/dist/core/reputation.js +84 -2
  104. package/dist/core/runtime-signals.js +72 -10
  105. package/dist/core/runtime.js +84 -1
  106. package/dist/core/schema.js +114 -0
  107. package/dist/core/search.js +19 -2
  108. package/dist/core/security-detectors.js +125 -0
  109. package/dist/core/security-extract.js +189 -0
  110. package/dist/core/security-guard.js +217 -139
  111. package/dist/core/security-packages.js +121 -0
  112. package/dist/core/security-scoring.js +76 -9
  113. package/dist/core/security.js +34 -2
  114. package/dist/core/sequence.js +11 -2
  115. package/dist/core/setup-flow.js +141 -13
  116. package/dist/core/spawn-check.js +16 -2
  117. package/dist/core/staleness.js +73 -2
  118. package/dist/core/state.js +250 -54
  119. package/dist/core/store-resolution.js +45 -12
  120. package/dist/core/worktree.js +90 -26
  121. package/dist/facts.js +8 -8
  122. package/dist/facts.json +7 -7
  123. package/docs/PROTOCOL.md +223 -0
  124. package/docs/adapters/openclaw.md +43 -43
  125. package/docs/architecture/project-refs.md +328 -328
  126. package/docs/cli.md +2097 -2096
  127. package/docs/concepts/coordination.md +52 -52
  128. package/docs/concepts/coordinator-runbook.md +129 -0
  129. package/docs/concepts/dispatch-lifecycle.md +245 -245
  130. package/docs/concepts/event-log-store.md +928 -0
  131. package/docs/concepts/ideation-loop.md +317 -317
  132. package/docs/concepts/loop-engine.md +520 -511
  133. package/docs/concepts/mcp-governance.md +268 -268
  134. package/docs/concepts/memory.md +89 -88
  135. package/docs/concepts/multi-agent-workflows.md +167 -167
  136. package/docs/concepts/observer-protocol.md +361 -0
  137. package/docs/concepts/parallel-merge-protocol.md +71 -0
  138. package/docs/concepts/plans-and-claims.md +217 -174
  139. package/docs/concepts/project-md-convention.md +35 -35
  140. package/docs/concepts/runtime-notes.md +38 -38
  141. package/docs/concepts/skills.md +78 -0
  142. package/docs/concepts/troubleshooting.md +254 -254
  143. package/docs/concepts/workspace-bootstrapping.md +142 -81
  144. package/docs/context-format-changelog.md +35 -35
  145. package/docs/context-format.md +48 -48
  146. package/docs/index.md +65 -65
  147. package/docs/integrations/agents.md +162 -162
  148. package/docs/integrations/claude-code.md +23 -23
  149. package/docs/integrations/cline.md +87 -88
  150. package/docs/integrations/codex.md +2 -2
  151. package/docs/integrations/continue.md +60 -60
  152. package/docs/integrations/copilot.md +82 -80
  153. package/docs/integrations/cursor.md +23 -23
  154. package/docs/integrations/kilocode.md +72 -72
  155. package/docs/integrations/mcp.md +377 -377
  156. package/docs/integrations/mistral-vibe.md +122 -122
  157. package/docs/integrations/openclaw.md +99 -98
  158. package/docs/integrations/opencode.md +84 -84
  159. package/docs/integrations/overview.md +122 -122
  160. package/docs/integrations/roo.md +74 -74
  161. package/docs/integrations/windsurf.md +83 -83
  162. package/docs/mcp-schema-changelog.md +360 -329
  163. package/docs/playbooks/integration/index.md +121 -121
  164. package/docs/playbooks/orchestration.md +37 -0
  165. package/docs/playbooks/productivity/index.md +99 -99
  166. package/docs/playbooks/team/index.md +117 -117
  167. package/docs/product/agent-first-model.md +184 -184
  168. package/docs/product/entity-model-audit.md +462 -462
  169. package/docs/product/positioning.md +86 -86
  170. package/docs/quickstart-existing-project.md +107 -107
  171. package/docs/quickstart.md +148 -147
  172. package/docs/release-maintenance.md +79 -79
  173. package/docs/reputation.md +52 -52
  174. package/docs/review.md +45 -45
  175. package/docs/security.md +212 -53
  176. package/docs/server-operations.md +118 -118
  177. package/docs/storage.md +110 -108
  178. package/package.json +86 -69
@@ -1,268 +1,268 @@
1
- # MCP surface governance
2
-
3
- How the brainclaw MCP server evolves — catalog tiers, breaking-change
4
- policy, versioning, deprecation cadence, and changelog discipline.
5
-
6
- Operator-facing. Agents that cache tool catalogs use this to know when
7
- to invalidate and what to expect when we change things. Source of
8
- truth for `pln_aaf94588` (doc/mcp-versioning-and-surface-governance).
9
-
10
- ## Tiers
11
-
12
- The MCP surface is split into four tiers. Callers filter via the
13
- `tools/list` params `catalog`, `include`, `advanced`, or `tier` (see
14
- [docs/integrations/mcp.md](../integrations/mcp.md)).
15
-
16
- | Tier | Use | Stability guarantee |
17
- |--------------|-----------------------------------------|----------------------------------------------------------|
18
- | `facade` | `bclaw_work`, `bclaw_coordinate`, `bclaw_loop`, … | **Public, stable.** Breaking changes require a schema major bump. |
19
- | `standard` | Common CRUD + read tools | **Public, stable.** Same rules as facade. |
20
- | `advanced` | Low-level ops used by specialised flows | **Public, evolving.** Breaking changes require a minor bump + deprecation warning. |
21
- | `internal` | Build-only, test fixtures, experimental | **Unstable.** No compatibility guarantees — can change between patch releases. |
22
-
23
- `facade + standard` are the default `tools/list` output. `advanced`
24
- must be opted-into. `internal` is never returned by `tools/list`.
25
-
26
- A tool's tier is declared at registration time in
27
- `src/commands/mcp.ts`. Moving a tool between tiers is itself a
28
- contract change — moving *up* (e.g., advanced → standard) is safe,
29
- moving *down* (standard → advanced) requires a deprecation window.
30
-
31
- ## What counts as a breaking change
32
-
33
- Anything that can cause a previously-working MCP client call to fail
34
- or return a differently-shaped response. Concretely:
35
-
36
- - **Tool surface**
37
- - Removing a tool.
38
- - Renaming a tool.
39
- - Adding a required input argument.
40
- - Changing an argument's type, enum values, or shape.
41
- - Tightening validation in a way that rejects previously-accepted inputs.
42
- - Moving a tool to a lower tier (e.g., standard → advanced or removed from default catalog).
43
-
44
- - **Response shape**
45
- - Removing a field from `structuredContent`.
46
- - Renaming a field.
47
- - Changing a field's type (string → object, array → scalar).
48
- - Changing the meaning of an existing enum value.
49
-
50
- - **Behaviour**
51
- - Changing a tool's error model (new exit codes, new error shapes callers might pattern-match on).
52
- - Changing default values in a way that flips a downstream decision (e.g., `openLoop: true` becoming the default when it was `false`).
53
- - Removing or renaming env vars that affect tool behaviour (`BRAINCLAW_*`).
54
-
55
- **Non-breaking additions** (safe at any time):
56
-
57
- - Adding a new tool in any tier.
58
- - Adding a new **optional** argument.
59
- - Adding a new field to `structuredContent`.
60
- - Loosening validation (accepting a superset of previous inputs).
61
- - Moving a tool to a higher tier.
62
-
63
- ## Schema versioning rules
64
-
65
- `SCHEMA_VERSION` in `src/commands/mcp.ts` tracks the MCP *protocol*
66
- version — distinct from the `package.json` app version which follows
67
- app evolution. A call to `initialize` returns this in `serverInfo.version`
68
- and every tool response includes it in `schema_version`.
69
-
70
- Semver interpretation:
71
-
72
- | Bump | Allowed changes | Required artefacts |
73
- |-----------|-------------------------------------------------------------|------------------------------------------------------|
74
- | **patch** (`x.y.Z`) | Bug fixes, doc updates, internal refactors with no contract change | Changelog entry under "Fixed" |
75
- | **minor** (`x.Y.0`) | Non-breaking additions (new tools, optional args, new response fields). `advanced`-tier breaking changes *with* a deprecation window. | Changelog entry under "Added" / "Changed". Deprecation warnings for `advanced` changes. |
76
- | **major** (`X.0.0`) | Breaking changes on `facade`/`standard` tiers. Removal of any deprecated tool. Schema rename/rework. | Changelog entry under "Removed" / "Breaking". Migration guide. Clients expect to update. |
77
-
78
- Public stability guarantees apply from `1.0.0` onward (the Phase 3
79
- canonical grammar refactor, `pln_c6472192`). Subsequent v1.x releases
80
- follow the rules above strictly.
81
-
82
- ## Deprecation policy
83
-
84
- A tool slated for removal goes through a deprecation window, not a
85
- silent drop. Pattern:
86
-
87
- 1. **Mark deprecated.** Add an entry in `LEGACY_MCP_TOOL_WARNINGS`
88
- (`src/commands/mcp.ts`) with a short message pointing at the
89
- replacement. Tool keeps working. Changelog entry under "Deprecated".
90
- 2. **Surface the warning.** Every call to the tool during this window
91
- returns a `warning` in `structuredContent` and stderr. Warnings are
92
- not errors — callers continue to work.
93
- 3. **Minimum compatibility window.**
94
- - `facade`/`standard` tier tools: at least **two minor releases**
95
- with warnings before removal.
96
- - `advanced` tier tools: at least **one minor release**.
97
- - `internal` tools: no window required.
98
- 4. **Removal.** Allowed only on a major bump. Changelog entry under
99
- "Removed" with the replacement path.
100
-
101
- Deprecation warnings must name the replacement. "Deprecated, use X
102
- instead" — no orphan deprecations.
103
-
104
- ## Changelog discipline
105
-
106
- `docs/mcp-schema-changelog.md` is the single source of truth for MCP
107
- protocol changes. Conventions:
108
-
109
- - One section per released version (`## x.y.z`). The current in-flight
110
- version is marked `(current)` until it ships; the marker moves on
111
- release.
112
- - Subsections in this order:
113
- - `**Added**` — new surface.
114
- - `**Changed**` — modifications to existing surface (non-breaking
115
- unless flagged).
116
- - `**Deprecated**` — tools entering the deprecation window.
117
- - `**Removed**` — tools or fields gone.
118
- - `**Fixed**` — bug fixes that may affect behaviour.
119
- - `**Breaking**` — any breaking change, called out explicitly. Must
120
- map to a major bump.
121
- - Every changelog entry must name the tool and/or field it touches,
122
- so a client maintainer can grep for references.
123
- - `SCHEMA_VERSION` constant in `src/commands/mcp.ts` must match the
124
- latest released version in this changelog. A mismatch is a bug —
125
- bump the constant or amend the changelog, but do not ship drift.
126
-
127
- ## Enforcement guard
128
-
129
- `tests/unit/mcp-governance.test.ts` computes a stable fingerprint of
130
- the published MCP surface from `src/commands/mcp.ts`:
131
-
132
- - tool name
133
- - tier
134
- - category
135
- - input schema with descriptions stripped
136
-
137
- The test requires the current section of
138
- `docs/mcp-schema-changelog.md` to include that fingerprint. If a
139
- public tool is added, removed, moved between tiers, or has its input
140
- contract changed, the test fails until the changelog is updated.
141
-
142
- This guard is intentionally advisory-by-test rather than a runtime
143
- block. It catches contract drift in CI and local validation without
144
- preventing operators from using `brainclaw doctor` during active
145
- development.
146
-
147
- ## Schema source-of-truth — zod-derived inputSchemas
148
-
149
- MCP tool `inputSchema` blocks in `src/commands/mcp.ts` are JSON Schema.
150
- The runtime validation that actually rejects bad calls lives in zod
151
- schemas elsewhere (e.g. `src/core/loops/types.ts`,
152
- `src/core/loops/facade-schema.ts`). When the same shape is expressed
153
- twice — once as zod, once as hand-written JSON Schema — the two drift,
154
- silently. The class is the same one flagged by
155
- `feedback_cross_agent_patterns` rule 2 ("catalog source-of-truth >
156
- hardcoded constants"); it produced `trp#180` in May 2026 (Copilot
157
- rejected `bclaw_loop` because `phases`/`slots` arrays had no `items`,
158
- which Claude Code's permissive validator had silently accepted).
159
-
160
- The fix is to derive the JSON Schema from the zod source at build time
161
- and commit the generated artifact. Hand-written schemas remain for tools
162
- without a zod backing (intent-polymorphic dispatchers, etc.) and stay
163
- protected by the strict CI test in
164
- `tests/unit/mcp-input-schema-strict.test.ts`.
165
-
166
- ### How it works
167
-
168
- 1. Zod schemas are exported from their owning module (e.g.
169
- `LoopPhaseSchema`, `LoopSlotInputSchema`).
170
- 2. `scripts/build-mcp-schemas.mjs` reads the compiled zod from `dist/`
171
- and emits `src/commands/mcp-schemas.generated.ts` via zod v4's
172
- native `z.toJSONSchema()`.
173
- 3. `src/commands/mcp.ts` imports `generatedSchemas` and uses the
174
- generated objects inline as `items:` / sub-schemas inside the tool's
175
- `inputSchema`.
176
- 4. The migrated tool descriptor carries
177
- `annotations.schemaSource: 'zod-derived'` as a grep-target marker.
178
- 5. `tests/unit/mcp-zod-parity.test.ts` re-runs `z.toJSONSchema()` at
179
- test time and deep-compares against the committed generated file.
180
- Drift fails CI with a one-line fix instruction.
181
-
182
- The generated file is committed (protobuf pattern). Developers run
183
- `npm run build:mcp-schemas` after editing a zod schema and commit the
184
- regen alongside their source change. CI then verifies parity.
185
-
186
- ### How to migrate a tool to zod-derived schemas
187
-
188
- Use this checklist when you touch a tool's source for any reason. Do
189
- **not** mass-migrate in a dedicated PR — the regression risk on the
190
- combined diff outweighs the cleanup benefit.
191
-
192
- 1. **Identify the zod schema.** Locate the existing zod that the
193
- handler validates against (or extract a partial form for input-only
194
- shapes — see `LoopSlotInputSchema` for the precedent).
195
- 2. **Export it** as a named symbol so the build script can import it
196
- from `dist/`.
197
- 3. **Add the generation entry** in `scripts/build-mcp-schemas.mjs`
198
- under the `SCHEMAS` map.
199
- 4. **Run** `npm run build:mcp-schemas`. Inspect the diff in
200
- `src/commands/mcp-schemas.generated.ts` — it must be small,
201
- readable, and free of unwanted `$schema` / `$id` / `$defs` headers
202
- for sub-schemas you intend to inline.
203
- 5. **Replace the hand-written sub-schema** in `mcp.ts` with the
204
- generated reference (e.g. `items: generatedSchemas.LoopPhase`).
205
- 6. **Tag** the tool descriptor with
206
- `annotations.schemaSource: 'zod-derived'`. The annotation is
207
- informational today (see comment in `mcp.ts`); the parity test
208
- currently hardcodes its (tool, schema) pairs explicitly.
209
- 7. **Add an entry** to `tests/unit/mcp-zod-parity.test.ts` mirroring
210
- the pattern of `LoopPhase` / `LoopSlotInput`. The test exists to
211
- catch silent regen drift; it must include every newly migrated
212
- shape.
213
- 8. **Run the strict + parity tests** locally
214
- (`node --test dist-test/tests/unit/mcp-input-schema-strict.test.js
215
- dist-test/tests/unit/mcp-zod-parity.test.js`). Both must pass.
216
-
217
- ### When to skip the migration
218
-
219
- Some inputSchemas should stay hand-written:
220
-
221
- - **Intent-polymorphic surfaces.** Tools whose `inputSchema` is a flat
222
- union of intents (`bclaw_work`, `bclaw_coordinate`) where each
223
- intent permits a different field set. zod can express this via
224
- `discriminatedUnion`, but `z.toJSONSchema()` produces verbose
225
- `oneOf` blocks that are harder to read than the hand-written
226
- flat-properties form. The strict CI test (Phase 1) still protects
227
- these.
228
- - **Tools without a zod handler at all.** Some adapters and admin
229
- utilities validate manually. Migrating them just to satisfy the
230
- pattern would add zod definitions for shapes that have no other
231
- consumer.
232
- - **Build-time-only or developer-only tools.** No external client
233
- reads their schema; drift cost is bounded.
234
-
235
- ### Adding a new tool
236
-
237
- For tools added _after_ Phase 2 of `pln#494`, the default is
238
- zod-derived. Skip the hand-written sub-schemas entirely:
239
-
240
- 1. Define the zod input schema in the owning module.
241
- 2. Export it.
242
- 3. Add it to the `SCHEMAS` map in `scripts/build-mcp-schemas.mjs`.
243
- 4. Run `npm run build:mcp-schemas` and reference the generated entry
244
- in your tool descriptor.
245
- 5. Add the parity test entry.
246
-
247
- The strict CI test still runs and validates the generated output —
248
- defense in depth.
249
-
250
- ## Changelog → code cross-check
251
-
252
- Quick command to verify `SCHEMA_VERSION` matches the changelog:
253
-
254
- ```bash
255
- node -e "import('./dist/commands/mcp.js').then(m => console.log(m.SCHEMA_VERSION))"
256
- head -5 docs/mcp-schema-changelog.md
257
- ```
258
-
259
- Both should report the same version. Drift = bug.
260
-
261
- Quick command to inspect the current public-surface fingerprint:
262
-
263
- ```bash
264
- node --test dist-test/tests/unit/mcp-governance.test.js
265
- ```
266
-
267
- If the test fails, copy the reported fingerprint into the current
268
- `docs/mcp-schema-changelog.md` section and describe the surface change.
1
+ # MCP surface governance
2
+
3
+ How the brainclaw MCP server evolves — catalog tiers, breaking-change
4
+ policy, versioning, deprecation cadence, and changelog discipline.
5
+
6
+ Operator-facing. Agents that cache tool catalogs use this to know when
7
+ to invalidate and what to expect when we change things. Source of
8
+ truth for `pln_aaf94588` (doc/mcp-versioning-and-surface-governance).
9
+
10
+ ## Tiers
11
+
12
+ The MCP surface is split into four tiers. Callers filter via the
13
+ `tools/list` params `catalog`, `include`, `advanced`, or `tier` (see
14
+ [docs/integrations/mcp.md](../integrations/mcp.md)).
15
+
16
+ | Tier | Use | Stability guarantee |
17
+ |--------------|-----------------------------------------|----------------------------------------------------------|
18
+ | `facade` | `bclaw_work`, `bclaw_coordinate`, `bclaw_loop`, … | **Public, stable.** Breaking changes require a schema major bump. |
19
+ | `standard` | Common CRUD + read tools | **Public, stable.** Same rules as facade. |
20
+ | `advanced` | Low-level ops used by specialised flows | **Public, evolving.** Breaking changes require a minor bump + deprecation warning. |
21
+ | `internal` | Build-only, test fixtures, experimental | **Unstable.** No compatibility guarantees — can change between patch releases. |
22
+
23
+ `facade + standard` are the default `tools/list` output. `advanced`
24
+ must be opted-into. `internal` is never returned by `tools/list`.
25
+
26
+ A tool's tier is declared at registration time in
27
+ `src/commands/mcp.ts`. Moving a tool between tiers is itself a
28
+ contract change — moving *up* (e.g., advanced → standard) is safe,
29
+ moving *down* (standard → advanced) requires a deprecation window.
30
+
31
+ ## What counts as a breaking change
32
+
33
+ Anything that can cause a previously-working MCP client call to fail
34
+ or return a differently-shaped response. Concretely:
35
+
36
+ - **Tool surface**
37
+ - Removing a tool.
38
+ - Renaming a tool.
39
+ - Adding a required input argument.
40
+ - Changing an argument's type, enum values, or shape.
41
+ - Tightening validation in a way that rejects previously-accepted inputs.
42
+ - Moving a tool to a lower tier (e.g., standard → advanced or removed from default catalog).
43
+
44
+ - **Response shape**
45
+ - Removing a field from `structuredContent`.
46
+ - Renaming a field.
47
+ - Changing a field's type (string → object, array → scalar).
48
+ - Changing the meaning of an existing enum value.
49
+
50
+ - **Behaviour**
51
+ - Changing a tool's error model (new exit codes, new error shapes callers might pattern-match on).
52
+ - Changing default values in a way that flips a downstream decision (e.g., `openLoop: true` becoming the default when it was `false`).
53
+ - Removing or renaming env vars that affect tool behaviour (`BRAINCLAW_*`).
54
+
55
+ **Non-breaking additions** (safe at any time):
56
+
57
+ - Adding a new tool in any tier.
58
+ - Adding a new **optional** argument.
59
+ - Adding a new field to `structuredContent`.
60
+ - Loosening validation (accepting a superset of previous inputs).
61
+ - Moving a tool to a higher tier.
62
+
63
+ ## Schema versioning rules
64
+
65
+ `SCHEMA_VERSION` in `src/commands/mcp.ts` tracks the MCP *protocol*
66
+ version — distinct from the `package.json` app version which follows
67
+ app evolution. A call to `initialize` returns this in `serverInfo.version`
68
+ and every tool response includes it in `schema_version`.
69
+
70
+ Semver interpretation:
71
+
72
+ | Bump | Allowed changes | Required artefacts |
73
+ |-----------|-------------------------------------------------------------|------------------------------------------------------|
74
+ | **patch** (`x.y.Z`) | Bug fixes, doc updates, internal refactors with no contract change | Changelog entry under "Fixed" |
75
+ | **minor** (`x.Y.0`) | Non-breaking additions (new tools, optional args, new response fields). `advanced`-tier breaking changes *with* a deprecation window. | Changelog entry under "Added" / "Changed". Deprecation warnings for `advanced` changes. |
76
+ | **major** (`X.0.0`) | Breaking changes on `facade`/`standard` tiers. Removal of any deprecated tool. Schema rename/rework. | Changelog entry under "Removed" / "Breaking". Migration guide. Clients expect to update. |
77
+
78
+ Public stability guarantees apply from `1.0.0` onward (the Phase 3
79
+ canonical grammar refactor, `pln_c6472192`). Subsequent v1.x releases
80
+ follow the rules above strictly.
81
+
82
+ ## Deprecation policy
83
+
84
+ A tool slated for removal goes through a deprecation window, not a
85
+ silent drop. Pattern:
86
+
87
+ 1. **Mark deprecated.** Add an entry in `LEGACY_MCP_TOOL_WARNINGS`
88
+ (`src/commands/mcp.ts`) with a short message pointing at the
89
+ replacement. Tool keeps working. Changelog entry under "Deprecated".
90
+ 2. **Surface the warning.** Every call to the tool during this window
91
+ returns a `warning` in `structuredContent` and stderr. Warnings are
92
+ not errors — callers continue to work.
93
+ 3. **Minimum compatibility window.**
94
+ - `facade`/`standard` tier tools: at least **two minor releases**
95
+ with warnings before removal.
96
+ - `advanced` tier tools: at least **one minor release**.
97
+ - `internal` tools: no window required.
98
+ 4. **Removal.** Allowed only on a major bump. Changelog entry under
99
+ "Removed" with the replacement path.
100
+
101
+ Deprecation warnings must name the replacement. "Deprecated, use X
102
+ instead" — no orphan deprecations.
103
+
104
+ ## Changelog discipline
105
+
106
+ `docs/mcp-schema-changelog.md` is the single source of truth for MCP
107
+ protocol changes. Conventions:
108
+
109
+ - One section per released version (`## x.y.z`). The current in-flight
110
+ version is marked `(current)` until it ships; the marker moves on
111
+ release.
112
+ - Subsections in this order:
113
+ - `**Added**` — new surface.
114
+ - `**Changed**` — modifications to existing surface (non-breaking
115
+ unless flagged).
116
+ - `**Deprecated**` — tools entering the deprecation window.
117
+ - `**Removed**` — tools or fields gone.
118
+ - `**Fixed**` — bug fixes that may affect behaviour.
119
+ - `**Breaking**` — any breaking change, called out explicitly. Must
120
+ map to a major bump.
121
+ - Every changelog entry must name the tool and/or field it touches,
122
+ so a client maintainer can grep for references.
123
+ - `SCHEMA_VERSION` constant in `src/commands/mcp.ts` must match the
124
+ latest released version in this changelog. A mismatch is a bug —
125
+ bump the constant or amend the changelog, but do not ship drift.
126
+
127
+ ## Enforcement guard
128
+
129
+ `tests/unit/mcp-governance.test.ts` computes a stable fingerprint of
130
+ the published MCP surface from `src/commands/mcp.ts`:
131
+
132
+ - tool name
133
+ - tier
134
+ - category
135
+ - input schema with descriptions stripped
136
+
137
+ The test requires the current section of
138
+ `docs/mcp-schema-changelog.md` to include that fingerprint. If a
139
+ public tool is added, removed, moved between tiers, or has its input
140
+ contract changed, the test fails until the changelog is updated.
141
+
142
+ This guard is intentionally advisory-by-test rather than a runtime
143
+ block. It catches contract drift in CI and local validation without
144
+ preventing operators from using `brainclaw doctor` during active
145
+ development.
146
+
147
+ ## Schema source-of-truth — zod-derived inputSchemas
148
+
149
+ MCP tool `inputSchema` blocks in `src/commands/mcp.ts` are JSON Schema.
150
+ The runtime validation that actually rejects bad calls lives in zod
151
+ schemas elsewhere (e.g. `src/core/loops/types.ts`,
152
+ `src/core/loops/facade-schema.ts`). When the same shape is expressed
153
+ twice — once as zod, once as hand-written JSON Schema — the two drift,
154
+ silently. The class is the same one flagged by
155
+ `feedback_cross_agent_patterns` rule 2 ("catalog source-of-truth >
156
+ hardcoded constants"); it produced `trp#180` in May 2026 (Copilot
157
+ rejected `bclaw_loop` because `phases`/`slots` arrays had no `items`,
158
+ which Claude Code's permissive validator had silently accepted).
159
+
160
+ The fix is to derive the JSON Schema from the zod source at build time
161
+ and commit the generated artifact. Hand-written schemas remain for tools
162
+ without a zod backing (intent-polymorphic dispatchers, etc.) and stay
163
+ protected by the strict CI test in
164
+ `tests/unit/mcp-input-schema-strict.test.ts`.
165
+
166
+ ### How it works
167
+
168
+ 1. Zod schemas are exported from their owning module (e.g.
169
+ `LoopPhaseSchema`, `LoopSlotInputSchema`).
170
+ 2. `scripts/build-mcp-schemas.mjs` reads the compiled zod from `dist/`
171
+ and emits `src/commands/mcp-schemas.generated.ts` via zod v4's
172
+ native `z.toJSONSchema()`.
173
+ 3. `src/commands/mcp.ts` imports `generatedSchemas` and uses the
174
+ generated objects inline as `items:` / sub-schemas inside the tool's
175
+ `inputSchema`.
176
+ 4. The migrated tool descriptor carries
177
+ `annotations.schemaSource: 'zod-derived'` as a grep-target marker.
178
+ 5. `tests/unit/mcp-zod-parity.test.ts` re-runs `z.toJSONSchema()` at
179
+ test time and deep-compares against the committed generated file.
180
+ Drift fails CI with a one-line fix instruction.
181
+
182
+ The generated file is committed (protobuf pattern). Developers run
183
+ `npm run build:mcp-schemas` after editing a zod schema and commit the
184
+ regen alongside their source change. CI then verifies parity.
185
+
186
+ ### How to migrate a tool to zod-derived schemas
187
+
188
+ Use this checklist when you touch a tool's source for any reason. Do
189
+ **not** mass-migrate in a dedicated PR — the regression risk on the
190
+ combined diff outweighs the cleanup benefit.
191
+
192
+ 1. **Identify the zod schema.** Locate the existing zod that the
193
+ handler validates against (or extract a partial form for input-only
194
+ shapes — see `LoopSlotInputSchema` for the precedent).
195
+ 2. **Export it** as a named symbol so the build script can import it
196
+ from `dist/`.
197
+ 3. **Add the generation entry** in `scripts/build-mcp-schemas.mjs`
198
+ under the `SCHEMAS` map.
199
+ 4. **Run** `npm run build:mcp-schemas`. Inspect the diff in
200
+ `src/commands/mcp-schemas.generated.ts` — it must be small,
201
+ readable, and free of unwanted `$schema` / `$id` / `$defs` headers
202
+ for sub-schemas you intend to inline.
203
+ 5. **Replace the hand-written sub-schema** in `mcp.ts` with the
204
+ generated reference (e.g. `items: generatedSchemas.LoopPhase`).
205
+ 6. **Tag** the tool descriptor with
206
+ `annotations.schemaSource: 'zod-derived'`. The annotation is
207
+ informational today (see comment in `mcp.ts`); the parity test
208
+ currently hardcodes its (tool, schema) pairs explicitly.
209
+ 7. **Add an entry** to `tests/unit/mcp-zod-parity.test.ts` mirroring
210
+ the pattern of `LoopPhase` / `LoopSlotInput`. The test exists to
211
+ catch silent regen drift; it must include every newly migrated
212
+ shape.
213
+ 8. **Run the strict + parity tests** locally
214
+ (`node --test dist-test/tests/unit/mcp-input-schema-strict.test.js
215
+ dist-test/tests/unit/mcp-zod-parity.test.js`). Both must pass.
216
+
217
+ ### When to skip the migration
218
+
219
+ Some inputSchemas should stay hand-written:
220
+
221
+ - **Intent-polymorphic surfaces.** Tools whose `inputSchema` is a flat
222
+ union of intents (`bclaw_work`, `bclaw_coordinate`) where each
223
+ intent permits a different field set. zod can express this via
224
+ `discriminatedUnion`, but `z.toJSONSchema()` produces verbose
225
+ `oneOf` blocks that are harder to read than the hand-written
226
+ flat-properties form. The strict CI test (Phase 1) still protects
227
+ these.
228
+ - **Tools without a zod handler at all.** Some adapters and admin
229
+ utilities validate manually. Migrating them just to satisfy the
230
+ pattern would add zod definitions for shapes that have no other
231
+ consumer.
232
+ - **Build-time-only or developer-only tools.** No external client
233
+ reads their schema; drift cost is bounded.
234
+
235
+ ### Adding a new tool
236
+
237
+ For tools added _after_ Phase 2 of `pln#494`, the default is
238
+ zod-derived. Skip the hand-written sub-schemas entirely:
239
+
240
+ 1. Define the zod input schema in the owning module.
241
+ 2. Export it.
242
+ 3. Add it to the `SCHEMAS` map in `scripts/build-mcp-schemas.mjs`.
243
+ 4. Run `npm run build:mcp-schemas` and reference the generated entry
244
+ in your tool descriptor.
245
+ 5. Add the parity test entry.
246
+
247
+ The strict CI test still runs and validates the generated output —
248
+ defense in depth.
249
+
250
+ ## Changelog → code cross-check
251
+
252
+ Quick command to verify `SCHEMA_VERSION` matches the changelog:
253
+
254
+ ```bash
255
+ node -e "import('./dist/commands/mcp.js').then(m => console.log(m.SCHEMA_VERSION))"
256
+ head -5 docs/mcp-schema-changelog.md
257
+ ```
258
+
259
+ Both should report the same version. Drift = bug.
260
+
261
+ Quick command to inspect the current public-surface fingerprint:
262
+
263
+ ```bash
264
+ node --test dist-test/tests/unit/mcp-governance.test.js
265
+ ```
266
+
267
+ If the test fails, copy the reported fingerprint into the current
268
+ `docs/mcp-schema-changelog.md` section and describe the surface change.