klypix-mcp 1.49.1 → 1.49.2

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/A2A.md CHANGED
@@ -46,11 +46,13 @@ the skills below.
46
46
  |---|---|---|
47
47
  | `make_board` | Create a new `.klypix` from cards + connections | a `.klypix` **FilePart** + summary |
48
48
  | `remember` | Append cards/decisions to an existing canvas (positions preserved) | the updated `.klypix` |
49
+ | `learn_skill` | Capture a reusable how-to / gotcha as a 🛠 skill card — resurfaces every session | the updated `.klypix` |
49
50
  | `recall` | Search card text/titles/`#tags` across the vault | matching cards (text) |
50
51
  | `read_canvas` | Read one canvas (cards, graph, `[[links]]`) + its images | markdown + image FileParts |
51
52
  | `list_canvases` | List canvases with counts | text |
52
53
  | `brain_insights` | Hubs / orphans / stale questions in a brain | text |
53
54
  | `search_all_brains` | Cross-project memory search (semantic + lexical) | text |
55
+ | `brain_connect` | Find and draw related-but-unlinked cards (proposes before it applies) | text |
54
56
 
55
57
  ## Talk to it (JSON-RPC 2.0)
56
58
 
package/FORMAT.md CHANGED
@@ -47,7 +47,8 @@ writer guarantees the content-addressed `images/ files/ thumbs/` split.
47
47
  "updatedAt": "ISO-8601",
48
48
  "title": "My board",
49
49
  "stats": { "itemCount": 12, "assetCount": 3, "totalBytes": 0 },
50
- "sync": { "enabled": false, "lastSyncRev": null, "lastSyncAt": null, "deviceId": "dev_…" }
50
+ "sync": { "enabled": false, "lastSyncRev": null, "lastSyncAt": null, "deviceId": "dev_…" },
51
+ "cloud": { "blobId": "702ecfe0-…", "linkedAt": "ISO-8601", "linkedBy": "Sara Ali" }
51
52
  }
52
53
  ```
53
54
 
@@ -65,6 +66,13 @@ writer guarantees the content-addressed `images/ files/ thumbs/` split.
65
66
  `items/`. Never use `stats` as an integrity check.
66
67
  - `sync` records whether the file is opted into the app's cloud sync; it carries no
67
68
  content and no credentials.
69
+ - **`cloud`** — optional and additive; written by the KLYPIX app when a brain is
70
+ shared, naming the encrypted cloud copy this file pairs with. It exists so the
71
+ mapping **travels inside the file**: clone the repo, or email the `.klypix`, and the
72
+ copy that arrives already knows its cloud twin — no server lookup, works offline.
73
+ **The encryption key is never here.** The `blobId` alone reaches nothing: the cloud
74
+ copy is ciphertext, and the key travels only in a share link's URL fragment. A
75
+ reader that does not care about cloud sync should ignore this object.
68
76
 
69
77
  ## `canvas.json`
70
78
 
@@ -115,13 +123,27 @@ strings: `text`, `box`, `image`, `file`, `container`, `approval`, `link`,
115
123
  "border": true,
116
124
  "heading": false,
117
125
  "createdBy": "agent",
118
- "createdVia": "claude-code"
126
+ "createdVia": "claude-code",
127
+ "author": "Sara Ali",
128
+ "updatedAt": 1785500000000
119
129
  }
120
130
  ```
121
131
 
122
132
  `createdBy` (`user` | `agent`) and the optional `createdVia` (which agent/channel
123
133
  captured it) are the provenance bits the brain surfaces as badges and lenses.
124
134
 
135
+ The optional **`author`** answers the question a team actually asks: `createdBy` says
136
+ *what* wrote a card, `author` says *whose*. It is resolved from `git config user.name`
137
+ so brain attribution matches commit attribution with no configuration (override with
138
+ `KLYPIX_AUTHOR`; falls back to the OS user; simply absent if neither resolves).
139
+
140
+ **`updatedAt` is VOLATILE — never treat it as content.** It is restamped by the act of
141
+ writing, so two copies of an identical card differ in it. Any comparison that decides
142
+ "did this card change" must strip `updatedAt` (and the derived `zIndex` in
143
+ `positions`) before comparing, or a plain re-save reads as an edit. The merge engine
144
+ learned this the hard way: a byte-compare spawned conflict twins for cards nobody
145
+ touched. `mergeBrains` exports `sameMeaning(a, b)` as the single correct comparison.
146
+
125
147
  ## Bytes: when they are embedded vs referenced
