@sym-bot/sym 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/TECHNICAL-SPEC.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SYM — Technical Specification
2
2
 
3
- **Version:** 0.1
3
+ **Version:** 0.2
4
4
  **Author:** Hongwei Xu
5
5
  **Date:** March 2026
6
6
  **Organization:** SYM.BOT Ltd
@@ -9,204 +9,270 @@
9
9
 
10
10
  ## 1. Architecture Overview
11
11
 
12
- There is no central service. Each agent embeds its own SYM node with its own memory. Nodes discover each other via MMP and couple peer-to-peer. The mesh emerges from the connections between independent nodes.
12
+ SYM is a protocol for collective intelligence. There is no central service. Each agent embeds its own SYM node with its own identity, memory, and cognitive state. Nodes discover each other locally via Bonjour and remotely via a WebSocket relay. The mesh emerges from peer connections.
13
13
 
14
14
  ```
15
15
  ┌────────────────┐ ┌────────────────┐ ┌────────────────┐
16
- │ Claude Code │ │ OpenClaw │ │ Agent X
16
+ │ Claude Code │ │ MeloTune │ │ Telegram Bot
17
+ │ (Mac/Windows) │ │ (iPhone) │ │ (any device) │
17
18
  │ │ │ │ │ │
18
19
  │ ┌───────────┐ │ │ ┌───────────┐ │ │ ┌───────────┐ │
19
20
  │ │ SYM Node │ │ │ │ SYM Node │ │ │ │ SYM Node │ │
20
- │ │ Own memory│ │ │ │ Own memory│ │ │ │ Own memory│ │
21
- │ │ Own state │ │ │ │ Own state │ │ │ │ Own state │ │
21
+ │ │ Node.js │ │ │ │ Swift │ │ │ │ Node.js │ │
22
22
  │ └─────┬─────┘ │ │ └─────┬─────┘ │ │ └─────┬─────┘ │
23
23
  └────────┼────────┘ └────────┼───────┘ └────────┼───────┘
24
24
  │ │ │
25
- └──── MMP P2P ───────┴──── MMP P2P ──────┘
26
-
27
- discover ←→ couple ←→ broadcast ←→ evaluate ←→ accept/reject
25
+ ├── Bonjour (LAN) ──┤ │
26
+ │ │ │
27
+ └──── WebSocket Relay (internet) ────────┘
28
28
 
29
- MMP P2P
30
- │ Local network
31
- ┌────────────┴────────────┐
32
- │ Your Other Devices │
33
- │ (each agent = own node) │
34
- └─────────────────────────┘
29
+ discover encode → exchange state → evaluate drift → couple or reject
35
30
  ```
36
31
 
37
- Claude Code, OpenClaw, and Agent X — any agent embeds a SYM node. The mesh doesn't care what the agent is. That is the domain-agnostic claim proven in the architecture itself.
38
-
39
32
  Each agent is a sovereign node. Each node:
40
33
  - Maintains its own memory store
41
34
  - Runs its own context encoder
42
- - Discovers peers via Bonjour/mDNS
35
+ - Discovers local peers via Bonjour/mDNS
36
+ - Connects to remote peers via WebSocket relay
43
37
  - Evaluates peer state through drift analysis
44
38
  - Autonomously decides whether to couple
45
- - Broadcasts its memories to coupled peers
39
+ - Shares memories only with coupled peers
40
+ - Broadcasts mood signals evaluated by receiving agents
46
41
 
47
42
  No central process. No shared service. No hub. The mesh is the agents.
48
43
 
49
44
  ## 2. Package Structure
50
45
 
