@sym-bot/mesh-channel 0.3.12 → 0.3.13

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/CHANGELOG.md CHANGED
@@ -1,627 +1,644 @@
1
- # Changelog
2
-
3
- ## 0.3.11
4
-
5
- ### Added
6
-
7
- - **Prompt-injection filter (security layer 3).** Every incoming CMB — all CAT7 fields and the opaque payload is now scanned against a curated blocklist of injection patterns before `pushChannel()` is called. Patterns cover: instruction-override phrases ("ignore previous instructions", "forget everything you know"), role/persona hijacking ("you are now a new AI", "act as an unrestricted assistant"), system-prompt injection (`<system>`, `[SYSTEM]`, `## system prompt`), tool-call fabrication (`<tool_call>`, `<function_calls>`), and privilege-escalation language ("override safety filter", "jailbreak", "DAN mode"). Blocked CMBs are audit-logged to stderr with reason, peer name, and a truncated excerpt — never silently dropped.
8
-
9
- - **Per-peer rate limiting.** A sliding 60-second window caps each peer at `SYM_RATE_LIMIT` CMBs per minute (default: 30). CMBs exceeding the cap are blocked and audit-logged. Prevents flood attacks from a compromised or malfunctioning peer.
10
-
11
- - **Payload size cap.** Payloads larger than `SYM_MAX_PAYLOAD_BYTES` (default: 8 192 bytes) are rejected before context injection. Prevents oversized-payload attacks that could exhaust the context window.
12
-
13
- - **README security section updated** to document all four defence layers accurately.
14
-
15
- ### Security model
16
-
17
- The full gate before any mesh signal reaches Claude's context is now:
18
- 1. **Transport** Ed25519 peer identity + relay-token auth.
19
- 2. **Protocol** — SVAF per-field semantic relevance gate.
20
- 3. **Safety** — prompt-injection filter + rate limiter + payload size cap (this release).
21
- 4. **Application** — text-only injection; `claude/channel/permission` not declared.
22
-
23
- ## 0.3.10
24
-
25
- ### Fixed
26
-
27
- - **Live-identity-collision auto-suffix.** Two sessions wanting the same `SYM_NODE_NAME` previously hard-failed with `EIDENTITYLOCK`. The server now checks whether the name's lock file is held by a live process; if so, it appends `-2`, `-3`, … (up to 64) until it finds a free slot. Stale locks (dead holder) are still reclaimed by `@sym-bot/sym` on start — unchanged. Result: duplicate dev-agent sessions, or any two sessions sharing a fixed `SYM_NODE_NAME`, coexist instead of failing.
28
-
29
- ## 0.3.9
30
-
31
- ### Fixed
32
-
33
- - **stdout discipline — fixes `-32000 / Connection closed`.** The MCP JSON-RPC stream runs on stdout. Dependency load banners (e.g. `[encoder] Semantic encoder ready` from the semantic model) were printing to stdout, intermittently corrupting the handshake and causing Claude Code to log "Ignoring non-JSON line on stdout" or drop the connection with `-32000`. A stdout guard is now installed before any `require()`: lines that start with `{` (JSON-RPC frames) pass through to the real stdout; everything else is redirected to stderr. Verified: stdout is pure JSON after the fix.
34
-
35
- ## 0.3.8
36
-
37
- ### Added
38
-
39
- - **Per-session node identity.** Each Claude Code session now gets its own mesh identity derived from the working-directory slug and a session-unique suffix (e.g. `claude-symday-webapp-6e174e`), instead of all sessions sharing the machine hostname. Enables multiple Claude Code sessions on the same machine to appear as distinct peers on the mesh — confirmed working over loopback via Bonjour with no relay.
40
-
41
- - **`npx` launch path.** The plugin now launches via `npx @sym-bot/mesh-channel` rather than a global `node` path, so marketplace installs work without a prior `npm install -g`. The npx cache warms on first launch; subsequent sessions start in ~1 s.
42
-
43
- ## 0.3.7
44
-
45
- ### Changed
46
-
47
- - **Bumped `@sym-bot/sym` dependency `^0.5.8` → `^0.7.4`** to track the current sym stack. The range had drifted: sym moved through 0.6.x/0.7.x (mesh groups, Windows portability) while this wrapper still declared `^0.5.8`, so an installed sym ≥0.6 showed as `invalid` and a reinstall could nest a stale 0.5.x that shadows the global. Pinning `^0.7.4` makes the dependency honest and, in particular, **requires the loopback-capable sym (≥0.7.4)** — co-resident nodes mesh over `127.0.0.1` with no network interface (Wi-Fi off). No code change in this package; dependency-range correctness only.
48
-
49
- ## 0.3.6
50
-
51
- ### Added
52
-
53
- - **Group discovery beacon.** This MCP node now advertises its mesh group on a shared `_symgroups._tcp` service (group name in TXT) via the pure-JS `bonjour-service` — published on start, re-published on `sym_join_group` hot-swap, torn down on shutdown. Makes the Claude/MCP node discoverable by the `sym` CLI's `sym groups` command **cross-platform, including Windows** (where Apple's `dns-sd` is absent), so CLI-daemon and Claude/MCP nodes list together. Discovery-only — comms stay isolated on the group's own `_<group>._tcp`. `bonjour-service` pinned as a direct dependency. Validated on Windows 11.
54
- - **Operational note:** a session started before 0.3.6 must restart to begin beaconing.
55
-
56
- ## 0.3.5
57
-
58
- ### Added
59
-
60
- - **Opaque payload on `sym_send` / `sym_observe`.** Both tools accept
61
- an optional `payload` argument carrying data beyond CAT7 — any
62
- JSON-serializable value. Forwarded to `SymNode.remember(fields, {
63
- payload, … })` (requires `@sym-bot/sym` ≥ 0.5.8) and rides the wire
64
- frame to peers. Used by substrate-level protocols that need to carry
65
- structured data alongside CAT7 (e.g. LLM request/response, where the
66
- prompt + request_id ride in `payload` rather than getting smuggled
67
- through `motivation`).
68
- - **Channel notifications surface payload-bearing CMBs.** When an
69
- incoming peer CMB carries `cmb.payload`, the header gains a
70
- `[+payload Nb]` indicator and the body stored by `sym_fetch`
71
- includes a `---PAYLOAD---` section with the serialized payload.
72
- Receivers learn from the header that there's structured data beyond
73
- CAT7 and call `sym_fetch` to consume it.
74
- - Base MCP instructions now teach agents to recognise the
75
- `[+payload Nb]` header and to pass structured responses via the
76
- `payload` argument when emitting substrate-level CMBs.
77
-
78
- ### Compatibility
79
-
80
- - Omitting `payload` produces a v0.3.4-shaped CAT7 CMB byte-for-byte.
81
- - Old peers (without `cmb.payload`) surface unchanged headers no
82
- `[+payload …]` indicator, no PAYLOAD section in the body.
83
-
84
- ## 0.3.4
85
-
86
- ### Added
87
-
88
- - **`SYM_GROUP` is now first-class in the installer.** `init` accepts a
89
- `--group <name>` flag and reads the `SYM_GROUP` env var; both paths
90
- persist the chosen group into the `~/.claude.json` (or project
91
- `.mcp.json`) env block so every Claude Code launch auto-joins the
92
- named group instead of the global `_sym._tcp` mesh.
93
-
94
- Resolution order is `--force`-aware:
95
- - With `--force` and an explicit `--group`/`SYM_GROUP`: flag/env wins
96
- (one-command group switch on a live entry).
97
- - Without `--force`, or with `--force` but no explicit value:
98
- preserved value from any existing entry > explicit > none (omit).
99
-
100
- `--force --group default` (or `SYM_GROUP=default`) is the explicit
101
- escape hatch to revert a node from a named group back to the global
102
- mesh — removes `SYM_GROUP` from the env block entirely rather than
103
- writing the literal string "default".
104
-
105
- Both `--group` and `SYM_GROUP` env values are validated against the
106
- same kebab-case regex; malformed values exit with a clear error
107
- before any file write.
108
-
109
- - **`doctor` now reports the persisted group per entry** and warns when
110
- user-global and project-scoped entries disagree on `SYM_GROUP`.
111
- Group-mismatch is the most common cause of "peers never appear in
112
- `sym_peers`" with no other failure signal surfacing it inline saves
113
- the diagnostic walk that motivated this release.
114
-
115
- - **README** gains a "Persisting your group across restarts" subsection
116
- under Team mesh groups, plus a troubleshooting entry covering the
117
- group-mismatch failure mode. Quick-start shows the `--group` flag.
118
-
119
- ### Fixed
120
-
121
- - **Stale-entry heal preserves `SYM_GROUP` alongside `SYM_NODE_NAME`.**
122
- Previously, healing a stale `claude-sym-mesh` entry (args[0] points at
123
- a missing server.js) silently dropped any persisted `SYM_GROUP`,
124
- reverting the node to the default mesh on next launch and stranding
125
- teammates who stayed in the named group. The heal path now copies
126
- both fields from the prior entry into the rewrite.
127
-
128
- Same fix applied to project-scoped entry healing under
129
- `claudeJson.projects[<path>].mcpServers`.
130
-
131
- ### Why this matters
132
-
133
- Before 0.3.4, the only way to persist a group was to hand-edit
134
- `~/.claude.json`. The README pitched `sym_join_group` as the team-mesh
135
- UX, but that tool is runtime-only — the next Claude Code launch reverted
136
- the node to the default mesh, peer count dropped to zero, and the user
137
- saw no diagnostic signal. The 2026-05-02 SYM.BOT incident (CMO in
138
- `default`, COO in `sym-bot-team`, ~24h of silent duplex outage) traced
139
- directly to this gap.
140
-
141
- ## 0.3.3
142
-
143
- ### Fixed
144
-
145
- - **Real-time duplex for CAT7 CMBs.** The `cmb-accepted` handler now
146
- stores the rendered CMB body under an `[mNNN]` ID and includes that
147
- ID in the channel notification, matching the contract stated in the
148
- MCP instructions ("Messages arrive as compact headers with [mNNN] IDs
149
- — use sym_fetch to read the full content") and the behaviour of the
150
- raw-text `message` path.
151
-
152
- Previously only the legacy raw-text `message` event persisted bodies
153
- to `MESSAGE_STORE` the primary `cmb-accepted` event (fired for
154
- every structured CMB delivered via `sym_send` / `sym_observe`) pushed
155
- a headline with no `[mNNN]` and left no retrievable body. Inbound
156
- CMBs were admitted to the SVAF-backed memory store and surfaced by
157
- `sym_recall` as compact headlines, but `sym_fetch` could not return
158
- their content — the duplex was effectively headline-only for the 99%
159
- case of real mesh traffic.
160
-
161
- Symptom: after the 0.3.2 Mac↔Win fix restored bidirectional packet
162
- flow, peers' structured replies appeared in `sym_recall` but returned
163
- *"expired or invalid ID"* from `sym_fetch` because `storeMessage()`
164
- had never been called for them. Now both the raw-text and CAT7 paths
165
- persist bodies identically.
166
-
167
- ## 0.3.2
168
-
169
- ### Fixed
170
-
171
- - **Pulls in `@sym-bot/sym` 0.5.1** fixes Mac↔Windows peer connections
172
- over LAN. Prior releases shipped a Bonjour advertisement whose SRV
173
- target was the bare Windows NetBIOS hostname (e.g. `xmesh-hp.`) with
174
- no `.local` suffix. macOS mDNSResponder only resolves `.local.` mDNS
175
- names, so Macs could discover Windows peers via bonjour browse but
176
- failed to open the outbound TCP connection. CMBs targeted at Windows
177
- nodes never arrived; no replies came back. Full diagnosis in sym
178
- 0.5.1 CHANGELOG.
179
-
180
- Upgrade required on both sides to restore Mac↔Windows traffic.
181
- Existing Windows identities with a bare hostname are auto-migrated
182
- on next node start; no manual config edit needed.
183
-
184
- ## 0.3.1
185
-
186
- ### Fixed
187
-
188
- - **Installer no longer silently ships a broken MCP config.** Previously,
189
- if `~/.claude.json` already contained a `claude-sym-mesh` entry,
190
- `npm install -g @sym-bot/mesh-channel` (via postinstall) and
191
- `npx @sym-bot/mesh-channel init` both skipped with "already configured"
192
- even when the entry's `args[0]` server.js path no longer existed on
193
- disk (common after moving or reinstalling the repo). Users saw
194
- `/mcp` report "Failed to reconnect" with no diagnostic hint.
195
-
196
- The installer now classifies entries whose `args[0]` is missing as
197
- **stale** and rewrites them automatically without `--force`, preserving
198
- `SYM_NODE_NAME` from the prior entry so mesh identity doesn't drift
199
- back to the hostname-based default. Live entries continue to require
200
- `--force` for overwrite.
201
-
202
- - **Stale project-scoped entries are now healed too.** `~/.claude.json`
203
- can carry per-project `mcpServers` overrides under
204
- `projects.<dir>.mcpServers`, and Claude Code prefers those over the
205
- user-global entry when launched from that directory. A healthy
206
- user-global entry was therefore being silently shadowed by stale
207
- project entries. `init` now scans every project, rewrites any stale
208
- `claude-sym-mesh` entry, and preserves each project's `SYM_NODE_NAME`.
209
-
210
- ### Added
211
-
212
- - **`sym-mesh-channel doctor` subcommand.** Read-only diagnostic that
213
- lists every `claude-sym-mesh` entry in `~/.claude.json` (user-global
214
- and every project scope) with `[live]` or `[STALE]` plus its
215
- `SYM_NODE_NAME` and configured path. Point users here when `/mcp`
216
- reports "Failed to reconnect". No writes, safe to run any time.
217
-
218
- - **README troubleshooting section** covering the `/mcp` failure path,
219
- how to run `doctor`, and when restart is needed after a config change.
220
-
221
- ### Changed
222
-
223
- - `.claude-plugin/plugin.json` version field bumped to `0.3.1` to match
224
- `package.json`. Previous drift (`plugin.json` stuck at `0.2.0`, package
225
- at `0.3.0`) was caught by the in-repo version-parity test.
226
-
227
- ## 0.3.0
228
-
229
- ### Added
230
-
231
- - **Startup remix-memory primer automates agent memory recall on
232
- session/agent restart (MMP §4.2 O2, rejoin-without-replay).** As the
233
- final step of plugin initialisation (after `node.start()` and before
234
- the MCP transport connects), the plugin calls
235
- `node.buildStartupPrimer()` and appends the returned text to the MCP
236
- server's `instructions` field. A fresh Claude Code session wakes
237
- with the agent's own remix memory — own observations plus peer
238
- observations admitted by SVAF — already loaded into context. No
239
- first-turn `sym_recall` required; agent acts from prior state
240
- immediately.
241
-
242
- Default caps: last 24 hours OR 20 most recent CMBs, whichever is
243
- tighter. The primer lists each entry as `[timestamp] source · key —
244
- focus` and surfaces a dropped-count line when caps elide older
245
- entries. Empty store is a silent no-op.
246
-
247
- ### Changed
248
-
249
- - **`@sym-bot/sym` dep bumped to `^0.5.0`** to pick up the
250
- `buildStartupPrimer` helper and to keep every plugin on the
251
- sym.day platform pinned to the same substrate SDK version
252
- (no drift across mesh-channel / melotune-plugin / future
253
- specialised plugins).
254
-
255
- ## 0.2.0
256
-
257
- ### Breaking
258
-
259
- - **`sym_send` tool signature change.** `sym_send` now emits a structured
260
- CAT7 CMB (MMP §4.2) instead of a raw-text `type:'message'` frame, and
261
- accepts an optional `to` parameter for targeted single-peer delivery
262
- per MMP §4.4.4.
263
-
264
- Old signature: `sym_send(message: string)`
265
- New signature: `sym_send(focus: string (required), issue?, intent?,
266
- motivation?, commitment?, perspective?, mood?, to?)`
267
-
268
- Migration: agents that previously called `sym_send({message: "..."})`
269
- should now pass the CAT7 fields explicitly, with `focus` carrying the
270
- task anchor for the send. Prior ephemeral text-broadcast behaviour is
271
- no longer exposed at the tool surface — `sym_send` and `sym_observe`
272
- both emit CMBs now, receivers run SVAF per §9.2, and admitted CMBs are
273
- remix-stored with lineage. The low-level `node.send(text)` SDK API is
274
- unchanged but no longer surfaced as a tool.
275
-
276
- ### Added
277
-
278
- - **Targeted CMB send.** `sym_send` resolves `to` against connected
279
- peers by full nodeId first, then display name, then 8-char prefix.
280
- Ambiguous matches return an error asking for the full nodeId; a
281
- disconnected target returns an error and suggests `sym_peers`.
282
- - **Tool descriptions** for `sym_send` and `sym_observe` now explicitly
283
- call out the SVAF receive path and lineage semantics, and the MCP
284
- server's `instructions` string reflects the new division of labour.
285
- - **`@sym-bot/sym` dependency bumped to `^0.3.81`** for
286
- `remember(fields, {to})` targeted variant and `peers().peerId`.
287
-
288
- ## 0.1.23
289
-
290
- ### Added
291
-
292
- - **`sym_join_group(group, relay_url?, relay_token?)`** — hot-swap this
293
- node into a different mesh group at runtime, no Claude Code restart.
294
- Stops the current SymNode, reconstructs it on the new service type
295
- (and optional relay), re-registers event handlers, restarts. The
296
- "smooth way to join" that was missing in 0.1.22.
297
-
298
- - **`sym_invite_create(group, relay_url?, relay_token?)`** generate
299
- a shareable invite URL for a named group. Two flavors:
300
- - LAN-only: `sym://group/{name}` (Bonjour isolation only)
301
- - Cross-network: `sym://team/{name}?relay=...&token=...` (routes via
302
- a WebSocket relay so teammates on different networks can join).
303
- Validates kebab-case group names, rejects token without URL.
304
-
305
- - **`sym_invite_info(url)`** extended to parse the new `sym://team/`
306
- path and the `relay=` + `token=` query-string parameters.
307
- Output now includes a ready-to-paste `sym_join_group` call as JSON.
308
-
309
- - **`sym_groups_discover()`** — enumerate SYM-mesh groups currently
310
- advertising on the local LAN via Bonjour / mDNS. Shell-outs to
311
- `dns-sd` (macOS/Windows) or `avahi-browse` (Linux) with a 2-second
312
- timeout, filters to service types matching the SYM protocol family
313
- (global `_sym._tcp`, named groups, `{app}-{id}` rooms). Peer-to-peer
314
- means only groups with live members right now are visible — no
315
- central directory.
316
-
317
- - **README — "Dev-team groups" walkthrough** with two concrete scenarios:
318
- LAN dev-team group (single office) and cross-network team group via
319
- the public `wss://sym-relay.onrender.com` relay. Shows exact tool
320
- calls from both the team lead and each teammate.
321
-
322
- - **13 new tests** covering invite URL parse, generate, round-trip, and
323
- validation (kebab-case, token-requires-URL guard). Test suite now at
324
- 35 tests total.
325
-
326
- ### Changed
327
-
328
- - Module-level `node`, `GROUP`, `SERVICE_TYPE`, `RELAY_URL`,
329
- `RELAY_TOKEN` declared as `let` (was `const`) so the hot-swap path
330
- can re-bind them. All node event handlers (`identity-collision`,
331
- `cmb-accepted`, `message`) extracted into a single
332
- `registerNodeHandlers(n)` function so the hot-swap path re-attaches
333
- them without duplicating logic.
334
-
335
- - Tool count in README corrected to 11 (was 8 in 0.1.22):
336
- + sym_invite_create, sym_join_group, sym_groups_discover.
337
-
338
- ## 0.1.22
339
-
340
- ### Added
341
-
342
- - **Plugin marketplace distribution**: `.claude-plugin/marketplace.json`
343
- enables direct install via the Claude Code plugin marketplace without
344
- waiting on the Anthropic Plugin Directory propagation pipeline:
345
-
346
- ```
347
- /plugin marketplace add sym-bot/sym-mesh-channel
348
- /plugin install sym-mesh-channel@sym-mesh-channel
349
- ```
350
-
351
- Validates cleanly with `claude plugin validate .` and installs
352
- end-to-end with no manual steps.
353
-
354
- - **`LICENSE`** file (Apache-2.0). `package.json` already declared
355
- Apache-2.0 but no LICENSE text was present in the repo; this
356
- aligns the distribution with SPDX expectations.
357
-
358
- - **MMP §5.8 mesh-group support** — LAN isolation via Bonjour service
359
- type so Claude Code sessions can join app-specific meshes (e.g.
360
- MeloTune mood rooms on `_melotune._tcp`) instead of the global
361
- `_sym._tcp` mesh. Enables cross-app CMB delivery without cross-app
362
- noise: nodes in different groups never discover each other at mDNS.
363
-
364
- Config surface (two equivalent paths):
365
- - `SYM_GROUP=<name>` → service type `_<name>._tcp`
366
- - `SYM_SERVICE_TYPE=<st>` → explicit override (`_foo._tcp` form)
367
-
368
- Default remains `_sym._tcp` / `group=default` backward compatible.
369
-
370
- - **Two new MCP tools for mesh-group operations**:
371
- - `sym_group_info` reports current group + service type + peer
372
- roster scoped to this group.
373
- - `sym_invite_info` parses app-specific invite URLs
374
- (`melotune://room/{id}/{name}`, `sym://group/{name}`) into service
375
- type + group + room name. Read-only inspection; caller opens a
376
- new session/env to join.
377
-
378
- `sym_status` output now includes `Group` + service type.
379
-
380
- ### Fixed
381
-
382
- - **`plugin.json` validation failure on install.** The three
383
- `channels[0].userConfig` entries (`relay_url`, `relay_token`,
384
- `allowed_peers`) were missing the required `type` and `title`
385
- fields per the Claude Code plugin schema. Install failed with:
386
-
387
- ```
388
- channels.0.userConfig.relay_url.type: Invalid option
389
- channels.0.userConfig.relay_url.title: expected string, received undefined
390
- ```
391
-
392
- Added `type: "string"` and a human-readable `title` to all three.
393
- Likely one of the root causes of the 10 Apr 2026 submission
394
- showing "Published" on the Anthropic submissions portal but not
395
- propagating to the public `claude-plugins-official` marketplace.
396
-
397
- ### Changed
398
-
399
- - **README**: self-hosted plugin-marketplace install path promoted to
400
- the primary install recommendation (works today, independent of
401
- Anthropic directory propagation). npm path kept as alternative.
402
- Tool table updated 5 8 entries to reflect the current surface.
403
- Clarified that plugin-directory approval and Channels-allowlist
404
- inclusion are independent gates — the MCP tools work without the
405
- `--dangerously-load-development-channels` flag; the flag is only
406
- needed for the `<channel>` async-push behaviour.
407
-
408
- - Pairs with `@sym-bot/sym` ≥ 0.3.78 which added the
409
- `discoveryServiceType` and `group` constructor params consumed by
410
- the mesh-group tools.
411
-
412
- ## 0.1.21
413
-
414
- ### Changed
415
-
416
- - **README: accurate `sym_status` / `sym_peers` example output.** The
417
- Quick Start sample output was a stylized one-line compression; the
418
- real output is multi-line with additional fields (nodeId suffix,
419
- Relay, Memories, one peer per line). Updated so users see in the
420
- README exactly what their terminal will show. Doc-only — no code
421
- changes.
422
-
423
- ## 0.1.20
424
-
425
- ### Added
426
-
427
- - **`sym-mesh-channel init --project`** — new flag to install the MCP
428
- server at project scope (`<cwd>/.mcp.json` + merged
429
- `<cwd>/.claude/settings.local.json`) instead of global
430
- `~/.claude.json`. Enables multi-identity-per-machine workflows where
431
- several Claude Code sessions run in parallel from distinct project
432
- directories and each appears as its own peer on the mesh. Project
433
- `.mcp.json` entries override the global `mcpServers` entry when
434
- Claude Code launches from that directory, so `SYM_NODE_NAME` can
435
- differ per project without siblings stepping on each other.
436
- - Project mode supports the same `--force` semantics as global install:
437
- backs up existing `.mcp.json` and `settings.local.json` next to
438
- themselves (`*.bak-<timestamp>`), merges `settings.local.json` so
439
- unrelated keys (permissions, custom settings) are preserved, atomic
440
- writes via tmp+rename, refuses to overwrite an existing
441
- `claude-sym-mesh` entry without `--force`.
442
- - `--postinstall` always runs global install regardless of `--project`
443
- (npm postinstall runs from npm's staging dir, not the user's
444
- project). Keeps `npm install -g` auto-configure behavior unchanged.
445
- - **5 new tests** covering project-mode install: writes `.mcp.json`
446
- and `settings.local.json`, merge preserves existing keys, refusal
447
- path exits 2, `--force` overwrite creates backup, postinstall
448
- fallback ignores `--project`. Test suite now 22 tests total.
449
-
450
- ### Why
451
-
452
- Default mode (single mesh identity per machine, global install) is
453
- correct for most users and unchanged. `--project` exists for the
454
- small but real set of users who run multiple Claude Code sessions
455
- in parallel from distinct project directories and want each session
456
- to show up as its own peer on the mesh. Previously this workflow
457
- required hand-editing `.mcp.json` and `.claude/settings.local.json`
458
- per project; now it's one command per project.
459
-
460
- ## 0.1.19
461
-
462
- ### Added
463
-
464
- - **Claude Code plugin manifest** for Anthropic Channels allowlist
465
- submission. `.claude-plugin/plugin.json` + `.mcp.json` following the
466
- official single-repo pattern (Telegram/Discord). Submitted to
467
- Anthropic Plugin Directory 10 Apr 2026.
468
- - **`SYM_ALLOWED_PEERS`** — optional peer allowlist (defense-in-depth).
469
- Comma-separated node names; only listed peers can push to Claude's
470
- context. Empty = accept all authenticated peers. SVAF still gates on
471
- content relevance regardless.
472
- - **`SECURITY.md`** 3-layer defense model documentation (transport
473
- auth + SVAF content gate + peer allowlist) for Anthropic review.
474
- - **17 plugin tests** covering manifest validation, security checks
475
- (no permission relay, no code execution, self-echo filtering, peer
476
- allowlist), and lifecycle (shutdown handlers, identity collision).
477
-
478
- ## 0.1.18
479
-
480
- ### Changed
481
-
482
- - **Auto-configure on install.** `npm install -g` now runs `postinstall`
483
- that writes the MCP server config to global `mcpServers` in
484
- `~/.claude.json` automatically. No separate `sym-mesh-channel init`
485
- step neededtwo commands to mesh: install + launch.
486
- - **Global MCP config** server entry is now written to top-level
487
- `mcpServers` (available in all Claude Code sessions), not
488
- project-scoped.
489
- - **Windows postinstall fixes** `require.resolve` for server.js path
490
- (handles npm staging directory on Windows), EBUSY handling when
491
- Claude Code has `~/.claude.json` locked, graceful skip if Claude
492
- Code not yet installed.
493
- - **README repositioned** lead with capability ("first non-Anthropic
494
- Claude Code Channels implementation"), not use case. Simplified
495
- Quick Start to two commands.
496
- - **0 vulnerabilities** — fresh dependency rebuild resolves all 6
497
- moderate hono/node-server advisories.
498
- - Windows mDNS: built-in on Windows 10+, no Bonjour install needed.
499
-
500
- ## 0.1.7
501
-
502
- ### Added
503
-
504
- - **`npx @sym-bot/mesh-channel init`** interactive installer that
505
- writes `~/.claude.json` for the current project, picks a sensible
506
- default `SYM_NODE_NAME` (`claude-mac` / `claude-win` / `claude-linux`),
507
- resolves the absolute path to `server.js`, and prints the launch
508
- command including the `--dangerously-load-development-channels` flag.
509
- Backs up the existing config to `~/.claude.json.bak-<timestamp>`,
510
- validates JSON round-trip, atomic write via tmp+rename. Refuses to
511
- overwrite an existing entry without `--force`.
512
- - **README rewritten for LAN-first install.** Quick start is two
513
- minutes: install, init, launch. No relay required. Bonjour/mDNS
514
- is the default discovery path. Cross-network setup (relay) is now
515
- the optional advanced section.
516
-
517
- ### Changed
518
-
519
- - `package.json` `bin` now exposes both `sym-mesh-channel` (server
520
- entrypoint) and `sym-mesh-channel-init` (installer). The package
521
- description leads with "LAN-first via Bonjour, no relay required."
522
-
523
- ### Why
524
-
525
- The 0.1.5/0.1.6 install path required users to manually edit
526
- `~/.claude.json`, know about the Channels dev flag, set up a relay,
527
- and obtain a relay token. That gated the demo behind real friction.
528
- LAN-only mode has worked since day one in the underlying SymNode
529
- (`sym/lib/node.js:509-511` only connects to the relay if `SYM_RELAY_URL`
530
- is set; Bonjour discovery starts unconditionally), but no documentation
531
- or installer surfaced it. This release closes that gap: two users on
532
- the same wifi can join the same mesh in two minutes with three commands.
533
-
534
- ## 0.1.6
535
-
536
- ### Fixed
537
-
538
- - `sym_send` no longer double-delivers. Previously called both
539
- `node.send()` (broadcast as `event_type=message`) AND `node.remember()`
540
- (persist as CMB which gets gossiped as `event_type=cmb`), causing
541
- the same payload to arrive twice on receivers and double the
542
- context-window cost. Now broadcasts the message frame only. Hosts
543
- that want CMB persistence should call `sym_observe` separately
544
- with proper CAT7 fields.
545
- - `sym_send` now reports the actual delivered count, not
546
- `peers().length`. Requires `@sym-bot/sym >= 0.3.70` where `send()`
547
- returns the count of peer transports that successfully accepted
548
- the broadcast. The two can disagree when peers are tracked but
549
- have broken transports the delivered count is the truth about
550
- what was actually sent.
551
-
552
- ### Changed
553
-
554
- - Bumped `@sym-bot/sym` dep `^0.3.69` → `^0.3.70`. 0.3.70 ships the
555
- identity lockfile that prevents two SymNode processes from
556
- claiming the same nodeId on a host (the cliHostMode-vs-MCP
557
- collision that broke real-time push on Windows during the
558
- 2026-04-09 round-trip test).
559
-
560
- ## 0.1.5
561
-
562
- ### Changed
563
-
564
- - Bumped `@sym-bot/sym` dep `^0.3.68` `^0.3.69` (0.3.68 deprecated;
565
- same code in 0.3.69 with a cleaner published tarball).
566
- - Added `files` whitelist to `package.json` and `.npmignore` for
567
- `*.bak`, `*.swp`, `.DS_Store` so future publishes can't accidentally
568
- ship local backup files. First NPM publish of this package.
569
-
570
- ## 0.1.4
571
-
572
- ### Changed
573
-
574
- - Bumped `@sym-bot/sym` dep `^0.3.43` `^0.3.68` to pick up
575
- duplicate-identity refusal (close code 4004) and the new
576
- `identity-collision` event.
577
-
578
- ### Added
579
-
580
- - Wired `node.on('identity-collision', ...)` to `process.exit(2)` so
581
- the MCP dies cleanly when the relay reports a duplicate-identity
582
- race. Together with v0.1.3's clean shutdown, this fully resolves
583
- the host-side half of the duplicate-identity bug.
584
-
585
- ## 0.1.3
586
-
587
- ### Added
588
-
589
- - Clean shutdown handlers (SIGTERM/SIGINT/SIGHUP) that call
590
- `node.stop()` before exiting, so the SymNode disconnects from the
591
- relay before the process dies. Without this, restarts left zombie
592
- registrations on the relay until the next heartbeat tick (up to
593
- 30s), creating a duplicate-identity race window for the next MCP
594
- spawn. Idempotent re-entry guard.
595
-
596
- ## 0.1.2
597
-
598
- ### Fixed
599
-
600
- - Suppressed `peer-joined` / `peer-left` events from being pushed to
601
- Claude's context as `<channel>` notifications. Presence is high-
602
- frequency and low-signal — a relay reconnect could fire one event
603
- per peer per cycle, flooding the context window. CMBs and direct
604
- messages still flow through.
605
-
606
- ## 0.1.1
607
-
608
- ### Changed
609
-
610
- - Replaced hardcoded `claude-code` / `claude-code-mac` literals with
611
- a single `NODE_NAME` constant sourced from `process.env.SYM_NODE_NAME`
612
- (default `claude-code-mac`). Enables platform-scoped naming per
613
- MMP §3.1.2 without source edits. Fixed stale display strings in
614
- the MCP instructions, `sym_send` perspective, `sym_status` header,
615
- and the self-echo dedup filter.
616
-
617
- ## 0.1.0
618
-
619
- ### Added
620
-
621
- - Initial release. MCP server that runs a `SymNode` peer node inside
622
- a Claude Code session — own identity, own relay connection, own
623
- SVAF evaluation. Tools: `sym_send`, `sym_observe`, `sym_recall`,
624
- `sym_peers`, `sym_status`. Mesh events arrive as `<channel>`
625
- notifications when launched with
626
- `claude --dangerously-load-development-channels server:claude-sym-mesh`
627
- (allowlisted server name required by Claude Code Channels).
1
+ # Changelog
2
+
3
+ ## 0.3.13
4
+
5
+ ### Changed
6
+
7
+ - **Track the latest released `@sym-bot/sym` (`^0.7.6`).** Pulls in the SVAF decision log (every evaluation admit and reject is now persisted and emitted) on top of the 0.7.5 replay-storm receive-path dedup. Additive; no API changes in mesh-channel.
8
+
9
+ ## 0.3.12
10
+
11
+ ### Changed
12
+
13
+ - **Bump `@sym-bot/sym` to `^0.7.5`** mesh replay-storm receive-path dedup (dedup received CMBs so a co-resident peer restart no longer triggers a replay storm).
14
+
15
+ ### Fixed
16
+
17
+ - Align install commands + channel-flag handles with the actual marketplace (#13).
18
+ - Fix 5 moderate Dependabot vulnerabilities (`npm audit fix`).
19
+
20
+ ## 0.3.11
21
+
22
+ ### Added
23
+
24
+ - **Prompt-injection filter (security layer 3).** Every incoming CMB — all CAT7 fields and the opaque payload — is now scanned against a curated blocklist of injection patterns before `pushChannel()` is called. Patterns cover: instruction-override phrases ("ignore previous instructions", "forget everything you know"), role/persona hijacking ("you are now a new AI", "act as an unrestricted assistant"), system-prompt injection (`<system>`, `[SYSTEM]`, `## system prompt`), tool-call fabrication (`<tool_call>`, `<function_calls>`), and privilege-escalation language ("override safety filter", "jailbreak", "DAN mode"). Blocked CMBs are audit-logged to stderr with reason, peer name, and a truncated excerpt — never silently dropped.
25
+
26
+ - **Per-peer rate limiting.** A sliding 60-second window caps each peer at `SYM_RATE_LIMIT` CMBs per minute (default: 30). CMBs exceeding the cap are blocked and audit-logged. Prevents flood attacks from a compromised or malfunctioning peer.
27
+
28
+ - **Payload size cap.** Payloads larger than `SYM_MAX_PAYLOAD_BYTES` (default: 8 192 bytes) are rejected before context injection. Prevents oversized-payload attacks that could exhaust the context window.
29
+
30
+ - **README security section updated** to document all four defence layers accurately.
31
+
32
+ ### Security model
33
+
34
+ The full gate before any mesh signal reaches Claude's context is now:
35
+ 1. **Transport** — Ed25519 peer identity + relay-token auth.
36
+ 2. **Protocol** — SVAF per-field semantic relevance gate.
37
+ 3. **Safety** — prompt-injection filter + rate limiter + payload size cap (this release).
38
+ 4. **Application** — text-only injection; `claude/channel/permission` not declared.
39
+
40
+ ## 0.3.10
41
+
42
+ ### Fixed
43
+
44
+ - **Live-identity-collision auto-suffix.** Two sessions wanting the same `SYM_NODE_NAME` previously hard-failed with `EIDENTITYLOCK`. The server now checks whether the name's lock file is held by a live process; if so, it appends `-2`, `-3`, … (up to 64) until it finds a free slot. Stale locks (dead holder) are still reclaimed by `@sym-bot/sym` on start — unchanged. Result: duplicate dev-agent sessions, or any two sessions sharing a fixed `SYM_NODE_NAME`, coexist instead of failing.
45
+
46
+ ## 0.3.9
47
+
48
+ ### Fixed
49
+
50
+ - **stdout discipline — fixes `-32000 / Connection closed`.** The MCP JSON-RPC stream runs on stdout. Dependency load banners (e.g. `[encoder] Semantic encoder ready` from the semantic model) were printing to stdout, intermittently corrupting the handshake and causing Claude Code to log "Ignoring non-JSON line on stdout" or drop the connection with `-32000`. A stdout guard is now installed before any `require()`: lines that start with `{` (JSON-RPC frames) pass through to the real stdout; everything else is redirected to stderr. Verified: stdout is pure JSON after the fix.
51
+
52
+ ## 0.3.8
53
+
54
+ ### Added
55
+
56
+ - **Per-session node identity.** Each Claude Code session now gets its own mesh identity derived from the working-directory slug and a session-unique suffix (e.g. `claude-symday-webapp-6e174e`), instead of all sessions sharing the machine hostname. Enables multiple Claude Code sessions on the same machine to appear as distinct peers on the mesh — confirmed working over loopback via Bonjour with no relay.
57
+
58
+ - **`npx` launch path.** The plugin now launches via `npx @sym-bot/mesh-channel` rather than a global `node` path, so marketplace installs work without a prior `npm install -g`. The npx cache warms on first launch; subsequent sessions start in ~1 s.
59
+
60
+ ## 0.3.7
61
+
62
+ ### Changed
63
+
64
+ - **Bumped `@sym-bot/sym` dependency `^0.5.8` → `^0.7.4`** to track the current sym stack. The range had drifted: sym moved through 0.6.x/0.7.x (mesh groups, Windows portability) while this wrapper still declared `^0.5.8`, so an installed sym ≥0.6 showed as `invalid` and a reinstall could nest a stale 0.5.x that shadows the global. Pinning `^0.7.4` makes the dependency honest and, in particular, **requires the loopback-capable sym (≥0.7.4)** — co-resident nodes mesh over `127.0.0.1` with no network interface (Wi-Fi off). No code change in this package; dependency-range correctness only.
65
+
66
+ ## 0.3.6
67
+
68
+ ### Added
69
+
70
+ - **Group discovery beacon.** This MCP node now advertises its mesh group on a shared `_symgroups._tcp` service (group name in TXT) via the pure-JS `bonjour-service` published on start, re-published on `sym_join_group` hot-swap, torn down on shutdown. Makes the Claude/MCP node discoverable by the `sym` CLI's `sym groups` command **cross-platform, including Windows** (where Apple's `dns-sd` is absent), so CLI-daemon and Claude/MCP nodes list together. Discovery-only — comms stay isolated on the group's own `_<group>._tcp`. `bonjour-service` pinned as a direct dependency. Validated on Windows 11.
71
+ - **Operational note:** a session started before 0.3.6 must restart to begin beaconing.
72
+
73
+ ## 0.3.5
74
+
75
+ ### Added
76
+
77
+ - **Opaque payload on `sym_send` / `sym_observe`.** Both tools accept
78
+ an optional `payload` argument carrying data beyond CAT7 — any
79
+ JSON-serializable value. Forwarded to `SymNode.remember(fields, {
80
+ payload, })` (requires `@sym-bot/sym` 0.5.8) and rides the wire
81
+ frame to peers. Used by substrate-level protocols that need to carry
82
+ structured data alongside CAT7 (e.g. LLM request/response, where the
83
+ prompt + request_id ride in `payload` rather than getting smuggled
84
+ through `motivation`).
85
+ - **Channel notifications surface payload-bearing CMBs.** When an
86
+ incoming peer CMB carries `cmb.payload`, the header gains a
87
+ `[+payload Nb]` indicator and the body stored by `sym_fetch`
88
+ includes a `---PAYLOAD---` section with the serialized payload.
89
+ Receivers learn from the header that there's structured data beyond
90
+ CAT7 and call `sym_fetch` to consume it.
91
+ - Base MCP instructions now teach agents to recognise the
92
+ `[+payload Nb]` header and to pass structured responses via the
93
+ `payload` argument when emitting substrate-level CMBs.
94
+
95
+ ### Compatibility
96
+
97
+ - Omitting `payload` produces a v0.3.4-shaped CAT7 CMB byte-for-byte.
98
+ - Old peers (without `cmb.payload`) surface unchanged headers no
99
+ `[+payload …]` indicator, no PAYLOAD section in the body.
100
+
101
+ ## 0.3.4
102
+
103
+ ### Added
104
+
105
+ - **`SYM_GROUP` is now first-class in the installer.** `init` accepts a
106
+ `--group <name>` flag and reads the `SYM_GROUP` env var; both paths
107
+ persist the chosen group into the `~/.claude.json` (or project
108
+ `.mcp.json`) env block so every Claude Code launch auto-joins the
109
+ named group instead of the global `_sym._tcp` mesh.
110
+
111
+ Resolution order is `--force`-aware:
112
+ - With `--force` and an explicit `--group`/`SYM_GROUP`: flag/env wins
113
+ (one-command group switch on a live entry).
114
+ - Without `--force`, or with `--force` but no explicit value:
115
+ preserved value from any existing entry > explicit > none (omit).
116
+
117
+ `--force --group default` (or `SYM_GROUP=default`) is the explicit
118
+ escape hatch to revert a node from a named group back to the global
119
+ mesh — removes `SYM_GROUP` from the env block entirely rather than
120
+ writing the literal string "default".
121
+
122
+ Both `--group` and `SYM_GROUP` env values are validated against the
123
+ same kebab-case regex; malformed values exit with a clear error
124
+ before any file write.
125
+
126
+ - **`doctor` now reports the persisted group per entry** and warns when
127
+ user-global and project-scoped entries disagree on `SYM_GROUP`.
128
+ Group-mismatch is the most common cause of "peers never appear in
129
+ `sym_peers`" with no other failure signal — surfacing it inline saves
130
+ the diagnostic walk that motivated this release.
131
+
132
+ - **README** gains a "Persisting your group across restarts" subsection
133
+ under Team mesh groups, plus a troubleshooting entry covering the
134
+ group-mismatch failure mode. Quick-start shows the `--group` flag.
135
+
136
+ ### Fixed
137
+
138
+ - **Stale-entry heal preserves `SYM_GROUP` alongside `SYM_NODE_NAME`.**
139
+ Previously, healing a stale `claude-sym-mesh` entry (args[0] points at
140
+ a missing server.js) silently dropped any persisted `SYM_GROUP`,
141
+ reverting the node to the default mesh on next launch and stranding
142
+ teammates who stayed in the named group. The heal path now copies
143
+ both fields from the prior entry into the rewrite.
144
+
145
+ Same fix applied to project-scoped entry healing under
146
+ `claudeJson.projects[<path>].mcpServers`.
147
+
148
+ ### Why this matters
149
+
150
+ Before 0.3.4, the only way to persist a group was to hand-edit
151
+ `~/.claude.json`. The README pitched `sym_join_group` as the team-mesh
152
+ UX, but that tool is runtime-only the next Claude Code launch reverted
153
+ the node to the default mesh, peer count dropped to zero, and the user
154
+ saw no diagnostic signal. The 2026-05-02 SYM.BOT incident (CMO in
155
+ `default`, COO in `sym-bot-team`, ~24h of silent duplex outage) traced
156
+ directly to this gap.
157
+
158
+ ## 0.3.3
159
+
160
+ ### Fixed
161
+
162
+ - **Real-time duplex for CAT7 CMBs.** The `cmb-accepted` handler now
163
+ stores the rendered CMB body under an `[mNNN]` ID and includes that
164
+ ID in the channel notification, matching the contract stated in the
165
+ MCP instructions ("Messages arrive as compact headers with [mNNN] IDs
166
+ — use sym_fetch to read the full content") and the behaviour of the
167
+ raw-text `message` path.
168
+
169
+ Previously only the legacy raw-text `message` event persisted bodies
170
+ to `MESSAGE_STORE` — the primary `cmb-accepted` event (fired for
171
+ every structured CMB delivered via `sym_send` / `sym_observe`) pushed
172
+ a headline with no `[mNNN]` and left no retrievable body. Inbound
173
+ CMBs were admitted to the SVAF-backed memory store and surfaced by
174
+ `sym_recall` as compact headlines, but `sym_fetch` could not return
175
+ their content the duplex was effectively headline-only for the 99%
176
+ case of real mesh traffic.
177
+
178
+ Symptom: after the 0.3.2 Mac↔Win fix restored bidirectional packet
179
+ flow, peers' structured replies appeared in `sym_recall` but returned
180
+ *"expired or invalid ID"* from `sym_fetch` because `storeMessage()`
181
+ had never been called for them. Now both the raw-text and CAT7 paths
182
+ persist bodies identically.
183
+
184
+ ## 0.3.2
185
+
186
+ ### Fixed
187
+
188
+ - **Pulls in `@sym-bot/sym` 0.5.1** fixes Mac↔Windows peer connections
189
+ over LAN. Prior releases shipped a Bonjour advertisement whose SRV
190
+ target was the bare Windows NetBIOS hostname (e.g. `xmesh-hp.`) with
191
+ no `.local` suffix. macOS mDNSResponder only resolves `.local.` mDNS
192
+ names, so Macs could discover Windows peers via bonjour browse but
193
+ failed to open the outbound TCP connection. CMBs targeted at Windows
194
+ nodes never arrived; no replies came back. Full diagnosis in sym
195
+ 0.5.1 CHANGELOG.
196
+
197
+ Upgrade required on both sides to restore Mac↔Windows traffic.
198
+ Existing Windows identities with a bare hostname are auto-migrated
199
+ on next node start; no manual config edit needed.
200
+
201
+ ## 0.3.1
202
+
203
+ ### Fixed
204
+
205
+ - **Installer no longer silently ships a broken MCP config.** Previously,
206
+ if `~/.claude.json` already contained a `claude-sym-mesh` entry,
207
+ `npm install -g @sym-bot/mesh-channel` (via postinstall) and
208
+ `npx @sym-bot/mesh-channel init` both skipped with "already configured"
209
+ — even when the entry's `args[0]` server.js path no longer existed on
210
+ disk (common after moving or reinstalling the repo). Users saw
211
+ `/mcp` report "Failed to reconnect" with no diagnostic hint.
212
+
213
+ The installer now classifies entries whose `args[0]` is missing as
214
+ **stale** and rewrites them automatically without `--force`, preserving
215
+ `SYM_NODE_NAME` from the prior entry so mesh identity doesn't drift
216
+ back to the hostname-based default. Live entries continue to require
217
+ `--force` for overwrite.
218
+
219
+ - **Stale project-scoped entries are now healed too.** `~/.claude.json`
220
+ can carry per-project `mcpServers` overrides under
221
+ `projects.<dir>.mcpServers`, and Claude Code prefers those over the
222
+ user-global entry when launched from that directory. A healthy
223
+ user-global entry was therefore being silently shadowed by stale
224
+ project entries. `init` now scans every project, rewrites any stale
225
+ `claude-sym-mesh` entry, and preserves each project's `SYM_NODE_NAME`.
226
+
227
+ ### Added
228
+
229
+ - **`sym-mesh-channel doctor` subcommand.** Read-only diagnostic that
230
+ lists every `claude-sym-mesh` entry in `~/.claude.json` (user-global
231
+ and every project scope) with `[live]` or `[STALE]` plus its
232
+ `SYM_NODE_NAME` and configured path. Point users here when `/mcp`
233
+ reports "Failed to reconnect". No writes, safe to run any time.
234
+
235
+ - **README troubleshooting section** covering the `/mcp` failure path,
236
+ how to run `doctor`, and when restart is needed after a config change.
237
+
238
+ ### Changed
239
+
240
+ - `.claude-plugin/plugin.json` version field bumped to `0.3.1` to match
241
+ `package.json`. Previous drift (`plugin.json` stuck at `0.2.0`, package
242
+ at `0.3.0`) was caught by the in-repo version-parity test.
243
+
244
+ ## 0.3.0
245
+
246
+ ### Added
247
+
248
+ - **Startup remix-memory primer — automates agent memory recall on
249
+ session/agent restart (MMP §4.2 O2, rejoin-without-replay).** As the
250
+ final step of plugin initialisation (after `node.start()` and before
251
+ the MCP transport connects), the plugin calls
252
+ `node.buildStartupPrimer()` and appends the returned text to the MCP
253
+ server's `instructions` field. A fresh Claude Code session wakes
254
+ with the agent's own remix memory — own observations plus peer
255
+ observations admitted by SVAF — already loaded into context. No
256
+ first-turn `sym_recall` required; agent acts from prior state
257
+ immediately.
258
+
259
+ Default caps: last 24 hours OR 20 most recent CMBs, whichever is
260
+ tighter. The primer lists each entry as `[timestamp] source · key —
261
+ focus` and surfaces a dropped-count line when caps elide older
262
+ entries. Empty store is a silent no-op.
263
+
264
+ ### Changed
265
+
266
+ - **`@sym-bot/sym` dep bumped to `^0.5.0`** to pick up the
267
+ `buildStartupPrimer` helper and to keep every plugin on the
268
+ sym.day platform pinned to the same substrate SDK version
269
+ (no drift across mesh-channel / melotune-plugin / future
270
+ specialised plugins).
271
+
272
+ ## 0.2.0
273
+
274
+ ### Breaking
275
+
276
+ - **`sym_send` tool signature change.** `sym_send` now emits a structured
277
+ CAT7 CMB (MMP §4.2) instead of a raw-text `type:'message'` frame, and
278
+ accepts an optional `to` parameter for targeted single-peer delivery
279
+ per MMP §4.4.4.
280
+
281
+ Old signature: `sym_send(message: string)`
282
+ New signature: `sym_send(focus: string (required), issue?, intent?,
283
+ motivation?, commitment?, perspective?, mood?, to?)`
284
+
285
+ Migration: agents that previously called `sym_send({message: "..."})`
286
+ should now pass the CAT7 fields explicitly, with `focus` carrying the
287
+ task anchor for the send. Prior ephemeral text-broadcast behaviour is
288
+ no longer exposed at the tool surface — `sym_send` and `sym_observe`
289
+ both emit CMBs now, receivers run SVAF per §9.2, and admitted CMBs are
290
+ remix-stored with lineage. The low-level `node.send(text)` SDK API is
291
+ unchanged but no longer surfaced as a tool.
292
+
293
+ ### Added
294
+
295
+ - **Targeted CMB send.** `sym_send` resolves `to` against connected
296
+ peers by full nodeId first, then display name, then 8-char prefix.
297
+ Ambiguous matches return an error asking for the full nodeId; a
298
+ disconnected target returns an error and suggests `sym_peers`.
299
+ - **Tool descriptions** for `sym_send` and `sym_observe` now explicitly
300
+ call out the SVAF receive path and lineage semantics, and the MCP
301
+ server's `instructions` string reflects the new division of labour.
302
+ - **`@sym-bot/sym` dependency bumped to `^0.3.81`** for
303
+ `remember(fields, {to})` targeted variant and `peers().peerId`.
304
+
305
+ ## 0.1.23
306
+
307
+ ### Added
308
+
309
+ - **`sym_join_group(group, relay_url?, relay_token?)`** — hot-swap this
310
+ node into a different mesh group at runtime, no Claude Code restart.
311
+ Stops the current SymNode, reconstructs it on the new service type
312
+ (and optional relay), re-registers event handlers, restarts. The
313
+ "smooth way to join" that was missing in 0.1.22.
314
+
315
+ - **`sym_invite_create(group, relay_url?, relay_token?)`** — generate
316
+ a shareable invite URL for a named group. Two flavors:
317
+ - LAN-only: `sym://group/{name}` (Bonjour isolation only)
318
+ - Cross-network: `sym://team/{name}?relay=...&token=...` (routes via
319
+ a WebSocket relay so teammates on different networks can join).
320
+ Validates kebab-case group names, rejects token without URL.
321
+
322
+ - **`sym_invite_info(url)`** extended to parse the new `sym://team/`
323
+ path and the `relay=` + `token=` query-string parameters.
324
+ Output now includes a ready-to-paste `sym_join_group` call as JSON.
325
+
326
+ - **`sym_groups_discover()`** — enumerate SYM-mesh groups currently
327
+ advertising on the local LAN via Bonjour / mDNS. Shell-outs to
328
+ `dns-sd` (macOS/Windows) or `avahi-browse` (Linux) with a 2-second
329
+ timeout, filters to service types matching the SYM protocol family
330
+ (global `_sym._tcp`, named groups, `{app}-{id}` rooms). Peer-to-peer
331
+ means only groups with live members right now are visible — no
332
+ central directory.
333
+
334
+ - **README — "Dev-team groups" walkthrough** with two concrete scenarios:
335
+ LAN dev-team group (single office) and cross-network team group via
336
+ the public `wss://sym-relay.onrender.com` relay. Shows exact tool
337
+ calls from both the team lead and each teammate.
338
+
339
+ - **13 new tests** covering invite URL parse, generate, round-trip, and
340
+ validation (kebab-case, token-requires-URL guard). Test suite now at
341
+ 35 tests total.
342
+
343
+ ### Changed
344
+
345
+ - Module-level `node`, `GROUP`, `SERVICE_TYPE`, `RELAY_URL`,
346
+ `RELAY_TOKEN` declared as `let` (was `const`) so the hot-swap path
347
+ can re-bind them. All node event handlers (`identity-collision`,
348
+ `cmb-accepted`, `message`) extracted into a single
349
+ `registerNodeHandlers(n)` function so the hot-swap path re-attaches
350
+ them without duplicating logic.
351
+
352
+ - Tool count in README corrected to 11 (was 8 in 0.1.22):
353
+ + sym_invite_create, sym_join_group, sym_groups_discover.
354
+
355
+ ## 0.1.22
356
+
357
+ ### Added
358
+
359
+ - **Plugin marketplace distribution**: `.claude-plugin/marketplace.json`
360
+ enables direct install via the Claude Code plugin marketplace without
361
+ waiting on the Anthropic Plugin Directory propagation pipeline:
362
+
363
+ ```
364
+ /plugin marketplace add sym-bot/sym-mesh-channel
365
+ /plugin install sym-mesh-channel@sym-mesh-channel
366
+ ```
367
+
368
+ Validates cleanly with `claude plugin validate .` and installs
369
+ end-to-end with no manual steps.
370
+
371
+ - **`LICENSE`** file (Apache-2.0). `package.json` already declared
372
+ Apache-2.0 but no LICENSE text was present in the repo; this
373
+ aligns the distribution with SPDX expectations.
374
+
375
+ - **MMP §5.8 mesh-group support** LAN isolation via Bonjour service
376
+ type so Claude Code sessions can join app-specific meshes (e.g.
377
+ MeloTune mood rooms on `_melotune._tcp`) instead of the global
378
+ `_sym._tcp` mesh. Enables cross-app CMB delivery without cross-app
379
+ noise: nodes in different groups never discover each other at mDNS.
380
+
381
+ Config surface (two equivalent paths):
382
+ - `SYM_GROUP=<name>` → service type `_<name>._tcp`
383
+ - `SYM_SERVICE_TYPE=<st>` → explicit override (`_foo._tcp` form)
384
+
385
+ Default remains `_sym._tcp` / `group=default` backward compatible.
386
+
387
+ - **Two new MCP tools for mesh-group operations**:
388
+ - `sym_group_info` — reports current group + service type + peer
389
+ roster scoped to this group.
390
+ - `sym_invite_info` — parses app-specific invite URLs
391
+ (`melotune://room/{id}/{name}`, `sym://group/{name}`) into service
392
+ type + group + room name. Read-only inspection; caller opens a
393
+ new session/env to join.
394
+
395
+ `sym_status` output now includes `Group` + service type.
396
+
397
+ ### Fixed
398
+
399
+ - **`plugin.json` validation failure on install.** The three
400
+ `channels[0].userConfig` entries (`relay_url`, `relay_token`,
401
+ `allowed_peers`) were missing the required `type` and `title`
402
+ fields per the Claude Code plugin schema. Install failed with:
403
+
404
+ ```
405
+ channels.0.userConfig.relay_url.type: Invalid option
406
+ channels.0.userConfig.relay_url.title: expected string, received undefined
407
+ ```
408
+
409
+ Added `type: "string"` and a human-readable `title` to all three.
410
+ Likely one of the root causes of the 10 Apr 2026 submission
411
+ showing "Published" on the Anthropic submissions portal but not
412
+ propagating to the public `claude-plugins-official` marketplace.
413
+
414
+ ### Changed
415
+
416
+ - **README**: self-hosted plugin-marketplace install path promoted to
417
+ the primary install recommendation (works today, independent of
418
+ Anthropic directory propagation). npm path kept as alternative.
419
+ Tool table updated 5 8 entries to reflect the current surface.
420
+ Clarified that plugin-directory approval and Channels-allowlist
421
+ inclusion are independent gates — the MCP tools work without the
422
+ `--dangerously-load-development-channels` flag; the flag is only
423
+ needed for the `<channel>` async-push behaviour.
424
+
425
+ - Pairs with `@sym-bot/sym` ≥ 0.3.78 which added the
426
+ `discoveryServiceType` and `group` constructor params consumed by
427
+ the mesh-group tools.
428
+
429
+ ## 0.1.21
430
+
431
+ ### Changed
432
+
433
+ - **README: accurate `sym_status` / `sym_peers` example output.** The
434
+ Quick Start sample output was a stylized one-line compression; the
435
+ real output is multi-line with additional fields (nodeId suffix,
436
+ Relay, Memories, one peer per line). Updated so users see in the
437
+ README exactly what their terminal will show. Doc-only — no code
438
+ changes.
439
+
440
+ ## 0.1.20
441
+
442
+ ### Added
443
+
444
+ - **`sym-mesh-channel init --project`** new flag to install the MCP
445
+ server at project scope (`<cwd>/.mcp.json` + merged
446
+ `<cwd>/.claude/settings.local.json`) instead of global
447
+ `~/.claude.json`. Enables multi-identity-per-machine workflows where
448
+ several Claude Code sessions run in parallel from distinct project
449
+ directories and each appears as its own peer on the mesh. Project
450
+ `.mcp.json` entries override the global `mcpServers` entry when
451
+ Claude Code launches from that directory, so `SYM_NODE_NAME` can
452
+ differ per project without siblings stepping on each other.
453
+ - Project mode supports the same `--force` semantics as global install:
454
+ backs up existing `.mcp.json` and `settings.local.json` next to
455
+ themselves (`*.bak-<timestamp>`), merges `settings.local.json` so
456
+ unrelated keys (permissions, custom settings) are preserved, atomic
457
+ writes via tmp+rename, refuses to overwrite an existing
458
+ `claude-sym-mesh` entry without `--force`.
459
+ - `--postinstall` always runs global install regardless of `--project`
460
+ (npm postinstall runs from npm's staging dir, not the user's
461
+ project). Keeps `npm install -g` auto-configure behavior unchanged.
462
+ - **5 new tests** covering project-mode install: writes `.mcp.json`
463
+ and `settings.local.json`, merge preserves existing keys, refusal
464
+ path exits 2, `--force` overwrite creates backup, postinstall
465
+ fallback ignores `--project`. Test suite now 22 tests total.
466
+
467
+ ### Why
468
+
469
+ Default mode (single mesh identity per machine, global install) is
470
+ correct for most users and unchanged. `--project` exists for the
471
+ small but real set of users who run multiple Claude Code sessions
472
+ in parallel from distinct project directories and want each session
473
+ to show up as its own peer on the mesh. Previously this workflow
474
+ required hand-editing `.mcp.json` and `.claude/settings.local.json`
475
+ per project; now it's one command per project.
476
+
477
+ ## 0.1.19
478
+
479
+ ### Added
480
+
481
+ - **Claude Code plugin manifest** for Anthropic Channels allowlist
482
+ submission. `.claude-plugin/plugin.json` + `.mcp.json` following the
483
+ official single-repo pattern (Telegram/Discord). Submitted to
484
+ Anthropic Plugin Directory 10 Apr 2026.
485
+ - **`SYM_ALLOWED_PEERS`**optional peer allowlist (defense-in-depth).
486
+ Comma-separated node names; only listed peers can push to Claude's
487
+ context. Empty = accept all authenticated peers. SVAF still gates on
488
+ content relevance regardless.
489
+ - **`SECURITY.md`** 3-layer defense model documentation (transport
490
+ auth + SVAF content gate + peer allowlist) for Anthropic review.
491
+ - **17 plugin tests** covering manifest validation, security checks
492
+ (no permission relay, no code execution, self-echo filtering, peer
493
+ allowlist), and lifecycle (shutdown handlers, identity collision).
494
+
495
+ ## 0.1.18
496
+
497
+ ### Changed
498
+
499
+ - **Auto-configure on install.** `npm install -g` now runs `postinstall`
500
+ that writes the MCP server config to global `mcpServers` in
501
+ `~/.claude.json` automatically. No separate `sym-mesh-channel init`
502
+ step needed — two commands to mesh: install + launch.
503
+ - **Global MCP config** — server entry is now written to top-level
504
+ `mcpServers` (available in all Claude Code sessions), not
505
+ project-scoped.
506
+ - **Windows postinstall fixes** `require.resolve` for server.js path
507
+ (handles npm staging directory on Windows), EBUSY handling when
508
+ Claude Code has `~/.claude.json` locked, graceful skip if Claude
509
+ Code not yet installed.
510
+ - **README repositioned** lead with capability ("first non-Anthropic
511
+ Claude Code Channels implementation"), not use case. Simplified
512
+ Quick Start to two commands.
513
+ - **0 vulnerabilities** fresh dependency rebuild resolves all 6
514
+ moderate hono/node-server advisories.
515
+ - Windows mDNS: built-in on Windows 10+, no Bonjour install needed.
516
+
517
+ ## 0.1.7
518
+
519
+ ### Added
520
+
521
+ - **`npx @sym-bot/mesh-channel init`** interactive installer that
522
+ writes `~/.claude.json` for the current project, picks a sensible
523
+ default `SYM_NODE_NAME` (`claude-mac` / `claude-win` / `claude-linux`),
524
+ resolves the absolute path to `server.js`, and prints the launch
525
+ command including the `--dangerously-load-development-channels` flag.
526
+ Backs up the existing config to `~/.claude.json.bak-<timestamp>`,
527
+ validates JSON round-trip, atomic write via tmp+rename. Refuses to
528
+ overwrite an existing entry without `--force`.
529
+ - **README rewritten for LAN-first install.** Quick start is two
530
+ minutes: install, init, launch. No relay required. Bonjour/mDNS
531
+ is the default discovery path. Cross-network setup (relay) is now
532
+ the optional advanced section.
533
+
534
+ ### Changed
535
+
536
+ - `package.json` `bin` now exposes both `sym-mesh-channel` (server
537
+ entrypoint) and `sym-mesh-channel-init` (installer). The package
538
+ description leads with "LAN-first via Bonjour, no relay required."
539
+
540
+ ### Why
541
+
542
+ The 0.1.5/0.1.6 install path required users to manually edit
543
+ `~/.claude.json`, know about the Channels dev flag, set up a relay,
544
+ and obtain a relay token. That gated the demo behind real friction.
545
+ LAN-only mode has worked since day one in the underlying SymNode
546
+ (`sym/lib/node.js:509-511` only connects to the relay if `SYM_RELAY_URL`
547
+ is set; Bonjour discovery starts unconditionally), but no documentation
548
+ or installer surfaced it. This release closes that gap: two users on
549
+ the same wifi can join the same mesh in two minutes with three commands.
550
+
551
+ ## 0.1.6
552
+
553
+ ### Fixed
554
+
555
+ - `sym_send` no longer double-delivers. Previously called both
556
+ `node.send()` (broadcast as `event_type=message`) AND `node.remember()`
557
+ (persist as CMB which gets gossiped as `event_type=cmb`), causing
558
+ the same payload to arrive twice on receivers and double the
559
+ context-window cost. Now broadcasts the message frame only. Hosts
560
+ that want CMB persistence should call `sym_observe` separately
561
+ with proper CAT7 fields.
562
+ - `sym_send` now reports the actual delivered count, not
563
+ `peers().length`. Requires `@sym-bot/sym >= 0.3.70` where `send()`
564
+ returns the count of peer transports that successfully accepted
565
+ the broadcast. The two can disagree when peers are tracked but
566
+ have broken transports the delivered count is the truth about
567
+ what was actually sent.
568
+
569
+ ### Changed
570
+
571
+ - Bumped `@sym-bot/sym` dep `^0.3.69` → `^0.3.70`. 0.3.70 ships the
572
+ identity lockfile that prevents two SymNode processes from
573
+ claiming the same nodeId on a host (the cliHostMode-vs-MCP
574
+ collision that broke real-time push on Windows during the
575
+ 2026-04-09 round-trip test).
576
+
577
+ ## 0.1.5
578
+
579
+ ### Changed
580
+
581
+ - Bumped `@sym-bot/sym` dep `^0.3.68` `^0.3.69` (0.3.68 deprecated;
582
+ same code in 0.3.69 with a cleaner published tarball).
583
+ - Added `files` whitelist to `package.json` and `.npmignore` for
584
+ `*.bak`, `*.swp`, `.DS_Store` so future publishes can't accidentally
585
+ ship local backup files. First NPM publish of this package.
586
+
587
+ ## 0.1.4
588
+
589
+ ### Changed
590
+
591
+ - Bumped `@sym-bot/sym` dep `^0.3.43` `^0.3.68` to pick up
592
+ duplicate-identity refusal (close code 4004) and the new
593
+ `identity-collision` event.
594
+
595
+ ### Added
596
+
597
+ - Wired `node.on('identity-collision', ...)` to `process.exit(2)` so
598
+ the MCP dies cleanly when the relay reports a duplicate-identity
599
+ race. Together with v0.1.3's clean shutdown, this fully resolves
600
+ the host-side half of the duplicate-identity bug.
601
+
602
+ ## 0.1.3
603
+
604
+ ### Added
605
+
606
+ - Clean shutdown handlers (SIGTERM/SIGINT/SIGHUP) that call
607
+ `node.stop()` before exiting, so the SymNode disconnects from the
608
+ relay before the process dies. Without this, restarts left zombie
609
+ registrations on the relay until the next heartbeat tick (up to
610
+ 30s), creating a duplicate-identity race window for the next MCP
611
+ spawn. Idempotent re-entry guard.
612
+
613
+ ## 0.1.2
614
+
615
+ ### Fixed
616
+
617
+ - Suppressed `peer-joined` / `peer-left` events from being pushed to
618
+ Claude's context as `<channel>` notifications. Presence is high-
619
+ frequency and low-signal — a relay reconnect could fire one event
620
+ per peer per cycle, flooding the context window. CMBs and direct
621
+ messages still flow through.
622
+
623
+ ## 0.1.1
624
+
625
+ ### Changed
626
+
627
+ - Replaced hardcoded `claude-code` / `claude-code-mac` literals with
628
+ a single `NODE_NAME` constant sourced from `process.env.SYM_NODE_NAME`
629
+ (default `claude-code-mac`). Enables platform-scoped naming per
630
+ MMP §3.1.2 without source edits. Fixed stale display strings in
631
+ the MCP instructions, `sym_send` perspective, `sym_status` header,
632
+ and the self-echo dedup filter.
633
+
634
+ ## 0.1.0
635
+
636
+ ### Added
637
+
638
+ - Initial release. MCP server that runs a `SymNode` peer node inside
639
+ a Claude Code session — own identity, own relay connection, own
640
+ SVAF evaluation. Tools: `sym_send`, `sym_observe`, `sym_recall`,
641
+ `sym_peers`, `sym_status`. Mesh events arrive as `<channel>`
642
+ notifications when launched with
643
+ `claude --dangerously-load-development-channels server:claude-sym-mesh`
644
+ (allowlisted server name required by Claude Code Channels).