@sym-bot/mesh-channel 0.3.12 → 0.3.14

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