51
- SYM is a library that each agent embeds, not a standalone service. Each integration spawns its own SYM node.
52
-
53
46
  ```
54
47
  sym/
55
- ├── package.json name: "sym"
48
+ ├── package.json @sym-bot/sym
56
49
  ├── lib/
57
- │ ├── node.js ← SymNode class — the embeddable mesh node
58
- │ ├── config.js ← Configuration, paths, per-node identity
59
- │ ├── memory-store.js ← Per-node file-based memory store
60
- │ ├── context-encoder.js Local n-gram embedding + optional API
61
- │ ├── discovery.js Bonjour/mDNS peer discovery
62
- │ ├── transport.js TCP peer connections (MMP)
63
- ├── session-manager.js Peer session lifecycle
64
- │ └── frame-parser.js ← Length-prefixed JSON framing
65
- ├── python/
66
- └── sym/ Python package (SymNode)
50
+ │ ├── node.js ← SymNode class — the embeddable mesh node
51
+ │ ├── config.js ← Configuration, paths, per-node identity
52
+ │ ├── memory-store.js ← Per-node file-based memory store
53
+ │ ├── context-encoder.js N-gram hash embedding (zero API cost)
54
+ │ ├── transport.js TcpTransport + RelayPeerTransport abstraction
55
+ │ ├── frame-parser.js Length-prefixed JSON framing
56
+ └── claude-memory-bridge.js Claude Code memory directory integration
57
+ ├── sym-relay/
58
+ ├── package.json ← Standalone relay server
59
+ ├── server.js HTTP + WebSocket entry point
60
+ │ ├── lib/
61
+ │ │ ├── relay.js ← SymRelay — frame forwarding, auth, heartbeat
62
+ │ │ └── logger.js ← Structured logging
63
+ │ ├── Dockerfile ← Container deployment
64
+ │ └── render.yaml ← Render blueprint
67
65
  └── integrations/
68
- ├── claude-code/ ← MCP server embedding a SymNode
69
- └── openclaw/ OpenClaw skill embedding a SymNode
66
+ ├── claude-code/
67
+ └── mcp-server.js MCP server embedding a SymNode
68
+ └── telegram/
69
+ └── bot.js ← Telegram bot embedding a SymNode
70
70
  ```
71
71
 
72
- ## 3. SymNode — The Embeddable Mesh Node
72
+ **Cross-platform:**
73
+ - Node.js: `@sym-bot/sym` (npm)
74
+ - Swift: `sym-swift` (SPM) — for iOS/macOS
73
75
 
74
- The core primitive is `SymNode`a self-contained mesh node that any agent embeds. Each SymNode:
76
+ ## 3. SymNode — The Embeddable Mesh Node
75
77
 
76
- - Has its own unique identity (UUID, persisted per node name)
77
- - Has its own memory store (file-based, isolated)
78
- - Runs its own MMP listener (TCP, port auto-assigned)
79
- - Discovers other SymNodes via Bonjour/mDNS (`_sym._tcp`)
80
- - Couples autonomously via drift-bounded evaluation
81
- - Broadcasts new memories to coupled peers
82
- - Encodes context locally (n-gram hash, no API required)
78
+ The core primitive is `SymNode` a self-contained mesh node that any agent embeds.
83
79
 
84
80
  ```javascript
85
- const { SymNode } = require('sym');
81
+ const { SymNode } = require('@sym-bot/sym');
86
82
 
87
- // Each agent creates its own node
88
- const node = new SymNode({ name: 'claude-code' });
83
+ const node = new SymNode({
84
+ name: 'my-agent',
85
+ cognitiveProfile: 'What this agent understands and responds to',
86
+ moodThreshold: 0.8, // mood acceptance threshold
87
+ relay: 'wss://sym-relay.onrender.com', // optional relay URL
88
+ relayToken: 'shared-secret', // optional relay auth
89
+ relayOnly: false, // skip Bonjour if true
90
+ });
89
91
  await node.start();
90
92
 
91
- // Write a memory broadcasts to all coupled peers
92
- node.remember('API endpoint /users returns 500 when email is null', { tags: ['bug', 'api'] });
93
+ // Memory shared only with cognitively aligned peers
94
+ node.remember('API endpoint returns 500 on null email', { tags: ['bug'] });
95
+ node.recall('API bugs');
93
96
 
94
- // Search across own + peer memories
95
- const results = node.recall('API bugs');
97
+ // Mood evaluated by receiving agent's coupling engine
98
+ node.broadcastMood('tired, need rest');
99
+
100
+ // Communication
101
+ node.send('deploy complete');
96
102
 
97
- // Stop when agent exits
98
103
  await node.stop();
99
104
  ```
