klypix-mcp 1.65.0 → 1.66.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 CHANGED
@@ -79,7 +79,7 @@ npx klypix-mcp conformance
79
79
 
80
80
  It runs in a temporary fixture and touches nothing else. It checks tool discovery, task memory,
81
81
  truthful peer reporting, overlap surfacing, proactive logging, and in-band delivery of a peer note.
82
- It verifies 12 required coordination behaviours — not the 21 tools, and not the retrieval engine.
82
+ It verifies 15 required coordination behaviours — not the 21 tools, and not the retrieval engine.
83
83
 
84
84
  ---
85
85
 
@@ -150,7 +150,9 @@ not a filing convention.
150
150
 
151
151
  - **Decisions have a lifecycle.** A new decision that contradicts an old one supersedes it. The
152
152
  stale card is archived with an arrow and a date, never deleted, and later answers surface the
153
- correction rather than the corpse.
153
+ correction rather than the corpse. If a later decision returns to an earlier superseded stance,
154
+ high-confidence lineage leaves a dated `re-adopts` stamp on the new card plus an earlier→current
155
+ edge; the original A→B→C history remains intact.
154
156
  - **Corrections are explicit, not guessed.** Supersession fires on an UPPERCASE correction cue or
155
157
  an explicit edge. `brain_reconcile` only *proposes* stale-vs-correction pairs for a human to
156
158
  confirm.
@@ -274,7 +276,9 @@ the full brief written to disk for when broad history or status work needs it.
274
276
 
275
277
  Every other host gets a bounded ~2.8KB task capsule from one `brain_sync` call, plus a compact
276
278
  always-loaded `AGENTS.md` block that tells the agent to make that call at task start, when scope
277
- changes, and on completion. The gateway capsule is lexical-fast by design.
279
+ changes, and on completion. The gateway capsule is lexical-fast by design. A newly captured open
280
+ gap can claim a labeled `RECENT OPEN` slot only after clearing the normal lexical-relevance floor,
281
+ so fresh relevant findings are not crowded out by older area vocabulary.
278
282
 
279
283
  Briefs are **not** injected automatically on Cursor, Cline, Copilot, Gemini CLI or Antigravity —
280
284
  there are no lifecycle hooks on those hosts.
