remote-pi 0.4.1 → 0.4.3

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,52 +1,80 @@
1
1
  ---
2
2
  name: agent-network
3
- description: Use when you (a Pi agent) are running inside a local agent session i.e., when the Pi footer shows "📡 <session-name>". This skill teaches how to discover who's online (`list_peers`), how to send messages with delivery status (`agent_send` + ACK), how replies arrive in a future turn, how cross-PC addressing works (`<pc_label>:<peer>`), and the retry matrix for the four ACK statuses.
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 cross-PC addressing works (`<pc_label>:<peer>`).
4
4
  ---
5
5
 
6
- # Agent Network (skill — event-driven message protocol)
6
+ # Agent Network (remote-pi mesh)
7
7
 
8
- You are connected to a **local agent session** over a Unix Domain Socket.
9
- Other Pi agents on the same machine, in the same session, can send you
10
- messages and you can send messages to them.
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.
11
12
 
12
- This skill teaches how to participate in that network reliably. Read it
13
- to the end before acting the protocol is **event-driven**, not
14
- request/reply, and getting that wrong leaves coordination broken.
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).
15
19
 
16
20
  ---
17
21
 
18
- ## The most important rule
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
+ ```
19
37
 
20
- **You only receive messages that were explicitly addressed to you.** The
21
- session broker filters before delivery. You will never see messages
22
- intended for other agents or "broadcast with `exclude_self`".
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.
23
42
 
24
- **Practical consequence**: if a message arrived in your inbox, someone
25
- wanted your attention. Don't ignore it.
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.
26
49
 
27
50
  ---
28
51
 
29
- ## First thing to do in a new session: `list_peers`
52
+ ## First thing in a new session: `list_peers`
30
53
 
31
- Before you send anything, find out who's actually online. `list_peers` is
32
- a cheap metadata tool that returns the current inventory:
54
+ Before sending anything, find out who's actually online:
33
55
 
34
56
  ```
35
57
  list_peers()