100
105
 
101
106
  ### Built on Mesh Cognition SDK
102
- - MMP protocol (framing, handshake, state sync, memory broadcast)
103
- - Context Encoder (local n-gram + optional OpenAI)
104
- - Bonjour discovery and TCP transport
105
- - Coupling engine (SemanticCoupler from mesh-cognition)
107
+ - Coupling engine (`SemanticCoupler` from `mesh-cognition`)
108
+ - Context encoder (local n-gram hash, zero API cost)
109
+ - MMP framing (length-prefixed JSON)
110
+ - Bonjour discovery (`_sym._tcp`)
111
+ - WebSocket relay transport
106
112
  - File-based memory store
107
113
 
108
114
  ## 4. SymNode API
109
115
 
110
- Each agent interacts with its embedded SymNode through direct method calls. No HTTP. No CLI. No intermediate process.
111
-
112
- ### JavaScript / TypeScript
113
-
114
116
  ```javascript
115
- const { SymNode } = require('sym');
117
+ const node = new SymNode(options);
118
+ await node.start();
116
119
 
117
- const node = new SymNode({ name: 'my-agent' });
118
- await node.start(); // Start discovery + MMP listener
120
+ // Memory (shared only with cognitively aligned peers)
121
+ node.remember(content, { tags });
122
+ node.recall(query);
119
123
 
120
- // Memory
121
- node.remember(content, { key?, tags? }); // Write + broadcast to peers
122
- node.recall(query); // Search own + peer memories
124
+ // Mood (evaluated by receiving agent's coupling engine)
125
+ node.broadcastMood(mood, { context });
123
126
 
124
127
  // Communication
125
- node.send(message); // Send message to all coupled peers
126
- node.send(message, { to: peerId }); // Send to specific peer
127
- node.on('message', (from, content) => {}); // Receive messages from peers
128
+ node.send(message);
129
+ node.send(message, { to: peerId });
128
130
 
129
131
  // Monitoring
130
- node.peers(); // Connected peer nodes with coupling state
131
- node.coherence(); // Kuramoto r(t) with peers
132
- node.context(); // Current mesh context summary
133
- node.memories(); // Memory count (own + per peer)
134
- node.status(); // Full node status: identity, peers, memories, coupling
135
-
136
- // Lifecycle
137
- await node.stop(); // Disconnect from mesh, persist state
138
- ```
139
-
140
- ### Python
141
-
142
- ```python
143
- from sym import SymNode
144
-
145
- node = SymNode(name='my-agent')
146
- node.start()
147
-
148
- # Memory
149
- node.remember("API returns 500 on null email", tags=["bug", "api"])
150
- results = node.recall("API bugs")
132
+ node.peers(); // [{ name, coupling, drift, source }, ...]
133
+ node.coherence(); // Overall mesh coherence
134
+ node.memories(); // Memory count
135
+ node.status(); // Full node status
136
+
137
+ // Events
138
+ node.on('peer-joined', ({ id, name }) => {});
139
+ node.on('peer-left', ({ id, name }) => {});
140
+ node.on('coupling-decision', ({ peer, decision, drift }) => {});
141
+ node.on('memory-received', ({ from, entry, decision }) => {});
142
+ node.on('mood-accepted', ({ from, mood, drift }) => {});
143
+ node.on('mood-rejected', ({ from, mood, drift }) => {});
144
+ node.on('message', (from, content, msg) => {});
151
145
 
152
- # Communication
153
- node.send("What do we know about the API bug?")
154
- node.on_message(lambda sender, content: print(f"{sender}: {content}"))
155
-
156
- # Monitoring
157
- node.peers()
158
- node.coherence()
159
- node.status()
160
-
161
- node.stop()
146
+ await node.stop();
162
147
  ```
163
148
 
164
149
  ## 5. Per-Node Storage
165
150
 
166
- Each SymNode has its own isolated storage under `~/.sym/nodes/{name}/`:
151
+ Each SymNode has isolated storage under `~/.sym/nodes/{name}/`:
167
152
 