126
148
 
127
149
  **Embedded** — the bytes live inside the ZIP under `assets/`, and the item JSON
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 7 coordination behaviours — not the 18 tools, and not the retrieval engine.
82
+ It verifies 12 required coordination behaviours — not the 18 tools, and not the retrieval engine.
83
83
 
84
84
  ---
85
85
 
@@ -133,9 +133,9 @@ content.
133
133
  npx klypix-mcp link --check # audits without writing; exits non-zero on drift
134
134
  ```
135
135
 
136
- > Use that exact form. The standalone `klypix-link` binary currently drops the `--check` flag and
137
- > writes instead (`bin/klypix-link.mjs:23`). Do not wire `npx -p klypix-mcp klypix-link --check`
138
- > into CI until that is fixed.
136
+ > Either form works, and both are safe in CI: `npx -p klypix-mcp klypix-link --check` used to
137
+ > drop `--check` and write anyway fixed, and locked by `test/cli-args.mjs`, which asserts the
138
+ > standalone bin and the dispatcher parse arguments identically.
139
139
 
140
140
  **Give a project a brain** by dropping a `brain.klypix` into it — the
141
141
  [KLYPIX app](https://klypix.com) does it in one click (*Save canvas as project brain*), or
@@ -494,7 +494,10 @@ Read this section before you build on any of it.
494
494
 
495
495
  - **Coordination is machine-local and OS-user-local.** The presence lane is a file in your home
496
496
  directory. Two developers on two machines do not see each other's sessions, peers, overlaps or
497
- messages. There is no cross-machine or cross-team coordination today.
497
+ messages. This package ships the cross-machine presence *core* (`./presence-relay` versioned
498
+ metadata-only frames, a symmetric default-off consent gate, loop prevention and message dedup),
499
+ but no transport: carrying frames between machines is the desktop app's job. With `klypix-mcp`
500
+ alone, coordination is machine-local.
498
501
  - **Overlap matching is exact-path, and both sides must declare.** A session that never declares
499
502
  its expected files is invisible to overlap detection, and `src/auth/token.ts` does not match a
500
503
  rename or a parent directory.
@@ -502,10 +505,9 @@ Read this section before you build on any of it.
502
505
  `blocking`; the mechanism is not.
503
506
  - **Codex has no automatic capture**, with or without `--codex-hooks`. The Codex hook never writes
504
507
  the brain.
505
- - **There is no uninstall command.** Removing Klypix means hand-editing `~/.claude/settings.json`,
506
- `~/.codex/config.toml` and `~/.codex/hooks.json`, deleting `~/.claude/project-brain`, and
507
- deleting the 14 per-project files. The removal primitives exist in the source but no CLI reaches
508
- them yet.
508
+ - **Uninstall does not remove per-project files.** `npx klypix-mcp uninstall` handles the
509
+ machine-global install; the 14 files `link` wrote into each project are listed by
510
+ `npx klypix-mcp link --check` and removed by `uninstall unlink` **per project**, one at a time.
509
511
  - **Drift detection is single-host and opt-in per card.** It needs an `ev:` anchor written by the
510
512
  card's author, and it runs only in the Claude Code hook path — the MCP tools do not compute
511
513
  freshness.
@@ -517,8 +519,10 @@ Read this section before you build on any of it.
517
519
  - **A fresh `npx klypix-mcp install` gets lexical retrieval.** The optional on-device model is
518
520
  deliberately not installed.
519
521
  - **The capture lock is fail-open** past ~3.6 seconds of contention (see *Git and concurrency*).
520
- - **Tests are developer-run, not CI-gated.** The npm publish workflow runs no tests, and `test/` is
521
- not in the published tarball.
522
+ - **`test/` is not in the published tarball.** Run the suite from a clone. The publish workflow
523
+ *does* gate on it — a `gate` job runs `npm ci`, asserts the test chain is intact, runs `npm test`,
524
+ validates the version/tag, and checks the packed tarball; `publish` declares `needs: gate`, so a
525
+ red gate means npm never sees a tarball.
522
526
  - **`canvas_view`'s MCP Apps UI has never been verified on a real Apps host.**
523
527
 
524
528
  ## Numbers and methodology
@@ -542,25 +546,27 @@ independently validated.
542
546
 
543
547
  ## Uninstall
544
548
 
545
- There is no uninstall command yet. To remove Klypix by hand:
546
-
547
549
  ```bash