36
- { peers: ["backend", "frontend", "casa:agent-1", "trab:worker"] }
58
+ → backend
59
+ frontend
60
+ casa:agent-1
61
+ trab:worker
37
62
  ```
38
63
 
39
- The reply is **synchronous** (broker resolves in milliseconds — this is
40
- not a turn of another agent). Use it freely:
64
+ Synchronous (resolves in milliseconds — not another agent's turn). Use it:
41
65
 
42
66
  - At the start of a session, to see what mesh you're in
43
- - After receiving `peer_joined` / `peer_left` to refresh
44
67
  - Before any `agent_send` whose target name 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.
45
73
 
46
74
  **Entry shape:**
47
- - `backend` → local peer (this machine, same UDS broker)
48
- - `casa:agent-1` → cross-PC peer on the Pi labeled `casa` (this Owner's
49
- other machine, reached through the relay)
75
+ - `backend` → local peer (this machine, same broker)
76
+ - `casa:agent-1` → cross-PC peer on the PC labeled `casa` (the Owner's other
77
+ machine, reached through the relay)
50
78
 
51
79
  You are excluded from the result — no need to filter yourself out.
52
80
 
@@ -54,112 +82,79 @@ You are excluded from the result — no need to filter yourself out.
54
82
 
55
83
  ## Anatomy of a message (envelope)
56
84
 
57
- Every message has 5 fields:
58
-
59
- ```json
60
- {
61
- "from": "orchestrator",
62
- "to": "backend",
63
- "id": "uuid-v7",
64
- "re": null,
65
- "body": <message contents>
66
- }
67
- ```
85
+ Each message carries: `from`, `to`, `id`, `re`, and `body`.
68
86
 
69
87
  | Field | Meaning |
70
88
  |---|---|
71
- | `from` | Who sent it. Use this to know who to reply to. |
72
- | `to` | You (or "broadcast", or a list of names including yours). |
73
- | `id` | Unique identifier of this specific message. |
74
- | `re` | If this message is a REPLY to another, echoes that one's `id`. Otherwise `null`. |
75
- | `body` | Free-form content. String or JSON object, sender's choice. |
89
+ | `from` | Who sent it. Use this verbatim as your `to` when replying. |
90
+ | `to` | You (or `broadcast`, or a list of names including yours). |
91
+ | `id` | Unique id of this message. Echo it as `re` when you reply. |
92
+ | `re` | If set, this message is itself a REPLY to an earlier `id` of yours. Otherwise `null`. |
93
+ | `body` | Free-form content string or JSON, sender's choice. |
76
94
 
77
95
  ---
78
96
 
79
- ## How sending works: `agent_send` returns an ACK status
97
+ ## Sending: `agent_send` returns an ACK status
80
98
 
81
- `agent_send` is the **only** tool you need to talk to peers. Every
82
- unicast call returns a status that tells you what happened at the
83
- recipient. **Always inspect the status — it dictates what to do next.**
99
+ `agent_send({ to, body, re? })` is how you talk to peers. Every **unicast**
100
+ call returns a status telling you what happened at the recipient. **Always
101
+ inspect the status — it dictates what to do next.**
84
102
 
85
- | Status | What it means | What you do |
103
+ | Status | Means | What you do |
86
104
  |---|---|---|
87
- | `received` | Peer was idle, broker handed the envelope over, peer will process it in its upcoming turn. | Move on. The reply (if any) arrives later in your inbox as a normal envelope with `re=<your-send-id>`. |
88
- | `busy` | Peer is mid-turn envelope **dropped**. | Retry 2× with backoff (2s, 5s). If still busy, abandon or escalate to the human. You own the retry. |
89
- | `denied` | Peer explicitly refused the message. | Do NOT retry. Report to the user. |
90
- | `timeout` | No ACK in 5s. Transport error — broker may be down, peer disappeared mid-handshake. | Treat as transient. Retry once after a longer delay (10s+), then escalate. |
91
- | `sent` | You used `to: "broadcast"` or an array. There is no single ACK target. | Move on. Broadcasts are fire-and-forget. |
92
- | `refused` | The tool refused your call locally (e.g., you tried to message yourself, or you're not in a session). | Fix the call. Don't retry the same arguments. |
93
-
94
- `busy` is the most common non-trivial answer. Two **new** messages aimed
95
- at the same peer in quick succession will see the second one as `busy`
96
- — the peer can only be processing one turn at a time.
97
-
98
- **Replies are exempt from busy gating.** A message with `re=<some-id>`
99
- (an answer to something the recipient asked) is always delivered,
100
- because it resolves pending state at the recipient rather than starting
101
- a new turn for them. So if you fan out questions to several peers in
102
- the same turn, every peer's reply will reach you even when you're still
103
- processing — they all flow into your inbox for the next turn.
105
+ | `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. |
106
+ | `denied` | Peer explicitly refused (or no such peer). | Do NOT retry. Report to the user. |
107
+ | `timeout` | No ACK (~5s). Transport error — broker down, or peer vanished. | Treat as transient. Retry once after ~10s, then escalate. |
104
108
 
105
- ---
109
+ For `to: "broadcast"` (or a name array), there's no single ACK — it's
110
+ fire-and-forget (`status: "sent"`).
106
111
 
107
- ## How receiving works: replies arrive in a future turn
112
+ **Delivery is reliable no retry-on-busy.** A message sent to a peer that's
113
+ mid-turn is still delivered: the peer's harness queues it and processes it on
114
+ its upcoming turn. You never need to retry because a peer was busy. `re=<id>`
115
+ is purely **correlation** — set it so the recipient (and you) can thread an
116
+ answer to a question; it carries no special delivery semantics.
108
117
 
109
- You **do not block waiting** for a peer's content reply. The model is
110
- push-based:
118
+ ---
111
119
 
112
- 1. You call `agent_send` status `received`.
113
- 2. Your turn continues. You might do other work, or finish.
114
- 3. **Later** — possibly several turns later — the peer finishes its
115
- own turn, processes your message, and sends a reply.
116
- 4. The reply lands in your inbox as a normal envelope. You see it on
117
- your next turn input, with `re` set to the `id` you sent earlier.
120
+ ## Receiving: replies arrive on a later turn
118
121
 
119
- You do not need a wait/poll/sleep. The Pi runtime delivers the reply as
120
- a new turn input the moment it arrives.
122
+ You **do not block** waiting for a reply. The model is event-driven:
121
123
 
122
- ### Concrete walk-through
124
+ 1. You call `agent_send` → status `received`.
125
+ 2. Your turn continues / ends.
126
+ 3. **Later** the peer finishes its own work and sends a reply.
127
+ 4. The reply reaches your inbox (via `get_messages` on Claude, or as a new turn
128
+ input on Pi), with `re` set to the `id` you originally sent.
123
129
 