168
153
  ```
169
154
  ~/.sym/
170
155
  └── nodes/
171
156
  ├── claude-code/
172
- │ ├── identity.json ← Node ID (UUID)
173
- │ ├── state.json ← Hidden state (coupled)
157
+ │ ├── identity.json ← Node ID (UUID), hostname
174
158
  │ └── memories/
175
159
  │ ├── local/ ← This node's memories
176
160
  │ └── {peer-nodeId}/ ← Memories received from peers
177
- ├── openclaw/
178
- ├── identity.json
179
- │ ├── state.json
180
- └── memories/
181
- └── agent-x/
182
- ├── identity.json
183
- ├── state.json
184
- └── memories/
161
+ ├── melotune/
162
+ └── ...
163
+ └── telegram/
164
+ └── ...
185
165
  ```
186
166
 
187
- Each node has its own identity, its own memories, its own coupled state. No shared files between nodes.
188
-
189
167
  Each memory entry:
190
168
  ```json
191
169
  {
192
- "key": "api-bug-null-email",
170
+ "key": "memory-1710851200000",
193
171
  "content": "API endpoint /users returns 500 when email is null",
194
172
  "source": "claude-code",
195
- "tags": ["bug", "api", "backend"],
173
+ "tags": ["bug", "api"],
196
174
  "timestamp": 1710851200000
197
175
  }
198
176
  ```
199
177
 
200
- ## 6. Integration Architecture
178
+ ## 6. Transport Layer
179
+
180
+ SYM supports two transport modes that run simultaneously (hybrid mode).
181
+
182
+ ### 6.1 Bonjour (LAN)
183
+
184
+ Zero-configuration discovery on the local network.
185
+
186
+ - **Service type**: `_sym._tcp`
187
+ - **TXT record**: `node-id`, `node-name`, `hostname`
188
+ - **Connection dedup**: Lower node ID initiates (prevents duplicate connections)
189
+ - **Transport**: TCP with length-prefixed JSON framing (4-byte BE u32 + UTF-8 JSON)
190
+ - **Heartbeat**: Ping every 5s idle, timeout 15s
191
+
192
+ ### 6.2 WebSocket Relay (Internet)
193
+
194
+ For mesh cognition across the internet. The relay is dumb transport — it forwards frames between authenticated nodes without inspecting payloads. All coupling decisions remain on-device.
195
+
196
+ **Relay protocol:**
197
+
198
+ 1. Client connects via WebSocket
199
+ 2. Client sends: `{ type: 'relay-auth', nodeId, name, token? }`
200
+ 3. Relay validates token and registers connection
201
+ 4. Relay sends: `{ type: 'relay-peers', peers: [{ nodeId, name }] }`
202
+ 5. Relay notifies others: `{ type: 'relay-peer-joined', nodeId, name }`
203
+ 6. Client sends: `{ to?: nodeId, payload: <SYM frame> }`
204
+ 7. Relay forwards: `{ from: nodeId, fromName: name, payload: <SYM frame> }`
205
+ 8. On disconnect: `{ type: 'relay-peer-left', nodeId, name }`
206
+ 9. Heartbeat: relay sends `relay-ping` every 30s, expects `relay-pong`
207
+
208
+ **Relay features:**
209
+ - Token-based authentication (`SYM_RELAY_TOKEN` env var)
210
+ - Health endpoint: `GET /health` → `{ status, connections, uptime }`
211
+ - Auto-reconnect with exponential backoff (1s → 30s, 10% jitter)
212
+ - Peer deduplication (Bonjour peer already connected → skip relay connection)
213
+
214
+ **Transport abstraction** (`lib/transport.js`):
215
+
216
+ All peer interactions use a unified transport interface:
217
+
218
+ | Transport | Wraps | Used for |
219
+ |-----------|-------|----------|
220
+ | `TcpTransport` | TCP socket + FrameParser | Bonjour peers |
221
+ | `RelayPeerTransport` | Shared WebSocket + target nodeId | Relay peers |
222
+
223
+ Both implement: `send(frame)`, `close()`, events: `message`, `close`, `error`.
201
224
 
202
- Each integration embeds a SymNode — it does not connect to an external service.
225
+ ### 6.3 Frame Types
203
226
 
