@sym-bot/mesh-channel 0.3.22 → 0.3.25

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sym-mesh-channel",
3
- "version": "0.3.22",
3
+ "version": "0.3.25",
4
4
  "description": "Real-time Claude-to-Claude mesh. Agent-to-agent cognitive signals over Bonjour LAN or WebSocket relay.",
5
5
  "author": {
6
6
  "name": "Hongwei Xu",
package/.mcp.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "command": "npx",
5
5
  "args": [
6
6
  "-y",
7
- "@sym-bot/mesh-channel@0.3.22"
7
+ "@sym-bot/mesh-channel@0.3.25"
8
8
  ],
9
9
  "env": {
10
10
  "SYM_RELAY_URL": "${user_config.relay_url}",
package/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.3.25
4
+
5
+ ### Changed
6
+
7
+ - **Runs the `meshmem/` → `cmbs/` store migration on install** (`bin/install.js` calls `@sym-bot/sym`'s `migrateStores()`), so every non-live node is migrated when the plugin is set up. Pairs with `@sym-bot/sym` 0.7.16.
8
+
9
+ ## 0.3.24
10
+
11
+ ### Changed
12
+
13
+ - **MCP tools renamed to canonical Enterprise Integration Pattern verbs:** `sym_observe` → **`sym_publish`** (Publish-Subscribe Channel) and `sym_inbox` → **`sym_receive`** (Polling Consumer). The I/O surface now reads as what the agent *does* (publish / send / receive), while the cognitive mechanism terms (emit/admit, projection/observation) stay in the MMP spec one layer down. `sym_send` (Point-to-Point) unchanged. Clean break — no aliases. Agent instructions + tool descriptions updated: publishing emits a *projection* of your state; a receiver that admits it takes it as an *observation*.
14
+
15
+ ## 0.3.23
16
+
17
+ ### Changed
18
+
19
+ - **Removed the automatic `postinstall` registration.** The package no longer mutates `~/.claude.json` (or a project `.mcp.json`) on `npm install`. As a Claude Code **plugin**, the package is launched via `npx` on every session start, and the postinstall re-registered a competing user-scoped `claude-sym-mesh` MCP server each time — producing a second mesh node alongside the plugin's own. Registration now happens only via the explicit `start`/`init` commands, which the standalone flow (`npx @sym-bot/mesh-channel start`) already runs and which self-configure on first launch — so there is no change for standalone users, and the plugin path no longer double-registers. Pairs with the 0.3.22 `.sym/node.json` reader to make the plugin the single, stable, per-project mesh node.
20
+
3
21
  ## 0.3.22
4
22
 
5
23
  ### Added
package/README.md CHANGED
@@ -106,8 +106,9 @@ Eleven MCP tools exposed to Claude Code, namespaced under `mcp__claude-sym-mesh_
106
106
 
107
107
  | Tool | What it does |
108
108
  |---|---|
109
- | `sym_send` | Broadcast a free-text message to all mesh peers. Arrives in receivers' contexts as a `<channel>` notification. |
110
- | `sym_observe` | Share a structured CAT7 observation: focus, issue, intent, motivation, commitment, perspective, mood. SVAF-gated on the receiving side. |
109
+ | `sym_send` | Send a CAT7 CMB to a specific peer (point-to-point), or to all if no recipient is given. Arrives in receivers' contexts as a `<channel>` notification. |
110
+ | `sym_publish` | Publish a structured CAT7 CMB — a projection of your state — to your whole group (publish-subscribe): focus, issue, intent, motivation, commitment, perspective, mood. SVAF-gated on the receiving side. |
111
+ | `sym_receive` | Surface CMBs the mesh delivered to you in real-time when the `<channel>` push was gated — a live delivery feed, not a store query. |
111
112
  | `sym_recall` | Search mesh memory for past cognitive memory blocks. |
112
113
  | `sym_fetch` | Fetch the full content of a single CMB by its compact channel-header ID. |
113
114
  | `sym_peers` | List discovered peers (via bonjour or relay). |
@@ -230,7 +231,7 @@ The plugin composes two open specs:
230
231
  - **[Claude Code Channels](https://code.claude.com/docs/en/mcp)** (Anthropic, 2026-03-20) — an MCP capability that lets servers push events directly into Claude's conversation context mid-turn via `notifications/claude/channel`. Anthropic built it for the Telegram/Discord/iMessage integrations. We use it for agent-to-agent cognitive coupling.
231
232
  - **[MMP — the Mesh Memory Protocol](https://meshcognition.org/spec/mmp)** — defines *what* gets pushed: typed seven-field cognitive bundles (CAT7: focus, issue, intent, motivation, commitment, perspective, mood), how receivers gate incoming signals ([SVAF](https://arxiv.org/abs/2604.03955)), and how peers maintain identity without a central orchestrator.
232
233
 
233
- **What happens on each message.** When a peer broadcasts a cognitive memory block (CMB), the local SymNode evaluates it via SVAF — Symbolic-Vector Attention Fusion, a receiver-side relevance gate that rejects low-signal messages before they reach Claude's context. If accepted, the MCP server fires a `notifications/claude/channel` notification to Claude Code, which surfaces it as a `<channel>` block in the conversation. Claude sees it, can react, and can broadcast back via `sym_send` or `sym_observe`. No polling. No tool calls. The mesh thinks together.
234
+ **What happens on each message.** When a peer broadcasts a cognitive memory block (CMB), the local SymNode evaluates it via SVAF — Symbolic-Vector Attention Fusion, a receiver-side relevance gate that rejects low-signal messages before they reach Claude's context. If accepted, the MCP server fires a `notifications/claude/channel` notification to Claude Code, which surfaces it as a `<channel>` block in the conversation. Claude sees it, can react, and can broadcast back via `sym_send` or `sym_publish`. No polling. No tool calls. The mesh thinks together.
234
235
 
235
236
  **Identity and transport.** Each peer has its own Ed25519 keypair stored at `~/.sym/nodes/<name>/identity.json`. Node IDs are UUID v7 + Ed25519 signatures, gossiped through the relay's directory or via Bonjour TXT records. Full architecture in MMP §4–§6.
236
237
 
package/bin/install.js CHANGED
@@ -60,6 +60,13 @@ if (cmd !== 'init' && cmd !== 'doctor' && cmd !== 'start') {
60
60
  process.exit(1);
61
61
  }
62
62
 
63
+ // One-time bulk store migration (meshmem/ → cmbs/) for all non-live nodes, run
64
+ // on install so readers use the cmbs/ name with no fallback. Idempotent.
65
+ try {
66
+ const n = require('@sym-bot/sym').migrateStores();
67
+ if (n) process.stderr.write(`[sym-mesh-channel] migrated ${n} node store(s): meshmem → cmbs\n`);
68
+ } catch { /* SDK not resolvable or nothing to do — non-fatal */ }
69
+
63
70
  const KEBAB_CASE_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
64
71
  function validateGroupValue(value, source) {
65
72
  if (!value) return;
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "name": "@sym-bot/mesh-channel",
3
- "version": "0.3.22",
3
+ "version": "0.3.25",
4
4
  "description": "MCP server — real-time agent-to-agent cognition for Claude Code remote teams via the SYM mesh.",
5
5
  "main": "server.js",
6
6
  "bin": {
7
7
  "sym-mesh-channel": "server.js"
8
8
  },
9
9
  "scripts": {
10
- "test": "node test/plugin.test.js",
11
- "postinstall": "node bin/install.js init --postinstall"
10
+ "test": "node test/plugin.test.js"
12
11
  },
13
12
  "files": [
14
13
  "server.js",
@@ -22,7 +21,7 @@
22
21
  ],
23
22
  "dependencies": {
24
23
  "@modelcontextprotocol/sdk": "^1.12.1",
25
- "@sym-bot/sym": "^0.7.11",
24
+ "@sym-bot/sym": "^0.7.16",
26
25
  "bonjour-service": "^1.3.0"
27
26
  },
28
27
  "engines": {
package/server.js CHANGED
@@ -34,7 +34,7 @@ process.stdout.write = function (chunk, ...rest) {
34
34
  * Architecture (MMP Section 13.9: Local Event Interface):
35
35
  * SymNode (own identity, own SVAF field weights) → relay → mesh
36
36
  * MCP channel notifications → Claude Code (real-time push)
37
- * MCP tools → SymNode methods (send, observe, recall)
37
+ * MCP tools → SymNode methods (send, publish, recall)
38
38
  *
39
39
  * This is a PEER NODE, not a client of the daemon. It has its own identity,
40
40
  * its own relay connection, and its own SVAF evaluation with engineering-domain
@@ -360,12 +360,12 @@ function registerNodeHandlers(n) {
360
360
  // Base instructions shown to the agent at every MCP initialize.
361
361
  const BASE_INSTRUCTIONS =
362
362
  `You are a peer node on the SYM mesh (identity: ${NODE_NAME}). ` +
363
- 'Mesh events may arrive as <channel> notifications in real-time, but that push can be gated by Claude Code policy so to RECEIVE reliably, call sym_inbox to PULL messages addressed to you (directed sym_send + admitted broadcasts). Call sym_inbox at the start of your turn and periodically while coordinating with peers, so you never miss one. ' +
363
+ 'The mesh is publish-subscribe: peers deliver CMBs to you in real-time the instant they publish, as <channel> notifications. That real-time push can be gated by Claude Code policy, so call sym_receive to surface any deliveries the push did not bring into your context (directed sym_send + admitted broadcasts) — a live delivery feed, not a memory query. Call sym_receive at the start of your turn and periodically while coordinating with peers, so no delivery is missed. ' +
364
364
  'When you receive a CMB from another node, respond via sym_send targeted at that node by name if the reply is for that specific peer (MMP §4.4.4 targeted CMB). ' +
365
- 'Share observations about your own state with the whole mesh via sym_observe (MMP §9.2 receiver-autonomous SVAF evaluation). ' +
366
- 'Both sym_send and sym_observe emit CAT7 CMBs; receivers run SVAF and, if admitted, remix-store with lineage pointing back to your CMB. ' +
365
+ 'Publish a CMB to your whole group via sym_publish a projection of your own state (MMP §9.2 receiver-autonomous SVAF evaluation). ' +
366
+ 'Both sym_send and sym_publish emit a CAT7 CMB (your projection); each receiver runs SVAF and, if it admits the CMB as an observation, remix-stores it with lineage back to yours. ' +
367
367
  'Search mesh memory via sym_recall. ' +
368
- 'sym_inbox and <channel> notifications give compact headers with [mNNN] IDs — use sym_fetch to read the full content when relevant to your current task.';
368
+ 'sym_receive and <channel> notifications give compact headers with [mNNN] IDs — use sym_fetch to read the full content when relevant to your current task.';
369
369
 
370
370
  // Final startup step (MMP §4.2 O2 — rejoin-without-replay). The SymNode
371
371
  // constructor builds the memory-store index from disk, so the primer is
@@ -407,7 +407,7 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
407
407
  'Send a structured CAT7 CMB to a specific mesh peer (targeted) or to all peers (broadcast, when "to" is omitted). ' +
408
408
  'Receivers evaluate the CMB per-field via SVAF (MMP §9.2) and, if admitted, remix-store it with lineage pointing back to this CMB. ' +
409
409
  'Use sym_send when the CMB is for a specific peer (e.g. a peer-review gating request directed at the reviewer role); ' +
410
- 'use sym_observe when sharing your own state with the whole mesh.',
410
+ 'use sym_publish when publishing your own state to the whole group.',
411
411
  inputSchema: {
412
412
  type: 'object',
413
413
  properties: {
@@ -444,11 +444,11 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
444
444
  },
445
445
  },
446
446
  {
447
- name: 'sym_observe',
447
+ name: 'sym_publish',
448
448
  description:
449
- 'Broadcast a structured CAT7 observation about your own state to all mesh peers. ' +
450
- 'Receivers run SVAF (MMP §9.2) and admitted CMBs are remix-stored with lineage. ' +
451
- 'Equivalent to sym_send with "to" omitted — kept as a separate tool because self-observation is the common case and does not need peer selection.',
449
+ 'Publish a structured CAT7 CMB a projection of your own state to all peers in your group. ' +
450
+ 'Each receiver runs SVAF (MMP §9.2) and, if it admits the CMB as an observation, remix-stores it with lineage. ' +
451
+ 'Equivalent to sym_send with "to" omitted — kept as a separate tool because publishing your own state is the common case and does not need peer selection.',
452
452
  inputSchema: {
453
453
  type: 'object',
454
454
  properties: {
@@ -505,8 +505,8 @@ mcp.setRequestHandler(ListToolsRequestSchema, async () => ({
505
505
  },
506
506
  },
507
507
  {
508
- name: 'sym_inbox',
509
- description: 'PULL mesh messages received since your last inbox check — directed sym_send addressed to you, plus admitted broadcasts. This is the poll-based RECEIVE path: real-time channel push can be gated by Claude Code policy, but this tool always works. Call it at the start of a turn and periodically while coordinating so you never miss a peer. Returns compact headers with [mNNN] IDs (newest last); use sym_fetch for full content, reply via sym_send.',
508
+ name: 'sym_receive',
509
+ description: 'Surface the CMBs the mesh has delivered to you in real-time — directed sym_send addressed to you, plus admitted broadcasts published to your group. The mesh is publish-subscribe: peers deliver the instant they publish, pushed as <channel> notifications. Because that push can be gated by Claude Code policy, sym_receive surfaces any deliveries it missed so none is lost — a live delivery feed, NOT a store query (use sym_recall to search stored memory). Call it at the start of a turn and periodically while coordinating so no delivery is missed. Returns compact headers with [mNNN] IDs (newest last); use sym_fetch for full content, reply via sym_send.',
510
510
  inputSchema: {
511
511
  type: 'object',
512
512
  properties: {
@@ -627,7 +627,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
627
627
  return { content: [{ type: 'text', text: summary }] };
628
628
  }
629
629
 
630
- case 'sym_observe': {
630
+ case 'sym_publish': {
631
631
  const fields = {
632
632
  focus: args.focus || 'observation',
633
633
  issue: args.issue || 'none',
@@ -640,7 +640,7 @@ mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
640
640
  const observeOpts = {};
641
641
  if (args.payload !== undefined && args.payload !== null) observeOpts.payload = args.payload;
642
642
  const entry = node.remember(fields, observeOpts);
643
- return { content: [{ type: 'text', text: entry ? `Observed: ${entry.key}` : 'Duplicate — already in memory.' }] };
643
+ return { content: [{ type: 'text', text: entry ? `Published: ${entry.key}` : 'Duplicate — already in memory.' }] };
644
644
  }
645
645
 
646
646
  case 'sym_recall': {
@@ -685,12 +685,12 @@ mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
685
685
  };
686
686
  }
687
687
 
688
- case 'sym_inbox': {
688
+ case 'sym_receive': {
689
689
  // Thin adapter over the SDK primitive: the node owns the delivery buffer
690
690
  // + drain cursor (node.inbox()). This wrapper only formats for display.
691
691
  const { messages, remaining } = node.inbox({ peek: !!args.peek, limit: args.limit });
692
692
  if (!messages.length) {
693
- return { content: [{ type: 'text', text: 'Inbox emptyno new mesh messages since your last check.' }] };
693
+ return { content: [{ type: 'text', text: 'Caught upnothing new delivered since your last sym_receive.' }] };
694
694
  }
695
695
  const now = Date.now();
696
696
  const lines = messages.map((m) => {
@@ -707,9 +707,9 @@ mcp.setRequestHandler(CallToolRequestSchema, async (request) => {
707
707
  return `[${m.from}${dirTag}] ${String(focus).replace(/\s+/g, ' ').slice(0, 90)}${memTag} [${m.id}] (${age}s ago)`;
708
708
  }).filter(Boolean);
709
709
  if (!lines.length) {
710
- return { content: [{ type: 'text', text: 'Inbox emptyno new mesh messages since your last check.' }] };
710
+ return { content: [{ type: 'text', text: 'Caught upnothing new delivered since your last sym_receive.' }] };
711
711
  }
712
- const moreNote = remaining > 0 ? ` (+${remaining} more — call sym_inbox again)` : '';
712
+ const moreNote = remaining > 0 ? ` (+${remaining} more — call sym_receive again)` : '';
713
713
  return {
714
714
  content: [{
715
715
  type: 'text',