@@ -285,9 +289,12 @@ On Claude Code, decisions are captured automatically at turn end from inline `
285
289
  markers in the transcript, deduped, under a capture lock.
286
290
 
287
291
  On every other host, capture is explicit: `brain_note` runs the same capture engine as the hooks —
288
- dedup, supersession, `✓` resolve, `~` update in place, `+` skill, `closes:` — and stamps which
289
- agent wrote the card. (If you install the git commit hook from the KLYPIX app, commit messages also
290
- capture automatically, for any agent. That hook has no CLI installer.)
292
+ dedup, supersession, round-trip re-adoption receipts, `✓` resolve, `~` update in place, `+` skill,
293
+ `closes:` — and stamps which agent wrote the card. A `✓` question preference ranks only candidates
294
+ that already clear raw lexical overlap and two subject-identity anchors; generic lifecycle wording
295
+ cannot turn weak overlap into a closure.
296
+ (If you install the git commit hook from the KLYPIX app, commit messages also capture automatically,
297
+ for any agent. That hook has no CLI installer.)
291
298
 
292
299
  `brain_challenge` is the other direction: propose a decision and the brain answers with receipts —
293
300
  prior decisions that deterministically contradict it, standing rules that dispute it, and
@@ -323,14 +330,30 @@ have to have declared their files for the overlap to be visible at all.
323
330
 
324
331
  ## Handoffs and messages
325
332
 
326
- `brain_message` leaves one-time coordination notes for other sessions. They arrive on the peer's
327
- next KLYPIX action, expire after 24 hours, and are never written into the brain. Delivery is
328
- best-effort-proactive through MCP logging (which some hosts hide) and in-band on the peer's next
329
- action. A peer that stays offline past the TTL misses the note.
333
+ `brain_message` leaves one-time coordination notes for other sessions. A supported KLYPIX action
334
+ offers the note in model-visible context; the next independent supported action replays it and
335
+ records an acknowledgement. That acknowledgement proves only that a later action followed the
336
+ offer — never that a person read it or that an agent acted on it. Pending and offered notes survive
337
+ reconnects. Expiry or bounded-capacity eviction records a failed per-recipient receipt instead of
338
+ silently looking delivered. The core lane is machine-local, notes expire after 24 hours, and they
339
+ are never written into the brain.
330
340
 
331
341
  Durable handoffs go in the brain itself — decisions, findings, open questions and skills captured
332
342
  as cards, each stamped with the agent that wrote it.
333
343
 
344
+ ## Evidence-gated completion
345
+
346
+ When a task publishes a quantified or otherwise machine-checkable claim, it can attach one or more
347
+ versioned result manifests to `brain_sync { phase: "complete" }`. Each manifest binds the claim to a
348
+ report hash, producer/run provenance, the exact input and configuration fingerprints, and named
349
+ metrics with counts and tolerances. Matching peer evidence is recorded as corroboration; conflicting
350
+ or incomparable evidence returns `needs-reconciliation` and keeps the task scope active.
351
+
352
+ The gate fails closed. Once a task submits result evidence, it cannot bypass an invalid or
353
+ conflicting result by retrying completion without the manifest, and that obligation survives worker
354
+ restart, hibernation, and transparent hot-swap. A fresh `phase: "start"` is the explicit boundary for
355
+ a new task. The strict schema and reusable validator are exported as `klypix-mcp/result-reconcile`.
356
+
334
357
  ## Human control in Klypix
335
358
 
336
359
  > **Not a second brain. A shared one.**
@@ -471,14 +494,14 @@ The MCP verbs below are what agents call. These are what **you** call:
471
494
  |---|---|
472
495
  | `brain_ask` | Whole-brain question answering — correction-aware, `as_of` time travel |
473
496
  | `brain_challenge` | The brain argues back: contradictions with receipts, tried-and-reversed chains, standing rules, other-agent provenance flags |
474
- | `brain_note` | Capture with the full lifecycle — supersede / ✓ resolve / ~ update / 🛠 skill / `closes:` |
497
+ | `brain_note` | Capture with the full lifecycle — supersede / re-adopt / ✓ resolve / ~ update / 🛠 skill / `closes:` |
475
498
  | `brain_reconcile` | Proposes stale-vs-correction pairs and unrecorded migrations for a human to confirm |
476
499
  | `brain_insights` | Hubs, orphaned decisions, stale questions, area sizes |
477
500
  | `brain_lens` | Machine-readable freshness, provenance, activity, timeline, orrery and unresolved views |
478
501
  | `brain_garden` | Maintenance pass — proposes first, and cannot apply without an approval code the human generates |
479
502
  | `brain_doctor` | Self-diagnosis: version, core/enhanced host adapters, active sessions, tool count, projection drift |
480
- | `brain_message` | Session-to-session coordination notes (24h TTL, never written into the brain) |
481
- | `brain_sync` | Context Gateway: task capsule, active-task peers, exact-file overlap, one-time alerts, timing |
503
+ | `brain_message` | Session-to-session coordination notes with per-recipient offer / later-action acknowledgement / failure receipts (24h TTL, never written into the brain) |
504
+ | `brain_sync` | Context Gateway: task capsule, active-task peers, exact-file overlap, one-time alerts, timing, and optional result-manifest reconciliation |
482
505
  | `brain_connect` | Find and draw related-but-unlinked cards |
483
506
  | `project_map_context` | Read-only, bounded code-graph evidence beside correction-aware brain context, with exact-path review proposals; external artifacts (e.g. Graphify) are supported but never installed or run locally |
484
507
  | `project_map_scan` | KLYPIX's own zero-install scanner: gitignore-aware file inventory + file-level import edges (relative, tsconfig-alias, and monorepo-workspace imports resolved) written to `klypix-map/graph.json` — which then serves `project_map_context` automatically |
@@ -491,7 +514,7 @@ The MCP verbs below are what agents call. These are what **you** call:
491
514
  | `add_to_canvas` | Append cards/connections (positions preserved) |
492
515
  | `list_canvases` | List every `.klypix` in the vault |
493
516
 
494
- Exactly 19, machine-verifiable with `npx klypix-mcp doctor`.
517
+ Exactly 21, machine-verifiable with `npx klypix-mcp doctor`.
495
518
 
496
519
  > **`canvas_view`:** no MCP Apps host has been observed rendering the UI resource yet — there is no
497
520
  > screenshot and no host-level test. Hosts without the extension get clean text, which is the path
@@ -570,7 +593,8 @@ replaceable worker runs the brain core. A staged update is hash-verified, initia
570
593
  checked for backward-compatible tool schemas, and handed the current `brain_sync` task scope before
571
594
  the supervisor switches between requests. Added tools use the standard
572
595
  `notifications/tools/list_changed` signal. A failed or breaking candidate is rejected while the old
573
- worker keeps serving.
596
+ worker keeps serving. A blocked result claim is kept in a durable per-project/session marker, so a
597
+ worker replacement cannot turn a failed evidence check into a result-less completion.
574
598
 
575
599
  Compatible engine updates therefore activate behind the same live connection — no reconnect, no
576
600
  host restart. Three cases still require a deliberate reconnect or manual install: the one-time
@@ -601,7 +625,11 @@ keep lazy first-use indexing instead.
601
625
  - **Coordination state is local files.** The brain is a file in your repo; the presence lane is a
602
626
  file under your home directory. Nothing is uploaded — with one explicit, default-OFF exception:
603
627
  the cross-PC presence relay, which (only after per-brain consent in the KLYPIX desktop app)
604
- shares metadata-only presence frames over that brain's cloud channel. No consent, no frames.
628
+ shares whitelisted presence fields and the text of one-time coordination notes over that
629
+ brain's cloud channel. KLYPIX does not automatically attach file/card contents, diffs, or screen
630
+ data, but a note relays whatever its sender typed (and automatic overlap alerts name the declared
631
+ file paths involved). The scope is versioned: an older metadata-only grant does not authorize note
632
+ text and must be granted again. No current consent, no frames.
605
633
  - **`install` writes to your home directory:** `~/.claude/project-brain` (engine + runtime),
606
634
  `~/.claude/settings.json` (four hooks — written even if Claude Code is not installed),
607
635
  `~/.codex/AGENTS.md` (guidance block), and with `--codex-hooks`, `~/.codex/hooks.json`. It also
@@ -617,9 +645,10 @@ Read this section before you build on any of it.
617
645
  - **Coordination is machine-local and OS-user-local.** The presence lane is a file in your home
618
646
  directory. Two developers on two machines do not see each other's sessions, peers, overlaps or
619
647
  messages. This package ships the cross-machine presence *core* (`./presence-relay` — versioned
620
- metadata-only frames, a symmetric default-off consent gate, loop prevention and message dedup),
621
- but no transport: carrying frames between machines is the desktop app's job. With `klypix-mcp`
622
- alone, coordination is machine-local.
648
+ whitelisted presence metadata plus coordination-note text, a symmetric default-off consent gate,
649
+ loop prevention, stable message IDs and per-recipient-machine acknowledgement primitives), but no
650
+ transport: carrying frames between machines is the desktop app's job. With `klypix-mcp` alone,
651
+ coordination is machine-local.
623
652
  - **Overlap matching is exact-path, and both sides must declare.** A session that never declares
624
653
  its expected files is invisible to overlap detection, and `src/auth/token.ts` does not match a
625
654
  rename or a parent directory.
@@ -685,7 +714,7 @@ Your `brain.klypix` is yours — it is a plain ZIP and stays readable with or wi
685
714
  Issues and pull requests: [github.com/dahshanlabs/klypix-mcp](https://github.com/dahshanlabs/klypix-mcp).
686
715
  Questions or feedback: [hello@klypix.com](mailto:hello@klypix.com).
687
716
 
688
- The repository carries 49 test files, 45 of them in the `npm test` chain, covering the presence
717
+ The repository carries 59 test files, 54 of them in the `npm test` chain, covering the presence
689
718
  lane and its cross-machine relay, the Context Gateway, supervisor hot-swap, auto-update, retrieval
690
719
  quality, decay, challenge, lenses, the format guard, the git tools (including a real `git merge`
691
720
  through the merge driver), uninstall, and conformance. Run them with `npm test` from a clone — they
@@ -37,8 +37,13 @@ if (action === 'list') {
37
37
  console.log(`${entries.length} deleted card(s) in ${path.basename(brainPath)} — newest first\n`);
38
38
  for (const e of entries) {
39
39
  const full = ids.includes(e.id) ? await readGraveyardCard(buf, e.id) : null;
40
- console.log(` ${e.id} ${ago(e.deletedAt).padEnd(9)} ${e.area ? `[${e.area}] ` : ''}${e.preview || '(no text)'}`);
40
+ const label = e.summary?.label || e.preview || `(${e.summary?.type || 'unknown'} item)`;
41
+ const audit = e.deletion?.confidence === 'legacy'
42
+ ? 'legacy source unverified'
43
+ : `${e.deletion?.initiator || 'unknown'} via ${e.deletion?.cause || 'unclassified'}`;
44
+ console.log(` ${e.id} ${ago(e.deletedAt).padEnd(9)} ${e.area ? `[${e.area}] ` : ''}${label} <${audit}>`);
41
45
  if (full?.content) console.log(`\n${String(full.content).split('\n').map((l) => ` ${l}`).join('\n')}\n`);
46
+ else if (full) console.log(`\n ${JSON.stringify(e.summary || { type: full.type || 'unknown' })}\n`);
42
47
  }
43
48
  console.log(`\nFull text: npx klypix-mcp brain-deleted list <id> --brain "${brainPath}"`);
44
49
  console.log(`Restore: npx klypix-mcp brain-deleted restore <id>`);
@@ -106,22 +106,32 @@ try {
106
106
  const tools = await a.client.listTools();
107
107
  checks.brainSyncDiscoverable = tools.tools?.some((tool) => tool.name === 'brain_sync') === true;
108
108
 
109
- const aStart = await a.client.callTool({
110
- name: 'brain_sync',
111
- arguments: {
112
- phase: 'start',
113
- intent: 'Validate automatic Codex Context Gateway coordination',
114
- files: ['src/conformance-overlap.ts'],
115
- },
116
- });
117
- const bStart = await b.client.callTool({
118
- name: 'brain_sync',
119
- arguments: {
120
- phase: 'start',
121
- intent: 'Validate proactive overlap delivery from a second session',
122
- files: ['src/conformance-overlap.ts'],
123
- },
124
- });
109
+ const syncStart = async (client, intent, expectedTasks) => {
110
+ let response;
111
+ for (let attempt = 1; attempt <= 3; attempt++) {
112
+ response = await client.callTool({
113
+ name: 'brain_sync',
114
+ arguments: {
115
+ phase: 'start',
116
+ intent,
117
+ files: ['src/conformance-overlap.ts'],
118
+ },
119
+ });
120
+ const structured = response.structuredContent || {};
121
+ if (Number.isFinite(structured.timingMs?.total)
122
+ && structured.counts?.activeTasks === expectedTasks) return { response, attempt };
123
+ await wait(75);
124
+ }
125
+ return { response, attempt: 3 };
126
+ };
127
+ // The lane is deliberately lock-protected and the two real clients heartbeat
128
+ // concurrently. A bounded retry proves convergence without turning one
129
+ // transient lock collision into a false product failure.
130
+ const aStarted = await syncStart(a.client, 'Validate automatic Codex Context Gateway coordination', 1);
131
+ const bStarted = await syncStart(b.client, 'Validate proactive overlap delivery from a second session', 2);
132
+ const aStart = aStarted.response;
133
+ const bStart = bStarted.response;
134
+ metrics.startAttempts = { first: aStarted.attempt, second: bStarted.attempt };
125
135
  const aStructured = aStart.structuredContent || {};
126
136
  const bStructured = bStart.structuredContent || {};
127
137
  checks.taskMemory = Array.isArray(aStructured.context?.hits) && aStructured.context.hits.length > 0;
@@ -144,16 +154,25 @@ try {
144
154
  metrics.firstClientLogCount = a.logs.length;
145
155
  if (!checks.proactiveLogging && a.logs.length) metrics.firstClientLogs = a.logs.slice(-4);
146
156
 
147
- const aCheckpoint = await a.client.callTool({
148
- name: 'brain_sync',
149
- arguments: {
150
- phase: 'checkpoint',
151
- intent: 'Validate automatic Codex Context Gateway coordination',
152
- files: ['src/conformance-overlap.ts'],
153
- },
154
- });
155
- const checkpointStructured = aCheckpoint.structuredContent || {};
156
- checks.guaranteedInBandDelivery = checkpointStructured.messages?.some((message) =>
157
+ let checkpointStructured = {};
158
+ let inBandAttempts = 0;
159
+ for (let attempt = 1; attempt <= 3; attempt++) {
160
+ inBandAttempts = attempt;
161
+ const aCheckpoint = await a.client.callTool({
162
+ name: 'brain_sync',
163
+ arguments: {
164
+ phase: 'checkpoint',
165
+ intent: 'Validate automatic Codex Context Gateway coordination',
166
+ files: ['src/conformance-overlap.ts'],
167
+ },
168
+ });
169
+ checkpointStructured = aCheckpoint.structuredContent || {};
170
+ if (checkpointStructured.messages?.some((message) =>
171
+ String(message.text).includes('Automatic KLYPIX overlap alert'))) break;
172
+ await wait(75);
173
+ }
174
+ metrics.inBandAttempts = inBandAttempts;
175
+ checks.durableInBandOffer = checkpointStructured.messages?.some((message) =>
157
176
  String(message.text).includes('Automatic KLYPIX overlap alert')) === true;
158
177
 
159
178
  await Promise.all([
@@ -188,10 +207,26 @@ try {
188
207
  && /no live session declared docs\/unowned\.md/.test(nobody.reason);
189
208
 
190
209
  const receipt = summarizeReceipts({
191
- messages: [{ id: 'finding-note', from: 'finding-sender', to: 'all', text: 'verified note', ts: now - 1_000, candidateIds: ['finding-owner'], seen: ['finding-owner'] }],
210
+ messages: [{
211
+ id: 'finding-note',
212
+ from: 'finding-sender',
213
+ to: 'all',
214
+ text: 'verified note',
215
+ ts: now - 1_000,
216
+ candidateIds: ['finding-owner'],
217
+ deliveryVersion: 2,
218
+ deliveries: [{
219
+ recipientId: 'finding-owner',
220
+ state: 'acknowledged',
221
+ attempts: 1,
222
+ offeredAt: now - 900,
223
+ acknowledgedAt: now - 500,
224
+ }],
225
+ seen: ['finding-owner'],
226
+ }],
192
227
  sessions: lane, selfId: 'finding-sender', now,
193
228
  });
194
- checks.findingReceiptRendered = /shown to all 1 peer\(s\) that were live/.test(renderReceiptSummary(receipt));
229
+ checks.findingReceiptRendered = /model-context delivery acknowledged by all 1 target peer\(s\) on a later action \(not human-read\)/.test(renderReceiptSummary(receipt));
195
230
  }
196
231
 
197
232
  // ── Cross-PC presence: simulated two-machine scenario ─────────────────────
@@ -305,7 +340,7 @@ const required = [
305
340
  'exactBlockingOverlap',
306
341
  'alertQueued',
307
342
  'proactiveLogging',
308
- 'guaranteedInBandDelivery',
343
+ 'durableInBandOffer',
309
344
  'findingRouteOwnerReason',
310
345
  'findingRouteNobodyReason',
311
346
  'findingReceiptRendered',
@@ -323,7 +358,8 @@ const result = {
323
358
  metrics,
324
359
  contract: {
325
360
  proactive: 'best-effort MCP logging notification',
326
- guaranteed: 'same alert on the next KLYPIX action',
361
+ inBand: 'a retained machine-local note is offered on a supported model-context KLYPIX action, then acknowledged only by a later independent action; expiry/overflow are failed receipts',
362
+ crossMachine: 'relay primitives require caller-confirmed durable insertion and a per-recipient-machine acknowledgement; app bridge wiring is a separate conformance boundary',
327
363
  },
328
364
  };
329
365
 
@@ -336,6 +372,6 @@ if (jsonMode) {
336
372
  }
337
373
  if (checks.error) console.log(` error: ${checks.error}`);
338
374
  console.log(` memory/coordination: ${metrics.firstClientMs ?? '?'}ms / ${metrics.secondClientMs ?? '?'}ms`);
339
- console.log(' proactive notifications are best-effort; next-action delivery is guaranteed.');
375
+ console.log(' proactive notifications are best-effort; retained notes use offer → later-action acknowledgement, with explicit failure receipts.');
340
376
  }
341
377
  process.exit(ok ? 0 : 1);
@@ -12,7 +12,7 @@
12
12
  // • ONE merge engine — the driver rides src/merge-brains.mjs verbatim.
13
13
  // • The registered driver path is the INSTALLED runtime
14
14
  // (~/.claude/project-brain) — stable across npx cache evictions; this
15
- // module self-provisions the three engine files + their two deps there
15
+ // module self-provisions the four engine files + their two deps there
16
16
  // when missing, without running the full hook installer.
17
17
  // • A truncated list must NEVER render as complete: every capped section
18
18
  // emits its "…and N more" through an unguarded push.
@@ -85,11 +85,11 @@ async function loadEngine() {
85
85
 
86
86
  // ── git-driver ──────────────────────────────────────────────────────────────
87
87
 
88
- const ENGINE_FILES = ['klypix-merge-driver.mjs', 'merge-brains.mjs', 'klypix-format.mjs'];
88
+ const ENGINE_FILES = ['klypix-merge-driver.mjs', 'merge-brains.mjs', 'klypix-format.mjs', 'brain-graveyard.mjs'];
89
89
  const ENGINE_DEPS = ['jszip', 'fractional-indexing'];
90
90
 
91
- // Make sure the INSTALLED runtime can actually run the driver: the three
92
- // engine files plus their two (dependency-free) deps. This is deliberately a
91
+ // Make sure the INSTALLED runtime can actually run the driver: the four
92
+ // engine files plus their two runtime deps. This is deliberately a
93
93
  // light provision — it never touches hooks or servers; the full installer
94
94
  // remains `npx klypix-mcp install`.
95
95
  function ensureDriverRuntime() {
@@ -226,7 +226,7 @@ const flatten = (code) => code
226
226
  .replace(/\.\.\/src\/klypix-(core|format)\.mjs/g, './klypix-$1.mjs')
227
227
  // brain-doctor + agent-rules (the server's lazy `import('../src/brain-doctor.mjs')`
228
228
  // for the brain_doctor tool) → flat sibling refs in the runtime layout.
229
- .replace(/\.\.\/src\/(brain-doctor|agent-rules|mcp-presence|mcp-supervisor|mcp-auto-update|semantic-memory|runtime-inspector|project-graph|git-capture-install)\.mjs/g, './$1.mjs')
229
+ .replace(/\.\.\/src\/(bench|brain-doctor|agent-presence|agent-rules|finding-routing|mcp-presence|mcp-supervisor|mcp-auto-update|presence-relay|semantic-memory|runtime-inspector|project-graph|git-capture-install)\.mjs/g, './$1.mjs')
230
230
  .replace(/klypix-worker\.mjs/g, 'klypix-mcp-worker.mjs')
231
231
  .replace(/const PKG_VERSION = \(\(\) => \{[\s\S]*?\}\)\(\);/, `const PKG_VERSION = '${VERSION}'; // baked at install (flat layout has no package.json)`);