204
- ### 6.1 Claude Code (MCP Server)
227
+ | Type | Purpose | Direction |
228
+ |------|---------|-----------|
229
+ | `handshake` | Identity exchange | Bidirectional on connect |
230
+ | `state-sync` | Hidden state vectors for coupling | Bidirectional, every 30s |
231
+ | `memory-share` | Broadcast memory to aligned peers | Sender → coupled peers |
232
+ | `mood` | Mood signal for autonomous evaluation | Sender → all peers |
233
+ | `message` | Direct peer communication | Sender → all or specific peer |
234
+ | `ping` / `pong` | Heartbeat | Either direction |
205
235
 
206
- An MCP server process that embeds a SymNode. Claude Code connects to it and gains two tools:
236
+ ## 7. Context Encoder
207
237
 
208
- - `sym_remember` write to this node's mesh memory (broadcasts to peers)
209
- - `sym_recall` — search this node's own + peer memories
238
+ Each node runs its own context encoder using n-gram hash embedding. Zero cost, no API key, deterministic.
239
+
240
+ **Algorithm:**
241
+ 1. Normalize text (lowercase, alphanumeric + spaces)
242
+ 2. Character trigram hashing → vector dimensions
243
+ 3. Word unigram hashing → vector dimensions
244
+ 4. Word bigram hashing → vector dimensions
245
+ 5. L2 normalize → `h1[32]` + `h2[32]`
246
+
247
+ **Properties:**
248
+ - Deterministic: same text → same vectors
249
+ - Semantic proximity: similar text → similar vectors
250
+ - Zero API cost
251
+ - Cross-platform compatible (Node.js uses MD5, Swift uses DJB2 — different hash but similar semantic output)
252
+
253
+ **Re-encoding:** Every 30 seconds, the node re-encodes its context (cognitive profile + recent 20 memories) and broadcasts updated state vectors to all peers.
254
+
255
+ ## 8. Coupling Mechanics
256
+
257
+ When two SymNodes discover each other, coupling is autonomous:
258
+
259
+ 1. **State exchange**: Nodes exchange hidden state vectors (`h1[32]`, `h2[32]`).
260
+ 2. **Drift evaluation**: Cosine drift `D = 1 - cosine_similarity([h1,h2]_local, [h1,h2]_peer)`.
261
+ 3. **Decision**:
262
+ - Aligned (drift ≤ 0.25) → strong coupling (α = 0.4)
263
+ - Guarded (0.25 < drift ≤ 0.5) → weak coupling (α = 0.15)
264
+ - Rejected (drift > 0.5) → no coupling
265
+ 4. **Memory sharing**: Aligned and guarded peers receive memory broadcasts. Rejected peers do not.
266
+ 5. **Mood evaluation**: Separate threshold (`moodThreshold`, default 0.8). More permissive than memory sharing because user wellbeing crosses domain boundaries.
267
+ 6. **Coherence**: Average pairwise cosine similarity across all peers.
268
+
269
+ The agent doesn't configure trust. The coupling engine evaluates and decides.
270
+
271
+ ## 9. Integrations
272
+
273
+ ### 9.1 Claude Code (MCP Server)
274
+
275
+ An MCP server process that embeds a SymNode.
210
276
 
211
277
  ```json
212
278
  {
@@ -219,116 +285,103 @@ An MCP server process that embeds a SymNode. Claude Code connects to it and gain
219
285
  }
220
286
  ```
221
287
 
222
- The MCP process runs its own SymNode. It is a peer, not a client.
223
-
224
- ### 6.2 OpenClaw
225
-
226
- OpenClaw skill that embeds a SymNode. Already has MMP integration via mesh-cognition-service — migrates to embedded SymNode.
227
-
228
- ### 6.3 Agent X (SDK)
288
+ **Tools:**
229
289
 
