@geohar/un-bien 0.7.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/LICENSE +21 -0
- package/README.md +726 -0
- package/dist/actions/handlers.d.ts +77 -0
- package/dist/actions/handlers.js +26 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +39 -0
- package/dist/actions/registry.js +62 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.d.ts +2 -0
- package/dist/bin/supervisord.js +86 -0
- package/dist/bin/supervisord.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +20 -0
- package/dist/daemon/client.js +131 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +176 -0
- package/dist/daemon/control_protocol.js +63 -0
- package/dist/daemon/control_protocol.js.map +1 -0
- package/dist/daemon/cron_log.d.ts +45 -0
- package/dist/daemon/cron_log.js +71 -0
- package/dist/daemon/cron_log.js.map +1 -0
- package/dist/daemon/cron_registry.d.ts +80 -0
- package/dist/daemon/cron_registry.js +198 -0
- package/dist/daemon/cron_registry.js.map +1 -0
- package/dist/daemon/id.d.ts +24 -0
- package/dist/daemon/id.js +36 -0
- package/dist/daemon/id.js.map +1 -0
- package/dist/daemon/install.d.ts +170 -0
- package/dist/daemon/install.js +603 -0
- package/dist/daemon/install.js.map +1 -0
- package/dist/daemon/registry.d.ts +63 -0
- package/dist/daemon/registry.js +153 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/rpc_child.d.ts +194 -0
- package/dist/daemon/rpc_child.js +419 -0
- package/dist/daemon/rpc_child.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +93 -0
- package/dist/daemon/supervisor.js +666 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension_ui_bridge.d.ts +26 -0
- package/dist/extension_ui_bridge.js +341 -0
- package/dist/extension_ui_bridge.js.map +1 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +5750 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/mesh_result.d.ts +10 -0
- package/dist/mcp/mesh_result.js +42 -0
- package/dist/mcp/mesh_result.js.map +1 -0
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +373 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/mesh/canonical.d.ts +30 -0
- package/dist/mesh/canonical.js +63 -0
- package/dist/mesh/canonical.js.map +1 -0
- package/dist/mesh/client.d.ts +18 -0
- package/dist/mesh/client.js +127 -0
- package/dist/mesh/client.js.map +1 -0
- package/dist/mesh/encoding.d.ts +38 -0
- package/dist/mesh/encoding.js +217 -0
- package/dist/mesh/encoding.js.map +1 -0
- package/dist/mesh/self_revoke.d.ts +73 -0
- package/dist/mesh/self_revoke.js +407 -0
- package/dist/mesh/self_revoke.js.map +1 -0
- package/dist/mesh/siblings.d.ts +49 -0
- package/dist/mesh/siblings.js +159 -0
- package/dist/mesh/siblings.js.map +1 -0
- package/dist/mesh/types.d.ts +34 -0
- package/dist/mesh/types.js +11 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/mesh/verify.d.ts +17 -0
- package/dist/mesh/verify.js +86 -0
- package/dist/mesh/verify.js.map +1 -0
- package/dist/pairing/crypto.d.ts +8 -0
- package/dist/pairing/crypto.js +22 -0
- package/dist/pairing/crypto.js.map +1 -0
- package/dist/pairing/qr.d.ts +59 -0
- package/dist/pairing/qr.js +127 -0
- package/dist/pairing/qr.js.map +1 -0
- package/dist/pairing/storage.d.ts +120 -0
- package/dist/pairing/storage.js +614 -0
- package/dist/pairing/storage.js.map +1 -0
- package/dist/panel_bridge.d.ts +15 -0
- package/dist/panel_bridge.js +409 -0
- package/dist/panel_bridge.js.map +1 -0
- package/dist/paths.d.ts +39 -0
- package/dist/paths.js +51 -0
- package/dist/paths.js.map +1 -0
- package/dist/protocol/codec.d.ts +7 -0
- package/dist/protocol/codec.js +48 -0
- package/dist/protocol/codec.js.map +1 -0
- package/dist/protocol/types.d.ts +404 -0
- package/dist/protocol/types.js +2 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/rooms.d.ts +42 -0
- package/dist/rooms.js +78 -0
- package/dist/rooms.js.map +1 -0
- package/dist/session/bridge.d.ts +37 -0
- package/dist/session/bridge.js +134 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/broker.d.ts +189 -0
- package/dist/session/broker.js +527 -0
- package/dist/session/broker.js.map +1 -0
- package/dist/session/broker_remote.d.ts +74 -0
- package/dist/session/broker_remote.js +581 -0
- package/dist/session/broker_remote.js.map +1 -0
- package/dist/session/cwd_lock.d.ts +33 -0
- package/dist/session/cwd_lock.js +127 -0
- package/dist/session/cwd_lock.js.map +1 -0
- package/dist/session/debug_log.d.ts +3 -0
- package/dist/session/debug_log.js +32 -0
- package/dist/session/debug_log.js.map +1 -0
- package/dist/session/envelope.d.ts +33 -0
- package/dist/session/envelope.js +117 -0
- package/dist/session/envelope.js.map +1 -0
- package/dist/session/global_config.d.ts +33 -0
- package/dist/session/global_config.js +73 -0
- package/dist/session/global_config.js.map +1 -0
- package/dist/session/ipc.d.ts +27 -0
- package/dist/session/ipc.js +22 -0
- package/dist/session/ipc.js.map +1 -0
- package/dist/session/leader_election.d.ts +32 -0
- package/dist/session/leader_election.js +108 -0
- package/dist/session/leader_election.js.map +1 -0
- package/dist/session/local_config.d.ts +67 -0
- package/dist/session/local_config.js +193 -0
- package/dist/session/local_config.js.map +1 -0
- package/dist/session/mesh_node.d.ts +116 -0
- package/dist/session/mesh_node.js +596 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/peer.d.ts +139 -0
- package/dist/session/peer.js +474 -0
- package/dist/session/peer.js.map +1 -0
- package/dist/session/peer_inventory.d.ts +13 -0
- package/dist/session/peer_inventory.js +48 -0
- package/dist/session/peer_inventory.js.map +1 -0
- package/dist/session/peer_limits.d.ts +9 -0
- package/dist/session/peer_limits.js +24 -0
- package/dist/session/peer_limits.js.map +1 -0
- package/dist/session/rpc_envelope.d.ts +108 -0
- package/dist/session/rpc_envelope.js +221 -0
- package/dist/session/rpc_envelope.js.map +1 -0
- package/dist/session/rpc_inbound.d.ts +55 -0
- package/dist/session/rpc_inbound.js +136 -0
- package/dist/session/rpc_inbound.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +39 -0
- package/dist/session/setup_wizard.js +63 -0
- package/dist/session/setup_wizard.js.map +1 -0
- package/dist/session/tools.d.ts +24 -0
- package/dist/session/tools.js +272 -0
- package/dist/session/tools.js.map +1 -0
- package/dist/session/wizard.d.ts +13 -0
- package/dist/session/wizard.js +20 -0
- package/dist/session/wizard.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +52 -0
- package/dist/transport/peer_channel.js +145 -0
- package/dist/transport/peer_channel.js.map +1 -0
- package/dist/transport/pi_forward_client.d.ts +29 -0
- package/dist/transport/pi_forward_client.js +68 -0
- package/dist/transport/pi_forward_client.js.map +1 -0
- package/dist/transport/relay_client.d.ts +96 -0
- package/dist/transport/relay_client.js +210 -0
- package/dist/transport/relay_client.js.map +1 -0
- package/dist/ui/footer.d.ts +32 -0
- package/dist/ui/footer.js +34 -0
- package/dist/ui/footer.js.map +1 -0
- package/docs/daemon.md +289 -0
- package/package.json +92 -0
- package/service-templates/launchd.plist.template +35 -0
- package/service-templates/systemd.service.template +19 -0
- package/service-templates/task-launcher.vbs.template +10 -0
- package/service-templates/task-scheduler.xml.template +38 -0
- package/skills/agent-network/SKILL.md +310 -0
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-network
|
|
3
|
+
description: Use when the remote-pi mesh tools (`list_peers`, `agent_send`, and — on Claude — `get_messages`) are available. You are an agent (a Claude session or a Pi coding agent) connected to the remote-pi agent mesh over a local broker. This skill teaches how to discover who's online (`list_peers`), how to send messages with a delivery ACK (`agent_send`), how incoming messages reach you (via `get_messages` on Claude, or delivered into your turn on Pi), how to reply (echo `re`), and how to treat every peer address as an opaque routing key that must be echoed verbatim.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Network (remote-pi mesh)
|
|
7
|
+
|
|
8
|
+
You are connected to the **remote-pi agent mesh**. Other agents — other Claude
|
|
9
|
+
sessions, Pi coding agents on this machine, and agents on the Owner's other PCs
|
|
10
|
+
(reached through the relay) — can send you messages, and you can send messages
|
|
11
|
+
to them.
|
|
12
|
+
|
|
13
|
+
Read this to the end before acting. The protocol is **event-driven**, not
|
|
14
|
+
request/reply. Getting the receive model wrong leaves coordination broken.
|
|
15
|
+
|
|
16
|
+
**Your tools:** `list_peers` and `agent_send` always. On Claude you also have
|
|
17
|
+
`get_messages` (a Pi agent receives messages directly into its turn instead —
|
|
18
|
+
see below).
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## The most important rule: read your inbox every turn
|
|
23
|
+
|
|
24
|
+
You only ever receive messages addressed to you — the broker filters before
|
|
25
|
+
delivery. **If a message arrived, someone wanted your attention. Don't ignore
|
|
26
|
+
it.** How a message reaches you depends on your runtime:
|
|
27
|
+
|
|
28
|
+
- **Claude (MCP):** incoming messages are buffered. **At the start of every
|
|
29
|
+
turn, call `get_messages`** to drain and read them:
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
get_messages()
|
|
33
|
+
→ "[2026-05-30T12:00:01Z] from=backend re=<your-id>
|
|
34
|
+
id=<msg-id>
|
|
35
|
+
{ "shape": { "sub": "string", "exp": "number" } }"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
It returns all pending messages and clears the buffer (call once per turn),
|
|
39
|
+
or `(no messages)` when nothing is waiting — that's normal, keep working. A
|
|
40
|
+
channel push (`📨 Message from …`) may nudge you mid-session; still call
|
|
41
|
+
`get_messages` for the full structured payload.
|
|
42
|
+
|
|
43
|
+
- **Pi:** the runtime delivers each incoming message directly as a new turn
|
|
44
|
+
input the moment it arrives — no polling, no `get_messages`. You'll see it
|
|
45
|
+
prefixed `[agent-network] message from "<peer>" (id=…, re=…)`.
|
|
46
|
+
|
|
47
|
+
Either way: no wait/sleep/poll-loop. Replies to your own sends arrive on a
|
|
48
|
+
**later turn**, never inline.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## First thing in a new session: `list_peers`
|
|
53
|
+
|
|
54
|
+
Before sending anything, find out who's actually online:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
list_peers()
|
|
58
|
+
→ /Users/jo/acme/backend@backend
|
|
59
|
+
/Users/jo/acme/backend@reviewer
|
|
60
|
+
/Users/jo/acme/web@web
|
|
61
|
+
casa:/Users/jo/acme/api@api
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Synchronous (resolves in milliseconds — not another agent's turn). Use it:
|
|
65
|
+
|
|
66
|
+
- At the start of a session, to see what mesh you're in
|
|
67
|
+
- Before any `agent_send` whose target is uncertain
|
|
68
|
+
- To refresh — peers join and leave over time
|
|
69
|
+
|
|
70
|
+
**Presence is passive (pull, not push).** A peer joining or leaving does **not**
|
|
71
|
+
wake your turn. When your view feels stale, just call `list_peers` again — it's
|
|
72
|
+
the authoritative snapshot. Don't expect `peer_joined`/`peer_left` events.
|
|
73
|
+
|
|
74
|
+
**Each entry is a complete ADDRESS, not a bare name. Treat the entire value as
|
|
75
|
+
an opaque routing key.** Local values may look like `<cwd>@<name>` and remote
|
|
76
|
+
values may appear with a receiver-local PC alias, but that appearance is for
|
|
77
|
+
presentation only. A PC alias can contain percent-encoded bytes such as `%3A`
|
|
78
|
+
or `%25`, or a collision suffix containing `~`.
|
|
79
|
+
|
|
80
|
+
**Echo every address VERBATIM into `agent_send` (and as your `to` when
|
|
81
|
+
replying).** Never split it on `:` or `@`, decode or re-encode `%` bytes, remove
|
|
82
|
+
a `~` suffix, change case, normalize it, or construct it from a path, agent
|
|
83
|
+
name, or PC label. Copy the exact whole string returned by `list_peers` or
|
|
84
|
+
received in `from`. Parsing or rebuilding an address is unsafe for routing and
|
|
85
|
+
must never be used for a security decision.
|
|
86
|
+
|
|
87
|
+
The technical identity of a PC is its canonical 32-byte Ed25519 Pi public key.
|
|
88
|
+
PC aliases are receiver-local presentation and routing labels only: each
|
|
89
|
+
receiving PC allocates aliases for its siblings independently, so two PCs can
|
|
90
|
+
list the same sibling under different aliases. Never use an alias as proof of
|
|
91
|
+
identity or for authorization. The Relay currently permits a route when any
|
|
92
|
+
correctly signed Owner blob lists both canonical Pi keys; that does not prove
|
|
93
|
+
the Owner paired with or controls either Pi.
|
|
94
|
+
|
|
95
|
+
You are excluded from the result — no need to filter yourself out.
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Anatomy of a message (envelope)
|
|
100
|
+
|
|
101
|
+
Each message carries: `from`, `to`, `id`, `re`, and `body`.
|
|
102
|
+
|
|
103
|
+
| Field | Meaning |
|
|
104
|
+
|---|---|
|
|
105
|
+
| `from` | Sender's ADDRESS (`<cwd>@<name>`). Use it verbatim as your `to` when replying — never reconstruct it. |
|
|
106
|
+
| `to` | Your address (or `broadcast`, or a list of addresses including yours). |
|
|
107
|
+
| `id` | Unique id of this message. Echo it as `re` when you reply. |
|
|
108
|
+
| `re` | If set, this message is itself a REPLY to an earlier `id` of yours. Otherwise `null`. |
|
|
109
|
+
| `body` | Free-form content — string or JSON, sender's choice. |
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Sending: `agent_send` returns an ACK status
|
|
114
|
+
|
|
115
|
+
`agent_send({ to, body, re? })` is how you talk to peers. Every **unicast**
|
|
116
|
+
call returns a status telling you what happened at the recipient. **Always
|
|
117
|
+
inspect the status — it dictates what to do next.**
|
|
118
|
+
|
|
119
|
+
| Status | Means | What you do |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `received` | Broker delivered the envelope. Delivery is reliable — even if the peer is mid-turn, its harness enqueues the message for the next turn. | Move on. Any reply arrives later. |
|
|
122
|
+
| `denied` | Peer explicitly refused (or no such peer). | Do NOT retry. Report to the user. |
|
|
123
|
+
| `timeout` | No ACK (~5s). Transport error — broker down, or peer vanished. | Treat a reasonless timeout as transient. Retry once after ~10s, then escalate. |
|
|
124
|
+
|
|
125
|
+
For a trusted Relay failure on a cross-PC unicast, the public statuses remain
|
|
126
|
+
unchanged and the closed transport reason is returned in `details`:
|
|
127
|
+
|
|
128
|
+
- `offline` → `status: "timeout"`
|
|
129
|
+
- `not_authorized` or `bad_envelope` → `status: "denied"`
|
|
130
|
+
- genuine silence → `status: "timeout"` without a reason
|
|
131
|
+
|
|
132
|
+
Do not blindly retry `not_authorized` or `bad_envelope`; fix authorization or
|
|
133
|
+
the envelope instead. A trusted Relay error is consumed internally to settle
|
|
134
|
+
the pending send (or legacy request), not delivered as an ordinary inbox
|
|
135
|
+
reply. Forged or invalid reserved `_relay` / `transport_error` bodies do not
|
|
136
|
+
gain that authority and cannot settle pending operations.
|
|
137
|
+
|
|
138
|
+
For `to: "broadcast"` (or a name array), there's no single ACK — it's
|
|
139
|
+
fire-and-forget (`status: "sent"`).
|
|
140
|
+
|
|
141
|
+
**Delivery is reliable — no retry-on-busy.** A message sent to a peer that's
|
|
142
|
+
mid-turn is still delivered: the peer's harness queues it and processes it on
|
|
143
|
+
its upcoming turn. You never need to retry because a peer was busy. `re=<id>`
|
|
144
|
+
is purely **correlation** — set it so the recipient (and you) can thread an
|
|
145
|
+
answer to a question; it carries no special delivery semantics.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Receiving: replies arrive on a later turn
|
|
150
|
+
|
|
151
|
+
You **do not block** waiting for a reply. The model is event-driven:
|
|
152
|
+
|
|
153
|
+
1. You call `agent_send` → status `received`.
|
|
154
|
+
2. Your turn continues / ends.
|
|
155
|
+
3. **Later** the peer finishes its own work and sends a reply.
|
|
156
|
+
4. The reply reaches your inbox (via `get_messages` on Claude, or as a new turn
|
|
157
|
+
input on Pi), with `re` set to the `id` you originally sent.
|
|
158
|
+
|
|
159
|
+
### Walk-through
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
agent_send({ to: "/Users/jo/acme/backend@backend", body: { q: "what's the JWT shape?" } })
|
|
163
|
+
→ Delivered to backend # status received; remember the message id
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Your turn continues. A turn or two later you receive:
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
from=backend re=<your-id> id=<new-id>
|
|
170
|
+
{ "shape": { "sub": "string", "exp": "number", "roles": ["string"] } }
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
You correlate by `re` — it matches the send you made. Now you have your answer.
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Replying to a message
|
|
178
|
+
|
|
179
|
+
When you receive:
|
|
180
|
+
|
|
181
|
+
```
|
|
182
|
+
from=/home/jo/backlog@orchestrator id=abc-uuid re=(none)
|
|
183
|
+
{ "task": "Implement POST /auth/login" }
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Reply with `re` set to that `id`, and `to` set to the sender's `from`:
|
|
187
|
+
|
|
188
|
+
```
|
|
189
|
+
agent_send({
|
|
190
|
+
to: "/home/jo/backlog@orchestrator",
|
|
191
|
+
body: { status: "done", files_changed: [...] },
|
|
192
|
+
re: "abc-uuid"
|
|
193
|
+
})
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Without `re`, the sender gets your message but can't match it to the
|
|
197
|
+
question — coordination drifts. **Always echo `re` on a reply.**
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Asking multiple peers at once
|
|
202
|
+
|
|
203
|
+
Fire multiple `agent_send` in one turn — each returns its own ACK. Replies
|
|
204
|
+
arrive on future turns as peers finish.
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
agent_send({ to: "/repo/api@backend", body: { q: "JWT shape?" } }) // received
|
|
208
|
+
agent_send({ to: "/repo/web@frontend", body: { q: "theme tokens?" } }) // received
|
|
209
|
+
agent_send({ to: "/repo/ops@infra", body: { q: "ETA for Y?" } }) // received (queued if mid-turn)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Track which `id` maps to which question. Don't assume replies arrive in send
|
|
213
|
+
order — use `re` to identify what each reply answers.
|
|
214
|
+
|
|
215
|
+
---
|
|
216
|
+
|
|
217
|
+
## Cross-PC addressing (`<pc>:<cwd>@<name>`)
|
|
218
|
+
|
|
219
|
+
When the Owner has paired multiple PCs, remote peers have a receiver-local
|
|
220
|
+
`<pc>:` prefix. Send and reply with the complete address verbatim; never add
|
|
221
|
+
your own prefix. Relay routing keeps the same `received | denied | timeout`
|
|
222
|
+
semantics. A reasonless `denied` can mean a stale remote roster; refresh with
|
|
223
|
+
`list_peers`. Trusted Relay reasons in `details` map `offline` to `timeout` and
|
|
224
|
+
`not_authorized` / `bad_envelope` to `denied`; they settle the pending operation
|
|
225
|
+
internally, not as inbox replies.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Broadcast and multicast
|
|
230
|
+
|
|
231
|
+
- `to: "broadcast"` → every other peer **in your folder (same cwd)** — broadcast
|
|
232
|
+
is folder-scoped and local-only (it does NOT cross PCs or reach other folders).
|
|
233
|
+
`to: ["addr1", "addr2"]` → the listed addresses (echo them verbatim).
|
|
234
|
+
- Use for announcements ("wave 2 started", "I'm taking the lock on /contracts"),
|
|
235
|
+
never for questions (replies would be uncorrelated).
|
|
236
|
+
- Broadcast/multicast skip the ACK — status is `sent`, you don't know who
|
|
237
|
+
received it. For delivery confirmation, use individual unicast sends.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## When in doubt
|
|
242
|
+
|
|
243
|
+
- **Received a task you don't understand** → reply with `body.status:"error"`,
|
|
244
|
+
echoing the original `id` in `re`. Don't go silent.
|
|
245
|
+
- **Received a `re` you never sent** → late reply to something already wrapped
|
|
246
|
+
up. Ignore. Don't reply to a reply.
|
|
247
|
+
- **No messages ever arrive** → normal. You only receive when addressed. Keep
|
|
248
|
+
working; don't poll the broker.
|
|
249
|
+
- **Reasonless `timeout` on send** → broker restarting (failover), relay
|
|
250
|
+
silence, or a vanished peer. The client reconnects transparently in ~500ms;
|
|
251
|
+
retry once after a beat, then escalate. For a reason in `details`, follow the
|
|
252
|
+
mapping above; never blindly retry authorization or envelope failures.
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Legacy: `agent_request` (Pi only, deprecated)
|
|
257
|
+
|
|
258
|
+
On Pi you may see a tool called `agent_request` that takes a target + body and
|
|
259
|
+
**blocks the entire turn** waiting for the peer's content reply. It still
|
|
260
|
+
works but emits a deprecation warning. It blocks your turn (costs tokens and
|
|
261
|
+
wall time), gives no ACK signal, and pairs badly with parallel multi-peer
|
|
262
|
+
questions. **Migrate every `agent_request` to `agent_send`** + reading your
|
|
263
|
+
inbox on a later turn. (Claude has no `agent_request` — use `agent_send`.)
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## Single-page summary
|
|
268
|
+
|
|
269
|
+
1. **Every turn**: read your inbox first — `get_messages()` on Claude; on Pi
|
|
270
|
+
messages arrive as turn input automatically.
|
|
271
|
+
2. **Discover**: `list_peers()` returns opaque, receiver-local addresses.
|
|
272
|
+
Echo them verbatim; never parse, decode, normalize, or compose them.
|
|
273
|
+
Presence is pull-based.
|
|
274
|
+
3. **Send**: `agent_send({to, body, re?})` → inspect the status.
|
|
275
|
+
4. **Unicast status**: `received | denied | timeout`. `received` queues work
|
|
276
|
+
even for a mid-turn peer; abandon on `denied`; investigate `timeout`.
|
|
277
|
+
Closed Relay reasons in `details` map `offline` to `timeout` and
|
|
278
|
+
`not_authorized` / `bad_envelope` to `denied`. No retry-on-busy.
|
|
279
|
+
5. **Broadcast/multicast**: status `sent`. Fire-and-forget.
|
|
280
|
+
6. **Reply**: set `re` to their `id`, `to` to their `from` (the full address,
|
|
281
|
+
prefix and all). `re` is correlation only.
|
|
282
|
+
7. You never receive your own messages.
|
|
283
|
+
|
|
284
|
+
Re-read when in doubt.
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Mini-FAQ
|
|
289
|
+
|
|
290
|
+
**Q: Can I send a message to myself?**
|
|
291
|
+
A: No. `agent_send` refuses early (`status: "refused"`) when `to` matches your
|
|
292
|
+
own address (or a legacy bare self-name), and the broker drops unicast
|
|
293
|
+
self-loops as a second line of defense.
|
|
294
|
+
|
|
295
|
+
**Q: What if the peer never replies?**
|
|
296
|
+
A: Then you never see a reply. Your send returned `received` (the broker handed
|
|
297
|
+
it over); the peer just chose not to answer. There's no implicit timeout on
|
|
298
|
+
replies.
|
|
299
|
+
|
|
300
|
+
**Q: How many sends can I fire in one turn?**
|
|
301
|
+
A: No hard limit. But if you fire 10+ unicasts, question whether you should be a
|
|
302
|
+
worker (answer narrow) rather than an orchestrator (dispatch wide).
|
|
303
|
+
|
|
304
|
+
**Q: Is order preserved?**
|
|
305
|
+
A: Per-pair, yes — the broker is FIFO. Across pairs, replies arrive whenever the
|
|
306
|
+
senders finish. Don't assume reply order matches send order.
|
|
307
|
+
|
|
308
|
+
**Q: Can `body` be binary?**
|
|
309
|
+
A: Not directly. Base64 inside a string if you must. JSON is the intended
|
|
310
|
+
payload.
|