548
- rm -rf ~/.claude/project-brain
549
- # then remove the klypix hook entries from ~/.claude/settings.json
550
- # and the klypix MCP entry from ~/.codex/config.toml (and ~/.codex/hooks.json if you used --codex-hooks)
551
- npx klypix-mcp link --check # lists the 14 managed files in a project, so you know what to delete
550
+ npx klypix-mcp uninstall --check # full inventory — writes nothing
551
+ npx klypix-mcp uninstall # asks, then removes the machine-global install
552
+ npx klypix-mcp uninstall unlink # run inside a project: removes the files `link` wrote there
552
553
  ```
553
554
 
555
+ It strips only KLYPIX's own entries — every other hook and setting in
556
+ `~/.claude/settings.json` stays — backs up each file it edits, and **never deletes a `.klypix`**.
557
+ `--yes` skips the prompt for scripted removal.
558
+
554
559
  Your `brain.klypix` is yours — it is a plain ZIP and stays readable with or without this package.
555
560
 
556
561
  ## Contributing
557
562
 
558
563
  Issues and pull requests: [github.com/dahshanlabs/klypix-mcp](https://github.com/dahshanlabs/klypix-mcp).
559
564
 
560
- The repository carries 28 test files covering the presence lane, Context Gateway, supervisor
561
- hot-swap, auto-update, retrieval quality, decay, challenge, lenses and conformance. Run them with
562
- `npm test` from a clone they are not in the published tarball and the publish workflow does not
563
- run them. There is a known intermittent Windows `EPERM` flake on rename in
565
+ The repository carries 38 test files, 34 of them in the `npm test` chain, covering the presence
566
+ lane and its cross-machine relay, the Context Gateway, supervisor hot-swap, auto-update, retrieval
567
+ quality, decay, challenge, lenses, the format guard, the git tools (including a real `git merge`
568
+ through the merge driver), uninstall, and conformance. Run them with `npm test` from a clone — they
569
+ are not in the published tarball, though the publish workflow does run them as a gate. There is a known intermittent Windows `EPERM` flake on rename in
564
570
  `test/mcp-supervisor.mjs`.
565
571
 
566
572
  ## Why this exists
@@ -19,7 +19,7 @@ const PKG_VERSION = (() => {
19
19
  }
20
20
  })();
21
21
 
22
- const DIRECT = new Set(['install', 'link', 'doctor', 'conformance', 'garden-code', 'init', 'git-driver', 'diff', 'pr-brief']);
22
+ const DIRECT = new Set(['install', 'link', 'doctor', 'conformance', 'garden-code', 'init', 'git-driver', 'diff', 'pr-brief', 'uninstall']);
23
23
 
24
24
  const USAGE = [
25
25
  `klypix-mcp ${PKG_VERSION} — shared project brain + MCP coordination server.`,
@@ -31,12 +31,12 @@ const USAGE = [
31
31
  ' conformance [--json] launch two real MCP clients against this build',
32
32
  ' init seed a starter ./brain.klypix + print an MCP config',
33
33
  ' garden-code [brain] print the human approval code for brain_garden',
34
+ ' uninstall [--check|--yes|unlink] remove this install from the machine (--check inventories first; never deletes a .klypix)',
34
35
  ' git-driver [install|status] [repo] register the lossless .klypix merge driver for a repo (zero-command teams)',
35
36
  ' diff [ref] [--brain <path>] readable brain diff vs a git ref (default HEAD) — markdown to stdout',
36
37
  ' pr-brief [baseRef] [--brain <path>] brain decisions touching the files changed since baseRef — PR-comment markdown',
37
38
  '',
38
39
  'With no verb (or any --flag, e.g. --vault <dir>) it runs as an MCP stdio server.',
39
- 'There is no uninstall command — removal is manual (see README).',
40
40
  ].join('\n');
41
41
 
42
42
  const verb = process.argv[2];
@@ -110,6 +110,13 @@ await runVerb('git-driver', './klypix-git-driver.mjs');
110
110
  await runVerb('diff', './klypix-diff.mjs');
111
111
  await runVerb('pr-brief', './klypix-pr-brief.mjs');
112
112
 
113
+ // `npx klypix-mcp uninstall` — the machine-global removal tool. `--check` prints a full
114
+ // inventory and writes nothing; every write is backed up; a `.klypix` brain is never
115
+ // touched. Wired into the dispatcher 2026-08-01: it shipped as a bin-only verb, so
116
+ // `npx klypix-mcp uninstall` answered "unknown command" while the README (and this
117
+ // CLI's own --help) said no uninstall existed at all.
118
+ await runVerb('uninstall', './klypix-uninstall.mjs');
119
+
113
120
  // `npx klypix-mcp garden-code` — the HUMAN half of the garden approval gate.
114
121
  // brain_garden's apply requires an 8-char code derived from the exact dormant
115
122
  // candidate set + day; the agent is deliberately never shown it. The human runs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klypix-mcp",
3
- "version": "1.49.1",
3
+ "version": "1.49.2",
4
4
  "description": "Shared project brain and MCP coordination server for multi-agent coding.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -126,12 +126,27 @@ export async function parseKlypix(buffer) {
126
126
  // (merge, arrange, capture) a structure it does not understand. The merge
127
127
  // driver inherits this automatically: the throw exits it non-zero, which
128
128
  // degrades to a normal manual git conflict.
129
+ // Both dimensions, or the guard has a hole: `version` is the CONTAINER shape and
130
+ // `schemaVersion` is the DOCUMENT (item/connection) shape, and they move
131
+ // independently. The desktop codec already refused a future value of either
132
+ // (klypixFormatV4.ts assertManifestReadable); checking only `version` here left
133
+ // {version:4, schemaVersion:5} parsed by this engine and refused by the app —
134
+ // the asymmetric case, where merge/git-driver/capture would happily write back a
135
+ // document they did not understand. Found by the 2026-08-01 doc audit.
129
136
  const KLYPIX_FORMAT_CEILING = 4;
130
- if (manifest && manifest.format === 'klypix' && Number(manifest.version) > KLYPIX_FORMAT_CEILING) {
131
- throw new Error(
132
- `This .klypix was saved by a newer format (v${manifest.version}); this engine reads up to v${KLYPIX_FORMAT_CEILING}. ` +
133
- 'Update KLYPIX / klypix-mcp instead of parsing it — a blind read could damage it.'
137
+ if (manifest && manifest.format === 'klypix') {
138
+ const layout = Number(manifest.version);
139
+ const schema = Number(manifest.schemaVersion);
140
+ const tooNew = Math.max(
141
+ Number.isFinite(layout) ? layout : 0,
142
+ Number.isFinite(schema) ? schema : 0,
134
143
  );
144
+ if (tooNew > KLYPIX_FORMAT_CEILING) {
145
+ throw new Error(
146
+ `This .klypix was saved by a newer format (v${tooNew}); this engine reads up to v${KLYPIX_FORMAT_CEILING}. ` +
147
+ 'Update KLYPIX / klypix-mcp instead of parsing it — a blind read could damage it.'
148
+ );
149
+ }
135
150
  }
136
151
  const canvas = JSON.parse(canvasRaw);
137
152
  // v4 manifests are {format:"klypix", version:4}; positions presence is the