230
- Any agent embeds a SymNode directly:
231
-
232
- ```javascript
233
- const { SymNode } = require('sym');
234
- const node = new SymNode({ name: 'my-custom-agent' });
235
- await node.start();
236
- // Agent is now a peer in the mesh
237
- ```
290
+ | Tool | Description |
291
+ |------|-------------|
292
+ | `sym_mood` | Proactively broadcast detected mood to the mesh |
293
+ | `sym_remember` | Store a memory in the mesh |
294
+ | `sym_recall` | Search memories across the mesh |
295
+ | `sym_send` | Send a message to all peers |
296
+ | `sym_peers` | Show connected peers with coupling state |
297
+ | `sym_status` | Full node status |
238
298
 
239
- Three lines. Any language. Any framework. The mesh doesn't care what the agent does.
299
+ **Relay support:** Set `SYM_RELAY_URL` and `SYM_RELAY_TOKEN` environment variables.
240
300
 
241
- ## 7. Peer-to-Peer Protocol
301
+ **Claude Memory Bridge:** Watches Claude Code's project memory directory. When Claude saves a memory, the bridge re-encodes the node's cognitive state and shares with aligned peers. When peer memory arrives, it's written to Claude's memory directory.
242
302
 
243
- Each SymNode communicates with peers using the Mesh Memory Protocol (MMP):
303
+ ### 9.2 Telegram Bot
244
304
 
245
- - **Discovery**: Bonjour/mDNS `_sym._tcp`. Each node advertises its own service with its node ID in the TXT record. Self-filtering prevents connecting to yourself.
246
- - **Transport**: TCP with length-prefixed JSON framing (4-byte BE u32 + UTF-8 JSON).
247
- - **Connection dedup**: Lower node ID initiates to prevent duplicate connections.
248
- - **Handshake**: First frame is state sync with hidden state + memory count.
249
- - **Memory broadcast**: When a node writes a memory, it broadcasts to all coupled peers.
250
- - **Peer messaging**: Nodes send messages to peers via `message` frames. Messages are delivered to coupled peers only. Each message carries sender ID, content, and optional target peer ID for directed messages.
251
- - **Heartbeat**: Ping every 5s idle, timeout 15s.
252
- - **Reconnection**: Exponential backoff 1s → 30s with 10% jitter.
253
- - **Port assignment**: Each node auto-assigns an available TCP port. No port conflicts between nodes on the same machine.
305
+ A Telegram bot that acts as a SYM mesh node, bridging human messages between Telegram and the mesh.
254
306
 
255
- ## 8. Context Encoder
307
+ ```bash
308
+ TELEGRAM_BOT_TOKEN=token SYM_RELAY_TOKEN=secret node integrations/telegram/bot.js
309
+ ```
256
310
 
257
- Each node runs its own context encoder:
311
+ **Commands:** `/peers`, `/status`, `/mood <text>`, `/remember <text>`, `/recall <query>`. Plain text messages are sent to all mesh peers.
258
312
 
259
- - **Local mode (default)**: N-gram hash embedding. Zero cost, no API key. Similar text produces similar vectors (cosine 0.856 for related contexts).
260
- - **API mode (optional)**: OpenAI `text-embedding-3-small`. Set `OPENAI_API_KEY`.
261
- - **Interval**: Every 60 seconds (configurable via `SYM_ENCODE_INTERVAL`).
262
- - **Purpose**: Encodes accumulated memories into hidden state vectors. Drives coupling coherence — nodes with similar context align, dissimilar nodes stay independent.
313
+ **Mesh Telegram:** Peer joins/leaves, incoming messages, mood signals, memory shares, and coupling decisions are forwarded to authorised Telegram chats.
263
314
 
264
- ## 9. Coupling Mechanics
315
+ ### 9.3 Any Agent (SDK)
265
316
 
266
- When two SymNodes discover each other, coupling is autonomous:
267
-
268
- 1. **State exchange**: Nodes exchange hidden state vectors (from Context Encoder).
269
- 2. **Drift evaluation**: Cosine drift between local and peer hidden states.
270
- 3. **Decision**: Aligned (drift ≤ 0.25) → strong coupling. Guarded (≤ 0.5) → weak. Rejected (> 0.5) → no coupling.
271
- 4. **Memory sharing**: Aligned and guarded peers receive memory broadcasts. Rejected peers do not.
272
- 5. **Coherence**: Measured by average pairwise cosine similarity across all peers.
273
-
274
- The agent doesn't configure trust. The architecture evaluates and decides.
317
+ ```javascript
318
+ const { SymNode } = require('@sym-bot/sym');
319
+ const node = new SymNode({
320
+ name: 'my-agent',
321
+ relay: 'wss://sym-relay.onrender.com',
322
+ });
323
+ await node.start();
324
+ // This agent is now a peer in the mesh — local and internet
325
+ ```
275
326
 
