@sym-bot/sym 0.1.0 → 0.2.1
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/PRD.md +1 -1
- package/README.md +237 -70
- package/TECHNICAL-SPEC.md +250 -197
- package/bin/setup-claude.sh +31 -1
- package/bin/sym-daemon.js +437 -0
- package/docs/mesh-memory-protocol.md +563 -0
- package/docs/mmp-architecture-image-prompt.txt +12 -0
- package/docs/p2p-protocol-research.md +907 -0
- package/docs/protocol-wake.md +242 -0
- package/integrations/claude-code/mcp-server.js +264 -41
- package/integrations/telegram/bot.js +418 -0
- package/lib/ipc-client.js +241 -0
- package/lib/node.js +489 -39
- package/lib/transport.js +88 -0
- package/package.json +5 -3
- package/sym-relay/Dockerfile +7 -0
- package/sym-relay/lib/logger.js +28 -0
- package/sym-relay/lib/relay.js +388 -0
- package/sym-relay/package-lock.json +40 -0
- package/sym-relay/package.json +18 -0
- package/sym-relay/render.yaml +14 -0
- package/sym-relay/server.js +67 -0
- package/.mcp.json +0 -12
package/TECHNICAL-SPEC.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SYM — Technical Specification
|
|
2
2
|
|
|
3
|
-
**Version:** 0.
|
|
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
|
|
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 │ │
|
|
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
|
-
│ │
|
|
21
|
-
│ │ Own state │ │ │ │ Own state │ │ │ │ Own state │ │
|
|
21
|
+
│ │ Node.js │ │ │ │ Swift │ │ │ │ Node.js │ │
|
|
22
22
|
│ └─────┬─────┘ │ │ └─────┬─────┘ │ │ └─────┬─────┘ │
|
|
23
23
|
└────────┼────────┘ └────────┼───────┘ └────────┼───────┘
|
|
24
24
|
│ │ │
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
├── Bonjour (LAN) ──┤ │
|
|
26
|
+
│ │ │
|
|
27
|
+
└──── WebSocket Relay (internet) ────────┘
|
|
28
28
|
|
|
29
|
-
|
|
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
|
-
-
|
|
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
|
|
48
|
+
├── package.json ← @sym-bot/sym
|
|
56
49
|
├── lib/
|
|
57
|
-
│ ├── node.js
|
|
58
|
-
│ ├── config.js
|
|
59
|
-
│ ├── memory-store.js
|
|
60
|
-
│ ├── context-encoder.js
|
|
61
|
-
│ ├──
|
|
62
|
-
│ ├──
|
|
63
|
-
│
|
|
64
|
-
|
|
65
|
-
├──
|
|
66
|
-
│
|
|
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/
|
|
69
|
-
└──
|
|
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
|
-
|
|
72
|
+
**Cross-platform:**
|
|
73
|
+
- Node.js: `@sym-bot/sym` (npm)
|
|
74
|
+
- Swift: `sym-swift` (SPM) — for iOS/macOS
|
|
73
75
|
|
|
74
|
-
|
|
76
|
+
## 3. SymNode — The Embeddable Mesh Node
|
|
75
77
|
|
|
76
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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
|
-
//
|
|
92
|
-
node.remember('API endpoint
|
|
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
|
-
//
|
|
95
|
-
|
|
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
|
-
-
|
|
103
|
-
- Context
|
|
104
|
-
-
|
|
105
|
-
-
|
|
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
|
|
117
|
+
const node = new SymNode(options);
|
|
118
|
+
await node.start();
|
|
116
119
|
|
|
117
|
-
|
|
118
|
-
|
|
120
|
+
// Memory (shared only with cognitively aligned peers)
|
|
121
|
+
node.remember(content, { tags });
|
|
122
|
+
node.recall(query);
|
|
119
123
|
|
|
120
|
-
//
|
|
121
|
-
node.
|
|
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);
|
|
126
|
-
node.send(message, { to: peerId });
|
|
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();
|
|
131
|
-
node.coherence();
|
|
132
|
-
node.
|
|
133
|
-
node.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
├──
|
|
178
|
-
│
|
|
179
|
-
|
|
180
|
-
|
|
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": "
|
|
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"
|
|
173
|
+
"tags": ["bug", "api"],
|
|
196
174
|
"timestamp": 1710851200000
|
|
197
175
|
}
|
|
198
176
|
```
|
|
199
177
|
|
|
200
|
-
## 6.
|
|
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
|
-
|
|
225
|
+
### 6.3 Frame Types
|
|
203
226
|
|
|
204
|
-
|
|
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
|
-
|
|
236
|
+
## 7. Context Encoder
|
|
207
237
|
|
|
208
|
-
|
|
209
|
-
|
|
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
|
-
|
|
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
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
-
|
|
299
|
+
**Relay support:** Set `SYM_RELAY_URL` and `SYM_RELAY_TOKEN` environment variables.
|
|
240
300
|
|
|
241
|
-
|
|
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
|
-
|
|
303
|
+
### 9.2 Telegram Bot
|
|
244
304
|
|
|
245
|
-
|
|
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
|
-
|
|
307
|
+
```bash
|
|
308
|
+
TELEGRAM_BOT_TOKEN=token SYM_RELAY_TOKEN=secret node integrations/telegram/bot.js
|
|
309
|
+
```
|
|
256
310
|
|
|
257
|
-
|
|
311
|
+
**Commands:** `/peers`, `/status`, `/mood <text>`, `/remember <text>`, `/recall <query>`. Plain text messages are sent to all mesh peers.
|
|
258
312
|
|
|
259
|
-
|
|
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
|
-
|
|
315
|
+
### 9.3 Any Agent (SDK)
|
|
265
316
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
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
|
-
- **
|
|
281
|
-
- **
|
|
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',
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
|
354
|
+
**Environment variables:**
|
|
299
355
|
|
|
300
|
-
| Variable |
|
|
301
|
-
|
|
302
|
-
| `
|
|
303
|
-
| `
|
|
304
|
-
| `
|
|
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 |
|
|
309
|
-
|
|
310
|
-
| Discovery | `bonjour-service` (
|
|
311
|
-
| Coupling | `mesh-cognition` (
|
|
312
|
-
| Transport | `net` (
|
|
313
|
-
| Storage | `fs`
|
|
314
|
-
| Identity | `crypto.randomUUID()` (
|
|
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
|
-
**
|
|
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.
|
|
376
|
+
## 13. Cross-Platform
|
|
319
377
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
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
|
-
|
|
384
|
+
Node.js ↔ Swift interop verified. Same frame format, same coupling engine, same relay protocol.
|
|
332
385
|
|
|
333
386
|
---
|
|
334
387
|
|
package/bin/setup-claude.sh
CHANGED
|
@@ -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.
|
|
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"
|