232
232
 
@@ -293,7 +293,7 @@ try {
293
293
  // canvas-view-app.html is the canvas_view MCP App UI — staged raw (an HTML
294
294
  // file must never get a JS-comment banner) beside the flat server, which
295
295
  // resolves it via its ./canvas-view-app.html candidate path.
296
- for (const f of ['global-brain-hook.mjs', 'brain-semantic.mjs', 'semantic-memory.mjs', 'brain-note.mjs', 'brain-git-hook.mjs', 'git-capture-install.mjs', 'brain-history.mjs', 'brain-graveyard.mjs', 'klypix-format.mjs', 'klypix-core.mjs', 'brain-write-lock.mjs', 'agent-rules.mjs', 'brain-doctor.mjs', 'agent-presence.mjs', 'mcp-presence.mjs', 'finding-routing.mjs', 'mcp-supervisor.mjs', 'mcp-auto-update.mjs', 'runtime-inspector.mjs', 'project-graph.mjs', 'bench.mjs', 'codex-brain-hook.mjs', 'codex-hooks.mjs', 'canvas-view-app.html']) {
296
+ for (const f of ['global-brain-hook.mjs', 'brain-semantic.mjs', 'semantic-memory.mjs', 'brain-note.mjs', 'brain-git-hook.mjs', 'git-capture-install.mjs', 'brain-history.mjs', 'brain-graveyard.mjs', 'klypix-format.mjs', 'klypix-core.mjs', 'brain-write-lock.mjs', 'agent-rules.mjs', 'brain-doctor.mjs', 'agent-presence.mjs', 'mcp-presence.mjs', 'result-reconcile.mjs', 'finding-routing.mjs', 'presence-relay.mjs', 'mcp-supervisor.mjs', 'mcp-auto-update.mjs', 'runtime-inspector.mjs', 'project-graph.mjs', 'bench.mjs', 'codex-brain-hook.mjs', 'codex-hooks.mjs', 'canvas-view-app.html']) {
297
297
  const s = path.join(SRC, f); if (exists(s)) staged.push({ dst: f, content: fs.readFileSync(s, 'utf8') });
298
298
  }
299
299
  for (const [src, dst] of [
@@ -509,7 +509,7 @@ server.registerTool('brain_note', {
509
509
 
510
510
  server.registerTool('brain_message', {
511
511
  title: 'Message the other live agent sessions on this project (one-time note, not a brain card)',
512
- description: 'Leave a DELIBERATE, targeted note for the OTHER active agent sessions working on this project right now ("merged the hook refactor — rebase before you commit", "don\'t touch canvasStore, mid-refactor"). Any MCP client can send and receive through the shared presence lane. Hookless MCP peers receive each note once on their next KLYPIX tool call (and may also see a host logging notification); lifecycle hooks provide more proactive delivery. Delivery is BEST-EFFORT, not guaranteed: the lane is machine-local and OS-user-local (a teammate on another machine never sees it) and a peer that takes no KLYPIX action within the 24h TTL misses the note entirely — so never tell the user a note was received. Ephemeral (expires in 24h) and NOT persisted to the brain — for a durable decision use brain_note instead.',
512
+ description: 'Leave a DELIBERATE, targeted note for the OTHER active agent sessions working on this project right now ("merged the hook refactor — rebase before you commit", "don\'t touch canvasStore, mid-refactor"). Any MCP client can send and receive through the shared machine-local presence lane. A supported lifecycle event or KLYPIX tool result offers the note into model-visible context; a later independent supported action acknowledges that offer. Pending/offered notes replay after reconnect, while expiry or capacity loss leaves a failed per-recipient receipt instead of silently disappearing. Acknowledged means a later action followed the offer — it is NOT proof a human read it. Delivery remains OS-user-local, machine-local, bounded by a 24h TTL, and unavailable to a peer that never takes a supported action. Ephemeral and NOT persisted to the brain — for a durable decision use brain_note instead.',
513
513
  inputSchema: {
514
514
  text: z.string().describe('The note to deliver (kept to 400 chars).'),
515
515
  to: z.string().optional().describe('Target hint — a peer session id-prefix or branch name; omit or "all" for every live session.'),
@@ -518,12 +518,23 @@ server.registerTool('brain_message', {
518
518
  }, async ({ text, to, canvas }) => {
519
519
  let via; try { via = server.server.getClientVersion()?.name; } catch { /* optional */ }
520
520
  mcpPresence.noteSent(text);
521
- return toContent(await opBrainMessage({ vault: mcpPresence.vault, canvas, text, to, via }));
521
+ return toContent(await opBrainMessage({
522
+ vault: mcpPresence.vault,
523
+ // Bind the default message lane to the brain this worker actually joined.
524
+ // The worker process can be launched from an IDE/install directory that has
525
+ // a different ancestor brain; falling back to process.cwd() would split the
526
+ // sender presence and its message across two unrelated project lanes.
527
+ canvas: canvas || mcpPresence.brainPath,
528
+ text,
529
+ to,
530
+ via,
531
+ from: mcpPresence.refreshIdentity(),
532
+ }));
522
533
  });
523
534
 
524
535
  server.registerTool('brain_sync', {
525
536
  title: 'KLYPIX Context Gateway — synchronize task, peers, conflicts, and relevant memory',
526
- description: 'APPROVAL-FREE task gateway over the authorized MCP connection. Call FIRST with a concise intent and expected files, again when scope changes, and with phase:"complete" before the final response. One bounded response returns compact task-relevant brain context, active TASK peers (idle connections hidden), one-time messages, structured exact-file conflicts, and late-arrival overlap alerts. Works on any MCP host — it needs only the authorized MCP connection, so native lifecycle hooks are optional. LIMITS: conflict matching is EXACT-PATH and both sessions must have declared their files, coordination is machine-local and OS-user-local (a teammate on another machine is invisible), and overlap is ADVISORY — nothing is blocked.',
537
+ description: 'APPROVAL-FREE task gateway over the authorized MCP connection. Call FIRST with a concise intent and expected files, again when scope changes, and with phase:"complete" before the final response. One bounded response returns compact task-relevant brain context, active TASK peers (idle connections hidden), one-time messages, structured exact-file conflicts, and late-arrival overlap alerts. A completion that supplies machine-checkable result manifests is fail-closed: invalid, conflicting, or incomparable evidence returns needs-reconciliation and retains task scope. Works on any MCP host — it needs only the authorized MCP connection, so native lifecycle hooks are optional. LIMITS: conflict matching is EXACT-PATH and both sessions must have declared their files, coordination/result reconciliation is machine-local and OS-user-local (a teammate on another machine is invisible), and file overlap remains ADVISORY.',
527
538
  annotations: {
528
539
  destructiveHint: false,
529
540
  idempotentHint: true,
@@ -534,11 +545,24 @@ server.registerTool('brain_sync', {
534
545
  intent: z.string().max(160).optional().describe('One sentence describing the current task. Supply for start/checkpoint; completion clears it.'),
535
546
  files: z.array(z.string()).max(20).optional().describe('Project-relative files you expect to touch or have touched. Exact overlaps with peers are flagged.'),
536
547
  phase: z.enum(['start', 'checkpoint', 'complete']).optional().describe('start replaces prior task scope; checkpoint merges changed scope; complete clears task intent/files. Default: checkpoint.'),
537
- include_context: z.boolean().optional().describe('Include fast task-relevant brain cards in the same response. Defaults true; ignored for phase complete.'),
548
+ include_context: z.boolean().optional().describe('Include fast task-relevant brain cards and offer queued coordination notes in the same response. Defaults true; false also defers note delivery so internal supervisor probes cannot consume model-visible messages.'),
549
+ // Deliberately permissive at the MCP/Zod boundary. The authoritative,
550
+ // versioned fail-closed validator lives in result-reconcile.mjs and must see
551
+ // malformed/unknown nested fields so it can persist the evidence-required
552
+ // marker before rejecting them. A strict transport schema rejected first,
553
+ // allowing a later result-less completion to bypass that state entirely.
554
+ results: z.unknown().optional().describe('On phase complete, 1-8 result manifests for stable claim keys. The in-handler versioned validator rejects malformed, empty, unknown-field, or incomparable evidence and retains task scope.'),
538
555
  },
539
- }, async ({ project, intent, files, phase, include_context }) => {
556
+ }, async ({ project, intent, files, phase, include_context, results }) => {
540
557
  const totalStartedAt = Date.now();
541
- const report = mcpPresence.sync({ project, intent, files, phase });
558
+ const report = mcpPresence.sync({
559
+ project,
560
+ intent,
561
+ files,
562
+ phase,
563
+ results,
564
+ deliverMessages: include_context !== false,
565
+ });
542
566
  // Zero-manual harness convergence: brain_sync is the one project-aware
543
567
  // gateway every MCP host can call. Register MCP-only projects here (Claude's
544
568
  // lifecycle hook is no longer the sole registry writer), then reconcile only
@@ -624,6 +648,7 @@ server.registerTool('brain_sync', {
624
648
  text: [report.text, harnessText, shipNotice, contextText, timingText].filter(Boolean).join('\n\n'),
625
649
  }],
626
650
  structuredContent,
651
+ ...(report.isError ? { isError: true } : {}),
627
652
  };
628
653
  });
629
654
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klypix-mcp",
3
- "version": "1.65.0",
3
+ "version": "1.66.0",
4
4
  "description": "Shared project brain and MCP coordination server for multi-agent coding.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -53,6 +53,7 @@
53
53
  "./core": "./src/klypix-core.mjs",
54
54
  "./presence": "./src/agent-presence.mjs",
55
55
  "./mcp-presence": "./src/mcp-presence.mjs",
56
+ "./result-reconcile": "./src/result-reconcile.mjs",
56
57
  "./presence-relay": "./src/presence-relay.mjs",
57
58
  "./supervisor": "./src/mcp-supervisor.mjs",
58
59
  "./runtime-inspector": "./src/runtime-inspector.mjs",
@@ -79,7 +80,7 @@
79
80
  "test:project-graph": "node test/project-graph.mjs",
80
81
  "bench": "node bin/klypix-mcp.mjs bench",
81
82
  "test:bench": "node test/bench.mjs",
82
- "test": "node test/publish-verdict.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/archived-visibility.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
83
+ "test": "node test/publish-verdict.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/result-reconcile.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/archived-visibility.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
83
84
  "test:memory": "node test/memory-runtime.mjs",
84
85
  "test:memory:soak": "node --expose-gc test/memory-soak.mjs",
85
86
  "runtime": "node bin/klypix-runtime.mjs"