276
327
  ## 10. Security Model
277
328
 
278
329
  - **Node isolation**: Each SymNode has its own identity, memory, and state. No shared files between nodes.
279
330
  - **Autonomous trust**: Each node evaluates peer state through drift analysis. No node is forced to accept peer influence.
280
- - **Network trust**: Bonjour discovery only on local network. TCP connections use same-network assumption.
281
- - **No authentication**: v0.1 relies on local network trust. Future: optional TLS + peer approval.
282
- - **No telemetry**: SYM sends nothing to any server. Ever.
331
+ - **Relay authentication**: Token-based auth (`SYM_RELAY_TOKEN`). Relay never inspects frame payloads.
332
+ - **Local network**: Bonjour discovery restricted to LAN.
333
+ - **No telemetry**: SYM sends nothing to any external server. Ever.
283
334
  - **Data locality**: All memories stored in `~/.sym/nodes/{name}/`. Delete the directory, everything is gone.
335
+ - **Coupling as security**: Rejected peers never receive your memories. The coupling engine is the access control layer.
284
336
 
285
337
  ## 11. Configuration
286
338
 
287
- Per-node configuration via constructor options:
288
-
289
339
  ```javascript
290
340
  const node = new SymNode({
291
- name: 'my-agent', // Required: node name (determines storage path)
292
- encodeInterval: 60000, // Context encoding interval (ms)
293
- maxContextChars: 2000, // Max context length for encoding
294
- openaiApiKey: process.env.OPENAI_API_KEY, // Optional: API embedding mode
341
+ name: 'my-agent', // Required: node name (storage path)
342
+ cognitiveProfile: '...', // What this agent understands
343
+ moodThreshold: 0.8, // Mood acceptance threshold (default 0.8)
344
+ relay: 'wss://...', // WebSocket relay URL
345
+ relayToken: 'secret', // Relay auth token
346
+ relayOnly: false, // Skip Bonjour, relay only
347
+ heartbeatInterval: 5000, // Peer heartbeat interval (ms)
348
+ heartbeatTimeout: 15000, // Peer timeout (ms)
349
+ encodeInterval: 30000, // Context re-encoding interval (ms)
350
+ silent: false, // Suppress console logging
295
351
  });
296
352
  ```
297
353
 
298
- Environment variables (apply to all nodes on the machine):
354
+ **Environment variables:**
299
355
 
300
- | Variable | Default | Description |
301
- |----------|---------|-------------|
302
- | `SYM_ENCODE_INTERVAL` | `60000` | Context encoding interval (ms) |
303
- | `SYM_CONTEXT_CHARS` | `2000` | Max context length for encoding |
304
- | `OPENAI_API_KEY` | | Optional: enables API embedding mode |
356
+ | Variable | Description |
357
+ |----------|-------------|
358
+ | `SYM_RELAY_URL` | Relay URL for MCP server integration |
359
+ | `SYM_RELAY_TOKEN` | Relay auth token |
360
+ | `TELEGRAM_BOT_TOKEN` | Telegram bot token |
305
361
 
306
362
  ## 12. Dependencies
307
363
 
308
- | Component | Implementation |
309
- |-----------|---------------|
310
- | Discovery | `bonjour-service` (npm) |
311
- | Coupling | `mesh-cognition` (npm) |
312
- | Transport | `net` (Node.js built-in) |
313
- | Storage | `fs` (Node.js built-in) |
314
- | Identity | `crypto.randomUUID()` (Node.js built-in) |
364
+ | Component | Node.js | Swift |
365
+ |-----------|---------|-------|
366
+ | Discovery | `bonjour-service` | `Network` (NWBrowser) |
367
+ | Coupling | `mesh-cognition` | `MeshCognition` (SPM) |
368
+ | Transport | `net` + `ws` | `Network` (NWConnection) + `URLSession` |
369
+ | Storage | `fs` | `FileManager` |
370
+ | Identity | `crypto.randomUUID()` | `UUID()` |
315
371
 