124
- You (name: `orq`) ask `backend` a question:
130
+ ### Walk-through
125
131
 
126
132
  ```
127
133
  agent_send({ to: "backend", body: { q: "what's the JWT shape?" } })
128
- { status: "received", target: "backend" }
134
+ Delivered to backend # status received; remember the message id
129
135
  ```
130
136
 
131
- You finish your current turn (maybe reply to the user, maybe do other
132
- sends). Turn ends.
133
-
134
- A few seconds later, the runtime hands you a new turn with this input:
137
+ Your turn continues. A turn or two later you receive:
135
138
 
136
139
  ```
137
- [agent-network] message from "backend" (id=<new-id>, re=<your-id>):
140
+ from=backend re=<your-id> id=<new-id>
138
141
  { "shape": { "sub": "string", "exp": "number", "roles": ["string"] } }
139
- (This is a reply to a previous message of yours.)
140
142
  ```
141
143
 
142
- You correlate by looking at `re` — it matches the `id` you got back
143
- when you originally sent. Now you have your answer. Use it.
144
+ You correlate by `re` — it matches the send you made. Now you have your answer.
144
145
 
145
146
  ---
146
147
 
147
- ## How to REPLY when you receive a message
148
+ ## Replying to a message
148
149
 
149
- You receive:
150
+ When you receive:
150
151
 
151
- ```json
152
- {
153
- "from": "orchestrator",
154
- "to": "backend",
155
- "id": "abc-uuid",
156
- "re": null,
157
- "body": { "task": "Implement POST /auth/login" }
158
- }
152
+ ```
153
+ from=orchestrator id=abc-uuid re=(none)
154
+ { "task": "Implement POST /auth/login" }
159
155
  ```
160
156
 
161
- When you have something to say back (an answer, an error, a status),
162
- you send back another envelope **with `re` set to the original `id`**:
157
+ Reply with `re` set to that `id`, and `to` set to the sender's `from`:
163
158
 
164
159
  ```
