brainclaw 1.9.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.
- package/README.md +585 -499
- package/dist/brainclaw-vscode.vsix +0 -0
- package/dist/commands/harvest.js +1 -1
- package/dist/commands/hooks.js +73 -73
- package/dist/commands/init.js +1 -1
- package/dist/commands/install-hooks.js +78 -78
- package/dist/commands/mcp-read-handlers.js +57 -14
- package/dist/commands/mcp.js +79 -13
- package/dist/commands/switch.js +26 -5
- package/dist/commands/version.js +1 -1
- package/dist/core/agent-capability.js +19 -4
- package/dist/core/agent-files.js +119 -119
- package/dist/core/codev-prompts.js +38 -38
- package/dist/core/default-profiles/doctor.yaml +11 -11
- package/dist/core/default-profiles/janitor.yaml +11 -11
- package/dist/core/default-profiles/onboarder.yaml +11 -11
- package/dist/core/default-profiles/reviewer.yaml +13 -13
- package/dist/core/dispatcher.js +1 -1
- package/dist/core/entity-operations.js +29 -3
- package/dist/core/execution.js +1 -1
- package/dist/core/loops/verbs.js +0 -1
- package/dist/core/messaging.js +2 -2
- package/dist/core/protocol-skills.js +164 -164
- package/dist/core/runtime-signals.js +1 -1
- package/dist/core/search.js +19 -2
- package/dist/core/security-guard.js +207 -207
- package/dist/core/spawn-check.js +16 -2
- package/dist/core/staleness.js +1 -1
- package/dist/core/store-resolution.js +26 -7
- package/dist/core/worktree.js +18 -18
- package/dist/facts.js +3 -3
- package/dist/facts.json +2 -2
- package/docs/PROTOCOL.md +1 -1
- package/docs/adapters/openclaw.md +43 -43
- package/docs/architecture/project-refs.md +328 -328
- package/docs/cli.md +2093 -2093
- package/docs/concepts/coordination.md +52 -52
- package/docs/concepts/coordinator-runbook.md +129 -129
- package/docs/concepts/dispatch-lifecycle.md +245 -245
- package/docs/concepts/event-log-store.md +928 -928
- package/docs/concepts/ideation-loop.md +317 -317
- package/docs/concepts/loop-engine.md +520 -511
- package/docs/concepts/mcp-governance.md +268 -268
- package/docs/concepts/memory.md +84 -84
- package/docs/concepts/multi-agent-workflows.md +167 -167
- package/docs/concepts/observer-protocol.md +361 -361
- package/docs/concepts/plans-and-claims.md +217 -217
- package/docs/concepts/project-md-convention.md +35 -35
- package/docs/concepts/runtime-notes.md +38 -38
- package/docs/concepts/troubleshooting.md +254 -254
- package/docs/concepts/workspace-bootstrapping.md +142 -142
- package/docs/context-format-changelog.md +35 -35
- package/docs/context-format.md +48 -48
- package/docs/index.md +65 -65
- package/docs/integrations/agents.md +158 -158
- package/docs/integrations/claude-code.md +23 -23
- package/docs/integrations/cline.md +77 -77
- package/docs/integrations/continue.md +55 -55
- package/docs/integrations/copilot.md +68 -68
- package/docs/integrations/cursor.md +23 -23
- package/docs/integrations/kilocode.md +72 -72
- package/docs/integrations/mcp.md +377 -377
- package/docs/integrations/mistral-vibe.md +122 -122
- package/docs/integrations/openclaw.md +92 -92
- package/docs/integrations/opencode.md +84 -84
- package/docs/integrations/overview.md +115 -115
- package/docs/integrations/roo.md +71 -71
- package/docs/integrations/windsurf.md +77 -77
- package/docs/mcp-schema-changelog.md +360 -356
- package/docs/playbooks/integration/index.md +121 -121
- package/docs/playbooks/orchestration.md +37 -0
- package/docs/playbooks/productivity/index.md +99 -99
- package/docs/playbooks/team/index.md +117 -117
- package/docs/product/agent-first-model.md +184 -184
- package/docs/product/entity-model-audit.md +462 -462
- package/docs/product/positioning.md +86 -86
- package/docs/quickstart-existing-project.md +107 -107
- package/docs/quickstart.md +183 -183
- package/docs/release-maintenance.md +79 -79
- package/docs/reputation.md +52 -52
- package/docs/review.md +45 -45
- package/docs/security.md +212 -212
- package/docs/server-operations.md +118 -118
- package/docs/storage.md +106 -106
- package/package.json +80 -65
- package/docs/concepts/event-log-store-critique-A.md +0 -333
- package/docs/concepts/event-log-store-critique-B.md +0 -353
- package/docs/concepts/event-log-store-phase0-measurements.md +0 -58
- package/docs/concepts/event-log-store-proposal-A.md +0 -365
- package/docs/concepts/event-log-store-proposal-B.md +0 -404
- package/docs/concepts/identity-model-proposal.md +0 -371
|
@@ -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.
|