316
- **Total external dependencies: 2** (`bonjour-service`, `mesh-cognition`).
372
+ **Node.js external deps:** `bonjour-service`, `mesh-cognition`, `ws`
373
+ **Swift external deps:** `MeshCognition` SPM package
374
+ **Relay server deps:** `ws`
317
375
 
318
- ## 13. Install & Usage
376
+ ## 13. Cross-Platform
319
377
 
320
- ```bash
321
- npm install sym
322
- ```
323
-
324
- ```javascript
325
- const { SymNode } = require('sym');
326
- const node = new SymNode({ name: 'my-agent' });
327
- await node.start();
328
- // This agent is now a peer in the mesh
329
- ```
378
+ | Platform | Package | Transport |
379
+ |----------|---------|-----------|
380
+ | Node.js | `@sym-bot/sym` (npm) | Bonjour + WebSocket relay |
381
+ | Swift | `sym-swift` (SPM) | Bonjour + WebSocket relay |
382
+ | Relay | `@sym-bot/relay` | WebSocket server |
330
383
 
331
- Published to npm as `sym`. No global install. No daemon. Each agent imports and embeds.
384
+ Node.js Swift interop verified. Same frame format, same coupling engine, same relay protocol.
332
385
 
333
386
  ---
334
387
 
@@ -1,6 +1,7 @@
1
1
  #!/bin/bash
2
2
  # SYM — Setup for Claude Code
3
3
  # Adds MCP server + auto-approves sym_mood + installs CLAUDE.md instructions
4
+ # Optionally configures WebSocket relay for internet-scale mesh
4
5
 
5
6
  set -e
6
7
 
@@ -38,7 +39,36 @@ if [ -f "$CLAUDE_JSON" ]; then
38
39
  "
39
40
  fi
40
41
 
41
- # 3. Append CLAUDE.md instructions if not already present
42
+ # 3. Configure relay (optional)
43
+ echo ""
44
+ echo "WebSocket Relay (optional)"
45
+ echo "Connects your mesh across the internet — not just local network."
46
+ echo ""
47
+
48
+ SHELL_RC="$HOME/.zshrc"
49
+ [ -f "$HOME/.bashrc" ] && [ ! -f "$HOME/.zshrc" ] && SHELL_RC="$HOME/.bashrc"
50
+
51
+ if grep -q "SYM_RELAY_URL" "$SHELL_RC" 2>/dev/null; then
52
+ echo " Relay already configured in $SHELL_RC"
53
+ else
54
+ read -p "Relay URL (leave empty to skip): " RELAY_URL
55
+ if [ -n "$RELAY_URL" ]; then
56
+ read -p "Relay token (leave empty for open access): " RELAY_TOKEN
57
+ echo "" >> "$SHELL_RC"
58
+ echo "# SYM Mesh" >> "$SHELL_RC"
59
+ echo "export SYM_RELAY_URL=\"$RELAY_URL\"" >> "$SHELL_RC"
60
+ if [ -n "$RELAY_TOKEN" ]; then
61
+ echo "export SYM_RELAY_TOKEN=\"$RELAY_TOKEN\"" >> "$SHELL_RC"
62
+ fi
63
+ echo " Relay configured in $SHELL_RC"
64
+ echo " Run 'source $SHELL_RC' or restart your terminal to activate."
65
+ else
66
+ echo " Skipping relay — using Bonjour (local network) only."
67
+ fi
68
+ fi
69
+
70
+ # 4. Append CLAUDE.md instructions if not already present
71
+ echo ""
42
72
  echo "Installing CLAUDE.md instructions..."
43
73
  PROJECT_DIR="${1:-$(pwd)}"
44
74
  CLAUDE_MD="$PROJECT_DIR/CLAUDE.md"