165
160
  agent_send({
@@ -169,240 +164,128 @@ agent_send({
169
164
  })
170
165
  ```
171
166
 
172
- The orchestrator correlates the reply via `re === "abc-uuid"`. Without
173
- `re`, they receive your message but cannot match it against the
174
- question — and the coordination drifts. **Always echo `re` on a reply.**
167
+ Without `re`, the sender gets your message but can't match it to the
168
+ question coordination drifts. **Always echo `re` on a reply.**
175
169
 
176
170
  ---
177
171
 
178
172
  ## Asking multiple peers at once
179
173
 
180
- You frequently need info from several agents before you can proceed.
181
- You can fire multiple `agent_send` in the same turn — each returns its
182
- own ACK status. Then your turn ends, and the replies arrive in future
183
- turns as they come in.
174
+ Fire multiple `agent_send` in one turn each returns its own ACK. Replies
175
+ arrive on future turns as peers finish.
184
176
 
185
- ```typescript
186
- // In one turn:
187
- agent_send({ to: "backend", body: { q: "JWT shape?" } }); // -> received
188
- agent_send({ to: "frontend", body: { q: "theme tokens?" } }); // -> received
189
- agent_send({ to: "infra", body: { q: "ETA for Y?" } }); // -> busy — retry next turn
177
+ ```
178
+ agent_send({ to: "backend", body: { q: "JWT shape?" } }) // received
179
+ agent_send({ to: "frontend", body: { q: "theme tokens?" } }) // received
180
+ agent_send({ to: "infra", body: { q: "ETA for Y?" } }) // received (queued if mid-turn)
190
181
  ```
191
182
 
192
- In a later turn, you might see two of the three replies; the third
193
- might arrive a turn after that. Track which `id` corresponds to which
194
- question (the ACK return shape includes `id`, store it).
195
-
196
- Don't assume replies arrive in send order. Use `re` to identify what
197
- each reply is for.
198
-
199
- ### When to retry
200
-
201
- A `busy` peer might be free in a few seconds. The skill recommends:
202
-
203
- - Try once → `busy` → wait ~2s, try again
204
- - Still `busy` → wait ~5s, try again
205
- - Still `busy` → abandon (report to human) or escalate to orchestrator
206
-
207
- Retries are **your** responsibility as the sender. The broker does not
208
- queue messages.
183
+ Track which `id` maps to which question. Don't assume replies arrive in send
184
+ order use `re` to identify what each reply answers.
209
185
 
210
186
  ---
211
187
 
212
188
  ## Cross-PC addressing (`<pc_label>:<peer>`)
213
189
 
214
- When the Owner has paired multiple Pis (e.g. "casa" and "trab"), peers
215
- on the other machine appear in `list_peers` with a prefix:
190
+ When the Owner has paired multiple PCs, remote peers appear with a prefix:
216
191
 
217
192
  ```
218
- { peers: ["backend", "frontend", "casa:agent-1", "trab:worker"] }
193
+ list_peers() backend frontend casa:agent-1 trab:worker
219
194
  ```
220
195
 
221
- To send to a remote peer, use the prefixed name verbatim:
196
+ Send to a remote peer with the prefixed name verbatim:
222
197
 
223
198
  ```
224
199
  agent_send({ to: "casa:agent-1", body: { ... } })
225
200
  ```
226
201
 
227
- The transport (relay) routes it across the mesh; the cross-PC peer
228
- receives it as if it were local. Behavior matches single-PC:
229
- `received | busy | denied | timeout` semantics are identical.
230
-
231
- When you **reply** to a cross-PC message, use the original sender's
232
- `from` verbatim — it already carries the prefix:
233
-
234
- ```
235
- Incoming: { from: "casa:sess-3", to: "agent-1", id: "abc", re: null, ... }
236
- Reply: agent_send({ to: "casa:sess-3", body: {...}, re: "abc" })
237
- ```
238
-
239
- You do NOT prefix your own outgoing `from` — that rewrite happens at the
240
- broker layer.
202
+ The relay routes it across the mesh; `received | denied | timeout` semantics
203
+ are identical to local. When you **reply** to a cross-PC message, use the
204
+ sender's `from` verbatim (it already carries the prefix) as your `to`. You
205
+ never prefix your own name — the broker handles that.
241
206
 
242
- **Failure modes specific to cross-PC:**
243
-
244
- - `denied`: remote PC's broker has no peer by that local name (peer left
245
- recently, or your cache is stale call `list_peers` again)
246
- - `timeout`: the other PC is offline or the relay is unreachable. The
247
- relay also synthesises a `transport_error` envelope (with `from:
248
- "_relay"`) for offline/not_authorized/bad_envelope — you'll see it in
249
- the inbox as a reply with `re=<your-send-id>` and `body.type:
250
- "transport_error"`. Treat exactly like timeout.
207
+ Cross-PC failure notes:
208
+ - `denied` → the remote broker has no peer by that name (left, or stale cache
209
+ call `list_peers` again).
210
+ - `timeout` the other PC is offline or the relay is unreachable. The relay
211
+ may also synthesise a `transport_error` reply (`from: "_relay"`,
212
+ `body.type: "transport_error"`) treat exactly like timeout.
251
213
 
252
214
  ---
253
215
 
254
216
  ## Broadcast and multicast
255
217
 
256
- `to: "broadcast"` delivers to every other peer. `to: ["a", "b"]`
257
- delivers to the listed names.
258
-
259
- - Announcements: "wave 2 started", "I'm taking the lock on /contracts"
260
- - Questions: nobody knows who's supposed to answer — replies will be
261
- uncorrelated
262
-
263
- Broadcast/multicast skip the ACK protocol entirely — the tool returns
264
- `status: "sent"` immediately. You don't know who received it. If you
265
- need delivery confirmation, use multiple unicast sends.
218
+ - `to: "broadcast"` every other peer. `to: ["a", "b"]` → the listed names.
219
+ - Use for announcements ("wave 2 started", "I'm taking the lock on /contracts"),
220
+ never for questions (replies would be uncorrelated).
221
+ - Broadcast/multicast skip the ACK status is `sent`, you don't know who
222
+ received it. For delivery confirmation, use individual unicast sends.
266
223
 
267
224
  ---
268
225
 
269
- ## Staying current: peer_joined / peer_left + `list_peers`
226
+ ## When in doubt
270
227
 
271
- You may receive, at any time, `system` events from the broker:
272
-
273
- ```json
274
- { "from": "broker", "to": "backend", "id": "uuid", "re": null,
275
- "body": { "type": "peer_joined", "name": "frontend" } }
276
- ```
277
-
278
- ```json
279
- { "from": "broker", "to": "backend", "id": "uuid", "re": null,
280
- "body": { "type": "peer_left", "name": "frontend" } }
281
- ```
282
-
283
- Use these to track who's online. Don't ask peers you know are offline.
284
-
285
- If you missed events (just woke up, or your view feels stale), call
286
- `list_peers` — it returns the authoritative snapshot in milliseconds.
287
-
288
- Do **not** send a `list_peers` envelope to the broker via `agent_send`.
289
- That's the old pre-tool pattern: it worked, but the reply arrived in a
290
- future turn and the ACK status didn't carry the peer list. The dedicated
291
- `list_peers` tool is strictly better — synchronous, typed return.
292
-
293
- ---
294
-
295
- ## Situations where you're in doubt
296
-
297
- ### "I received a task I don't understand"
298
-
299
- Reply with `status: "error"` in the body, echoing the original `id` in
300
- `re`. Don't go silent.
301
-
302
- ### "I received a message with `re` set, but I never sent that question"
303
-
304
- Late reply to something that already wrapped up. Ignore. Don't reply
305
- to a reply.
306
-
307
- ### "I'm in a session but no message ever arrives"
308
-
309
- Normal. You only receive when someone addresses you. Keep working on
310
- the current task. Don't poll the broker.
311
-
312
- ### "I sent something but got `timeout`"
313
-
314
- The broker didn't ACK in 5s. Either the broker is restarting (failover)
315
- or the peer disappeared between registration and delivery. Retry once
316
- after ~10s; if still timeout, treat as transport failure and escalate.
317
-
318
- ### "The leader died (peer_left from `broker` for the leader)"
319
-
320
- The transport layer automatically promotes another peer to leader. Your
321
- client reconnects transparently in ~500ms. During that window,
322
- `agent_send` may return `timeout` — retry once after a beat before
323
- giving up.
228
+ - **Received a task you don't understand** reply with `body.status:"error"`,
229
+ echoing the original `id` in `re`. Don't go silent.
230
+ - **Received a `re` you never sent** → late reply to something already wrapped
231
+ up. Ignore. Don't reply to a reply.
232
+ - **No messages ever arrive** normal. You only receive when addressed. Keep
233
+ working; don't poll the broker.
234
+ - **`timeout` on send** → broker restarting (failover) or peer vanished. The
235
+ client reconnects transparently in ~500ms; retry once after a beat, then
236
+ escalate.
324
237
 
325
238
  ---
326
239
 
327
- ## Legacy: `agent_request` is deprecated
328
-
329
- You may see references to a tool called `agent_request` that takes a
330
- target + body and **blocks the entire turn** waiting for the peer's
331
- content reply. It still works, but emits a deprecation warning on use
332
- and will be removed.
240
+ ## Legacy: `agent_request` (Pi only, deprecated)
333
241
 
334
- **Why deprecated:**
335
-
336
- - Blocks your turn while a peer thinks costs tokens and wall time
337
- - No ACK signal you can't tell `busy` from `pondering` from `gone`
338
- - Pairs badly with parallel multi-peer questions
339
-
340
- **Migration:** every `agent_request` call becomes an `agent_send`. The
341
- reply arrives in a future turn (see the walk-through above). Treat the
342
- inbox as your event loop, not your call stack.
242
+ On Pi you may see a tool called `agent_request` that takes a target + body and
243
+ **blocks the entire turn** waiting for the peer's content reply. It still
244
+ works but emits a deprecation warning. It blocks your turn (costs tokens and
245
+ wall time), gives no ACK signal, and pairs badly with parallel multi-peer
246
+ questions. **Migrate every `agent_request` to `agent_send`** + reading your
247
+ inbox on a later turn. (Claude has no `agent_request` — use `agent_send`.)
343
248
 
344
249
  ---
345
250
 
346
251
  ## Single-page summary
347
252
 
348
- 1. **Discover first**: `list_peers()` returns `{peers: string[]}`
349
- locals plus `<pc>:<peer>` cross-PC entries. Synchronous. Self-excluded.
350
- 2. **Send tool**: `agent_send({to, body, re?})`. Returns `{status, ...}`
351
- always inspect.
352
- 3. **Unicast status**: `received | busy | denied | timeout`. Retry on
353
- `busy` with backoff; abandon on `denied`; investigate on `timeout`.
354
- 4. **Broadcast/multicast**: status is `sent`. Fire-and-forget.
355
- 5. **Replies**: come back **in a future turn** as a normal inbound
356
- envelope with `re=<your-send-id>`. Correlate by `re`.
357
- 6. When YOU reply to a peer, set `re` to their original `id`, and use
358
- their `from` verbatim as your `to` (including any `<pc>:` prefix).
359
- 7. You never receive your own messages. The broker filters.
360
- 8. The broker does not queue. If a peer is busy, your message is
361
- **dropped** you own the retry.
362
- 9. `agent_request` is deprecated. Migrate to `agent_send` + inbox.
363
-
364
- That's the whole protocol. Re-read it when in doubt.
253
+ 1. **Every turn**: read your inbox first — `get_messages()` on Claude; on Pi
254
+ messages arrive as turn input automatically.
255
+ 2. **Discover**: `list_peers()` locals + `<pc>:<peer>` cross-PC. Synchronous,
256
+ self-excluded. Presence is pull-based join/leave don't wake you.
257
+ 3. **Send**: `agent_send({to, body, re?})` inspect the status.
258
+ 4. **Unicast status**: `received | denied | timeout`. Delivery is reliable —
259
+ `received` even if the peer is mid-turn (its harness queues it); abandon on
260
+ `denied`; investigate on `timeout`. No retry-on-busy.
261
+ 5. **Broadcast/multicast**: status `sent`. Fire-and-forget.
262
+ 6. **Reply**: set `re` to their `id`, `to` to their `from` (prefix and all).
263
+ `re` is correlation only.
264
+ 7. You never receive your own messages.
265
+
266
+ Re-read when in doubt.
365
267
 
366
268
  ---
367
269
 
368
270
  ## Mini-FAQ
369
271
 
370
272
  **Q: Can I send a message to myself?**
371
- A: No. `agent_send` refuses early with `status: "refused"` when `to`
372
- matches your assigned name. The broker also drops unicast self-loops
373
- as a second line of defense.
273
+ A: No. `agent_send` refuses early (`status: "refused"`) when `to` matches your
274
+ own name, and the broker drops unicast self-loops as a second line of defense.
374
275
 
375
- **Q: What if the peer never replies to my message?**
376
- A: Then you never see a reply. There is no implicit timeout your
377
- own send returned `received` (the broker handed it over), the peer
378
- just chose not to answer. If a reply is important, the agent-network
379
- skill in the peer's process should make them reply. If they're a
380
- non-Pi process that just listens, you live with the silence.
276
+ **Q: What if the peer never replies?**
277
+ A: Then you never see a reply. Your send returned `received` (the broker handed
278
+ it over); the peer just chose not to answer. There's no implicit timeout on
279
+ replies.
381
280
 
382
281
  **Q: How many sends can I fire in one turn?**
383
- A: No hard limit. But if you fire 10+ unicasts, question whether
384
- you should be a worker instead of an orchestrator. Workers answer
385
- narrow; orchestrators dispatch wide.
282
+ A: No hard limit. But if you fire 10+ unicasts, question whether you should be a
283
+ worker (answer narrow) rather than an orchestrator (dispatch wide).
386
284
 
387
285
  **Q: Is order preserved?**
388
- A: Per-pair, yes — the broker is FIFO. Across pairs, replies arrive
389
- whenever the senders finish. Don't assume reply order matches send
390
- order.
286
+ A: Per-pair, yes — the broker is FIFO. Across pairs, replies arrive whenever the
287
+ senders finish. Don't assume reply order matches send order.
391
288
 
392
289
  **Q: Can `body` be binary?**
393
- A: Not directly. Use base64 inside a string if you must. JSON is the
394
- intended payload.
395
-
396
- **Q: Can I disconnect any time?**
397
- A: Yes. The transport sends `peer_left` automatically when you close.
398
- Other agents see you go.
399
-
400
- ---
401
-
402
- ## See also
403
-
404
- - [`plan/19-agent-network.md`](../plan/19-agent-network.md) — original protocol design
405
- - [`plan/25-pc-mesh-bootstrap.md`](../plan/25-pc-mesh-bootstrap.md) — ACK protocol motivation + Wave 0 + cross-PC plans
406
- - `~/.pi/remote/sessions/<name>/audit.jsonl` — append-only log of every
407
- envelope that passed through the broker, with `ack_status` per entry
408
- for cross-checking what really happened.
290
+ A: Not directly. Base64 inside a string if you must. JSON is the intended
291
+ payload.