remote-pi 0.2.0 → 0.4.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/README.md +44 -0
- package/dist/actions/handlers.d.ts +116 -0
- package/dist/actions/handlers.js +152 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +25 -0
- package/dist/actions/registry.js +34 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.js +43 -1
- package/dist/bin/supervisord.js.map +1 -1
- package/dist/commands/builtin_mirror.d.ts +58 -0
- package/dist/commands/builtin_mirror.js +71 -0
- package/dist/commands/builtin_mirror.js.map +1 -0
- package/dist/commands/list_commands.d.ts +60 -0
- package/dist/commands/list_commands.js +73 -0
- package/dist/commands/list_commands.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +8 -0
- package/dist/daemon/control_protocol.js.map +1 -1
- package/dist/daemon/rpc_child.d.ts +24 -0
- package/dist/daemon/rpc_child.js +41 -2
- package/dist/daemon/rpc_child.js.map +1 -1
- package/dist/daemon/supervisor.d.ts +11 -0
- package/dist/daemon/supervisor.js +56 -4
- package/dist/daemon/supervisor.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +753 -209
- package/dist/index.js.map +1 -1
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +207 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/pairing/storage.js +12 -10
- package/dist/pairing/storage.js.map +1 -1
- package/dist/protocol/types.d.ts +103 -0
- package/dist/session/bridge.d.ts +39 -0
- package/dist/session/bridge.js +41 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/mesh_node.d.ts +123 -0
- package/dist/session/mesh_node.js +203 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +6 -23
- package/dist/session/setup_wizard.js +6 -15
- package/dist/session/setup_wizard.js.map +1 -1
- package/dist/session/tools.js +0 -6
- package/dist/session/tools.js.map +1 -1
- package/dist/transport/relay_client.d.ts +8 -0
- package/dist/transport/relay_client.js +50 -2
- package/dist/transport/relay_client.js.map +1 -1
- package/package.json +4 -2
- package/skills/claude-agent-network/SKILL.md +239 -0
|
@@ -17,40 +17,23 @@ export interface WizardUI {
|
|
|
17
17
|
export interface WizardDefaults {
|
|
18
18
|
agent_name: string;
|
|
19
19
|
use_relay: boolean;
|
|
20
|
-
/**
|
|
21
|
-
* Default for the "Enable daemon mode?" prompt. Doesn't persist in
|
|
22
|
-
* `LocalConfig` — daemon enablement is OS-level state (service unit on
|
|
23
|
-
* disk), not config. The wizard surfaces it so first-time users get
|
|
24
|
-
* the option without having to discover `/remote-pi install` later.
|
|
25
|
-
*/
|
|
26
|
-
enable_daemon?: boolean;
|
|
27
20
|
}
|
|
28
21
|
/**
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* command) — NOT a persisted config field.
|
|
32
|
-
*/
|
|
33
|
-
export interface WizardResult extends LocalConfig {
|
|
34
|
-
enable_daemon: boolean;
|
|
35
|
-
}
|
|
36
|
-
/**
|
|
37
|
-
* Runs the 3-question setup wizard. Returns the chosen config + a
|
|
38
|
-
* `enable_daemon` flag on confirm, or null when the user cancels any
|
|
39
|
-
* prompt.
|
|
22
|
+
* Runs the 2-question setup wizard. Returns the chosen config on confirm, or
|
|
23
|
+
* null when the user cancels any prompt.
|
|
40
24
|
*
|
|
41
25
|
* Prompts:
|
|
42
26
|
* 1. Agent name (default: parent/folder of cwd)
|
|
43
27
|
* 2. Use the relay on this terminal? (yes/no) — gates connection to the
|
|
44
28
|
* remote mesh (mobile devices + other PCs over the relay). "No" means
|
|
45
29
|
* local-only: this Pi joins the UDS mesh but doesn't open WSS.
|
|
46
|
-
* 3. Enable daemon mode? (yes/no) — installs the system service so
|
|
47
|
-
* agents you `/remote-pi create` keep running 24/7 in the background.
|
|
48
|
-
* Symlinks the `remote-pi` + `pi-supervisord` CLIs into
|
|
49
|
-
* `~/.local/bin/` so the shell can address daemons by id.
|
|
50
30
|
* Final: review + confirm "Save and activate?" yes/no
|
|
51
31
|
*
|
|
32
|
+
* Daemon mode (run agents 24/7 via systemd/launchd) is intentionally NOT in
|
|
33
|
+
* the wizard — it's an explicit, separate opt-in via `/remote-pi install`.
|
|
34
|
+
*
|
|
52
35
|
* The local UDS mesh is always single per machine ("local" session) — no
|
|
53
36
|
* session question. All Pis on the same machine see each other through
|
|
54
37
|
* the same broker.
|
|
55
38
|
*/
|
|
56
|
-
export declare function runSetupWizard(ui: WizardUI, defaults: WizardDefaults): Promise<
|
|
39
|
+
export declare function runSetupWizard(ui: WizardUI, defaults: WizardDefaults): Promise<LocalConfig | null>;
|
|
@@ -2,21 +2,19 @@ const YES = "Yes";
|
|
|
2
2
|
const NO = "No";
|
|
3
3
|
const CANCEL_TOKEN = "__cancel__";
|
|
4
4
|
/**
|
|
5
|
-
* Runs the
|
|
6
|
-
*
|
|
7
|
-
* prompt.
|
|
5
|
+
* Runs the 2-question setup wizard. Returns the chosen config on confirm, or
|
|
6
|
+
* null when the user cancels any prompt.
|
|
8
7
|
*
|
|
9
8
|
* Prompts:
|
|
10
9
|
* 1. Agent name (default: parent/folder of cwd)
|
|
11
10
|
* 2. Use the relay on this terminal? (yes/no) — gates connection to the
|
|
12
11
|
* remote mesh (mobile devices + other PCs over the relay). "No" means
|
|
13
12
|
* local-only: this Pi joins the UDS mesh but doesn't open WSS.
|
|
14
|
-
* 3. Enable daemon mode? (yes/no) — installs the system service so
|
|
15
|
-
* agents you `/remote-pi create` keep running 24/7 in the background.
|
|
16
|
-
* Symlinks the `remote-pi` + `pi-supervisord` CLIs into
|
|
17
|
-
* `~/.local/bin/` so the shell can address daemons by id.
|
|
18
13
|
* Final: review + confirm "Save and activate?" yes/no
|
|
19
14
|
*
|
|
15
|
+
* Daemon mode (run agents 24/7 via systemd/launchd) is intentionally NOT in
|
|
16
|
+
* the wizard — it's an explicit, separate opt-in via `/remote-pi install`.
|
|
17
|
+
*
|
|
20
18
|
* The local UDS mesh is always single per machine ("local" session) — no
|
|
21
19
|
* session question. All Pis on the same machine see each other through
|
|
22
20
|
* the same broker.
|
|
@@ -30,23 +28,16 @@ export async function runSetupWizard(ui, defaults) {
|
|
|
30
28
|
if (!useRelayChoice)
|
|
31
29
|
return null;
|
|
32
30
|
const auto_start_relay = useRelayChoice === YES;
|
|
33
|
-
ui.notify?.("Daemon mode runs Pi agents 24/7 in the background (systemd on Linux, launchd on macOS) so they can answer your phone or sibling PCs while your terminal is closed. Also adds `remote-pi` and `pi-supervisord` to your $PATH so you can drive them from any shell.", "info");
|
|
34
|
-
const enableDaemonDefault = defaults.enable_daemon ?? false;
|
|
35
|
-
const enableDaemonChoice = await ui.select("Enable daemon mode? (run agents 24/7 in background)", enableDaemonDefault ? [YES, NO] : [NO, YES]);
|
|
36
|
-
if (!enableDaemonChoice)
|
|
37
|
-
return null;
|
|
38
|
-
const enable_daemon = enableDaemonChoice === YES;
|
|
39
31
|
// Review + confirm
|
|
40
32
|
const summary = [
|
|
41
33
|
` Agent name: ${agent_name}`,
|
|
42
34
|
` Use relay: ${auto_start_relay ? YES : NO}`,
|
|
43
|
-
` Daemon mode: ${enable_daemon ? YES : NO}`,
|
|
44
35
|
].join("\n");
|
|
45
36
|
ui.notify?.(`Summary:\n${summary}`, "info");
|
|
46
37
|
const confirm = await ui.select("Save and activate?", [YES, NO]);
|
|
47
38
|
if (confirm !== YES)
|
|
48
39
|
return null;
|
|
49
|
-
return { agent_name, auto_start_relay
|
|
40
|
+
return { agent_name, auto_start_relay };
|
|
50
41
|
}
|
|
51
42
|
/**
|
|
52
43
|
* Asks the user for free text. The Pi SDK's `ui.input` does not pre-fill the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup_wizard.js","sourceRoot":"","sources":["../../src/session/setup_wizard.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"setup_wizard.js","sourceRoot":"","sources":["../../src/session/setup_wizard.ts"],"names":[],"mappings":"AAqBA,MAAM,GAAG,GAAG,KAAK,CAAC;AAClB,MAAM,EAAE,GAAG,IAAI,CAAC;AAChB,MAAM,YAAY,GAAG,YAAY,CAAC;AAElC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,EAAY,EACZ,QAAwB;IAExB,MAAM,UAAU,GAAG,MAAM,QAAQ,CAC/B,EAAE,EACF,aAAa,EACb,QAAQ,CAAC,UAAU,CACpB,CAAC;IACF,IAAI,UAAU,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAErC,EAAE,CAAC,MAAM,EAAE,CACT,6JAA6J,EAC7J,MAAM,CACP,CAAC;IACF,MAAM,cAAc,GAAG,MAAM,EAAE,CAAC,MAAM,CACpC,8EAA8E,EAC9E,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,CAC3C,CAAC;IACF,IAAI,CAAC,cAAc;QAAE,OAAO,IAAI,CAAC;IACjC,MAAM,gBAAgB,GAAG,cAAc,KAAK,GAAG,CAAC;IAEhD,mBAAmB;IACnB,MAAM,OAAO,GAAG;QACd,oBAAoB,UAAU,EAAE;QAChC,oBAAoB,gBAAgB,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;KAClD,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACb,EAAE,CAAC,MAAM,EAAE,CAAC,aAAa,OAAO,EAAE,EAAE,MAAM,CAAC,CAAC;IAE5C,MAAM,OAAO,GAAG,MAAM,EAAE,CAAC,MAAM,CAAC,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC;IACjE,IAAI,OAAO,KAAK,GAAG;QAAE,OAAO,IAAI,CAAC;IAEjC,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;;GAMG;AACH,KAAK,UAAU,QAAQ,CACrB,EAAY,EACZ,KAAa,EACb,YAAoB;IAEpB,MAAM,aAAa,GAAG,GAAG,KAAK,cAAc,YAAY,GAAG,CAAC;IAC5D,MAAM,GAAG,GAAG,EAAE,CAAC,KAAK;QAClB,CAAC,CAAC,MAAM,EAAE,CAAC,KAAK,CAAC,aAAa,EAAE,EAAE,YAAY,EAAE,CAAC;QACjD,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,aAAa,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC,CAAC;IACjE,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACnC,IAAI,GAAG,KAAK,YAAY;QAAE,OAAO,IAAI,CAAC;IACtC,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,wEAAwE;IACxE,0DAA0D;IAC1D,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC;AACrD,CAAC"}
|
package/dist/session/tools.js
CHANGED
|
@@ -164,7 +164,6 @@ export function registerAgentTools(pi, getSessionPeer) {
|
|
|
164
164
|
}
|
|
165
165
|
},
|
|
166
166
|
});
|
|
167
|
-
let _requestDeprecationWarned = false;
|
|
168
167
|
pi.registerTool({
|
|
169
168
|
name: "agent_request",
|
|
170
169
|
label: "Agent Request (deprecated)",
|
|
@@ -176,11 +175,6 @@ export function registerAgentTools(pi, getSessionPeer) {
|
|
|
176
175
|
promptSnippet: "agent_request({to, body, timeout_ms?}): DEPRECATED synchronous request/reply (blocks current turn). Prefer agent_send + inbox observation.",
|
|
177
176
|
parameters: RequestParams,
|
|
178
177
|
execute: async (_toolCallId, params) => {
|
|
179
|
-
if (!_requestDeprecationWarned) {
|
|
180
|
-
_requestDeprecationWarned = true;
|
|
181
|
-
console.error("[remote-pi] agent_request is deprecated — migrate to agent_send + " +
|
|
182
|
-
"observe inbox by `re`. See the agent-network skill for the new pattern.");
|
|
183
|
-
}
|
|
184
178
|
const peer = getSessionPeer();
|
|
185
179
|
if (!peer) {
|
|
186
180
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/session/tools.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/session/tools.ts"],"names":[],"mappings":"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"}
|
|
@@ -49,6 +49,9 @@ export declare class RelayClient extends EventEmitter {
|
|
|
49
49
|
private readonly url;
|
|
50
50
|
private readonly keypair;
|
|
51
51
|
private ws;
|
|
52
|
+
/** Epoch ms of the last inbound frame (message / relay ping / pong). */
|
|
53
|
+
private lastActivityAt;
|
|
54
|
+
private livenessTimer;
|
|
52
55
|
constructor(url: string, keypair: Ed25519Keypair);
|
|
53
56
|
/**
|
|
54
57
|
* Connects and completes Ed25519 auth. Resolves when relay is ready.
|
|
@@ -74,6 +77,11 @@ export declare class RelayClient extends EventEmitter {
|
|
|
74
77
|
*/
|
|
75
78
|
sendControl(frame: object): void;
|
|
76
79
|
close(): void;
|
|
80
|
+
/** Force-close the WS when no inbound frame has arrived for
|
|
81
|
+
* `LIVENESS_TIMEOUT_MS` — see the constant's doc for why. `terminate()`
|
|
82
|
+
* fires `close`, which the owner turns into a reconnect. */
|
|
83
|
+
private _startLiveness;
|
|
84
|
+
private _stopLiveness;
|
|
77
85
|
private _authenticate;
|
|
78
86
|
/** Waits for the next single WS message with a timeout. */
|
|
79
87
|
private _nextMsg;
|
|
@@ -2,6 +2,17 @@ import { EventEmitter } from "node:events";
|
|
|
2
2
|
import WebSocket from "ws";
|
|
3
3
|
import { ed25519Sign } from "../pairing/crypto.js";
|
|
4
4
|
const AUTH_TIMEOUT_MS = 5_000;
|
|
5
|
+
/**
|
|
6
|
+
* Liveness watchdog. The relay sends a WS Ping every ~25s (relay `peer.rs`),
|
|
7
|
+
* so a healthy connection sees inbound frames at least that often. If NOTHING
|
|
8
|
+
* arrives for this long the socket is silently dead — NAT/router idle drop,
|
|
9
|
+
* laptop sleep, or the relay/Cloudflare reaping the connection WITHOUT a clean
|
|
10
|
+
* close frame. That half-open case never fires `close`, so reconnect never
|
|
11
|
+
* triggers and a background daemon sits "online" but dead after a few idle
|
|
12
|
+
* hours. We force-close on timeout so `close` drives the caller's reconnect.
|
|
13
|
+
*/
|
|
14
|
+
const LIVENESS_TIMEOUT_MS = 70_000; // ~2.8 missed relay pings → confidently dead
|
|
15
|
+
const LIVENESS_CHECK_MS = 20_000;
|
|
5
16
|
/** Relay rejected hello because another peer already holds (pubkey, room_id). */
|
|
6
17
|
export class RoomAlreadyOpenError extends Error {
|
|
7
18
|
roomId;
|
|
@@ -32,6 +43,9 @@ export class RelayClient extends EventEmitter {
|
|
|
32
43
|
url;
|
|
33
44
|
keypair;
|
|
34
45
|
ws = null;
|
|
46
|
+
/** Epoch ms of the last inbound frame (message / relay ping / pong). */
|
|
47
|
+
lastActivityAt = 0;
|
|
48
|
+
livenessTimer = null;
|
|
35
49
|
constructor(url, keypair) {
|
|
36
50
|
super();
|
|
37
51
|
this.url = url;
|
|
@@ -59,8 +73,12 @@ export class RelayClient extends EventEmitter {
|
|
|
59
73
|
ws.on("open", async () => {
|
|
60
74
|
try {
|
|
61
75
|
await this._authenticate(ws, options);
|
|
62
|
-
// Auth done — wire persistent message handler
|
|
76
|
+
// Auth done — wire persistent message handler. Every inbound frame
|
|
77
|
+
// (data, plus the relay's keepalive ping/pong below) refreshes the
|
|
78
|
+
// liveness clock.
|
|
79
|
+
this.lastActivityAt = Date.now();
|
|
63
80
|
ws.on("message", (raw) => {
|
|
81
|
+
this.lastActivityAt = Date.now();
|
|
64
82
|
const text = Buffer.isBuffer(raw) ? raw.toString() : String(raw);
|
|
65
83
|
for (const line of text.split("\n")) {
|
|
66
84
|
const trimmed = line.trim();
|
|
@@ -68,7 +86,17 @@ export class RelayClient extends EventEmitter {
|
|
|
68
86
|
this.emit("message", trimmed);
|
|
69
87
|
}
|
|
70
88
|
});
|
|
71
|
-
ws
|
|
89
|
+
// The relay pings every ~25s; `ws` auto-replies Pong (keeping the
|
|
90
|
+
// relay's view of us alive). The relay ignores client pings rather
|
|
91
|
+
// than ponging, so these inbound pings — not a ping/pong we initiate
|
|
92
|
+
// — are our liveness signal.
|
|
93
|
+
ws.on("ping", () => { this.lastActivityAt = Date.now(); });
|
|
94
|
+
ws.on("pong", () => { this.lastActivityAt = Date.now(); });
|
|
95
|
+
ws.on("close", () => {
|
|
96
|
+
this._stopLiveness();
|
|
97
|
+
this.emit("close");
|
|
98
|
+
});
|
|
99
|
+
this._startLiveness(ws);
|
|
72
100
|
resolve();
|
|
73
101
|
}
|
|
74
102
|
catch (err) {
|
|
@@ -97,9 +125,29 @@ export class RelayClient extends EventEmitter {
|
|
|
97
125
|
this.ws.send(JSON.stringify(frame));
|
|
98
126
|
}
|
|
99
127
|
close() {
|
|
128
|
+
this._stopLiveness();
|
|
100
129
|
this.ws?.close();
|
|
101
130
|
this.ws = null;
|
|
102
131
|
}
|
|
132
|
+
// ── Liveness watchdog ─────────────────────────────────────────────────────
|
|
133
|
+
/** Force-close the WS when no inbound frame has arrived for
|
|
134
|
+
* `LIVENESS_TIMEOUT_MS` — see the constant's doc for why. `terminate()`
|
|
135
|
+
* fires `close`, which the owner turns into a reconnect. */
|
|
136
|
+
_startLiveness(ws) {
|
|
137
|
+
this._stopLiveness();
|
|
138
|
+
this.livenessTimer = setInterval(() => {
|
|
139
|
+
if (Date.now() - this.lastActivityAt > LIVENESS_TIMEOUT_MS) {
|
|
140
|
+
this._stopLiveness();
|
|
141
|
+
ws.terminate();
|
|
142
|
+
}
|
|
143
|
+
}, LIVENESS_CHECK_MS);
|
|
144
|
+
}
|
|
145
|
+
_stopLiveness() {
|
|
146
|
+
if (this.livenessTimer) {
|
|
147
|
+
clearInterval(this.livenessTimer);
|
|
148
|
+
this.livenessTimer = null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
103
151
|
// ── Auth ────────────────────────────────────────────────────────────────────
|
|
104
152
|
async _authenticate(ws, opts) {
|
|
105
153
|
const pubkeyB64 = Buffer.from(this.keypair.publicKey).toString("base64");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"relay_client.js","sourceRoot":"","sources":["../../src/transport/relay_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,SAAS,MAAM,IAAI,CAAC;AAC3B,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAGnD,MAAM,eAAe,GAAG,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"relay_client.js","sourceRoot":"","sources":["../../src/transport/relay_client.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "remote-pi",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Mobile remote control and local agent mesh for the Pi coding agent. Pair your phone via QR over a relay, watch tool calls in real time, run multi-Pi sessions over a local Unix Domain Socket broker, and let agents talk to each other through structured request/reply.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -76,10 +76,12 @@
|
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@mariozechner/pi-coding-agent": "^0.73.1",
|
|
79
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
79
80
|
"@napi-rs/keyring": "^1.3.0",
|
|
80
81
|
"@noble/ed25519": "^3.1.0",
|
|
81
82
|
"qrcode-terminal": "^0.12.0",
|
|
82
83
|
"typebox": "^1.1.38",
|
|
83
|
-
"ws": "^8.20.1"
|
|
84
|
+
"ws": "^8.20.1",
|
|
85
|
+
"zod": "^4.4.3"
|
|
84
86
|
}
|
|
85
87
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: agent-network
|
|
3
|
+
description: Use when the remote-pi mesh tools (`list_peers`, `agent_send`, `get_messages`) are available — you are a Claude 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 delivery status (`agent_send` + ACK), how incoming messages arrive (`get_messages` at the start of each turn, plus channel push), how to reply (echo `re`), and how cross-PC addressing works (`<pc_label>:<peer>`).
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Agent Network (Claude ↔ remote-pi mesh)
|
|
7
|
+
|
|
8
|
+
You are connected to the **remote-pi agent mesh** through an MCP server.
|
|
9
|
+
Other agents — other Claude sessions, Pi coding agents on this machine, and
|
|
10
|
+
agents on the Owner's other PCs (via the relay) — can send you messages, and
|
|
11
|
+
you can send messages 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
|
+
You have exactly three tools: `list_peers`, `agent_send`, `get_messages`.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## The most important rule: check your inbox every turn
|
|
21
|
+
|
|
22
|
+
Incoming messages are buffered for you. **At the start of every turn, call
|
|
23
|
+
`get_messages`** to drain and read anything other agents sent you:
|
|
24
|
+
|
|
25
|
+
```
|
|
26
|
+
get_messages()
|
|
27
|
+
→ "[2026-05-30T12:00:01Z] from=backend re=<your-id>
|
|
28
|
+
id=<msg-id>
|
|
29
|
+
{ "shape": { "sub": "string", "exp": "number" } }"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
- Returns all pending messages and clears the buffer (call once per turn).
|
|
33
|
+
- Returns `(no messages)` when nothing is waiting — that's normal, keep working.
|
|
34
|
+
- A channel push may also surface a message mid-session (a `📨 Message from …`
|
|
35
|
+
notification). When it does, still call `get_messages` to get the full,
|
|
36
|
+
structured payload (`from`, `id`, `re`, `body`) — the push is just a nudge.
|
|
37
|
+
|
|
38
|
+
**If a message arrived, someone wanted your attention. Don't ignore it.**
|
|
39
|
+
You only ever receive messages addressed to you — the broker filters before
|
|
40
|
+
delivery.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## First thing in a new session: `list_peers`
|
|
45
|
+
|
|
46
|
+
Before sending anything, find out who's actually online:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
list_peers()
|
|
50
|
+
→ backend
|
|
51
|
+
frontend
|
|
52
|
+
casa:agent-1
|
|
53
|
+
trab:worker
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Synchronous (resolves in milliseconds — not another agent's turn). Use it:
|
|
57
|
+
|
|
58
|
+
- At the start of a session, to see what mesh you're in
|
|
59
|
+
- Before any `agent_send` whose target name is uncertain
|
|
60
|
+
- After a while, to refresh (peers join/leave over time)
|
|
61
|
+
|
|
62
|
+
**Entry shape:**
|
|
63
|
+
- `backend` → local peer (this machine, same broker)
|
|
64
|
+
- `casa:agent-1` → cross-PC peer on the PC labeled `casa` (the Owner's other
|
|
65
|
+
machine, reached through the relay)
|
|
66
|
+
|
|
67
|
+
You are excluded from the result — no need to filter yourself out.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Anatomy of a message (envelope)
|
|
72
|
+
|
|
73
|
+
`get_messages` shows you, per message: `from`, `id`, `re`, and `body`.
|
|
74
|
+
|
|
75
|
+
| Field | Meaning |
|
|
76
|
+
|---|---|
|
|
77
|
+
| `from` | Who sent it. Use this verbatim as your `to` when replying. |
|
|
78
|
+
| `id` | Unique id of this message. Echo it as `re` when you reply. |
|
|
79
|
+
| `re` | If set, this message is itself a REPLY to an earlier `id` of yours. |
|
|
80
|
+
| `body` | Free-form content — string or JSON, sender's choice. |
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Sending: `agent_send` returns an ACK status
|
|
85
|
+
|
|
86
|
+
`agent_send({ to, body, re? })` is how you talk to peers. Every **unicast**
|
|
87
|
+
call returns a status telling you what happened at the recipient. **Always
|
|
88
|
+
inspect the status — it dictates what to do next.**
|
|
89
|
+
|
|
90
|
+
| Status | Means | What you do |
|
|
91
|
+
|---|---|---|
|
|
92
|
+
| `received` | Peer was idle; broker delivered the envelope; peer will process it on its next turn. | Move on. Any reply arrives later — check `get_messages` on future turns. |
|
|
93
|
+
| `busy` | Peer is mid-turn — envelope **dropped**. | Retry 2× with backoff (~2s, ~5s). Still busy → abandon or escalate. You own the retry. |
|
|
94
|
+
| `denied` | Peer explicitly refused. | Do NOT retry. Report to the user. |
|
|
95
|
+
| `timeout` | No ACK (~5s). Transport error — broker down, or peer vanished. | Treat as transient. Retry once after ~10s, then escalate. |
|
|
96
|
+
|
|
97
|
+
For `to: "broadcast"`, there's no single ACK — it's fire-and-forget
|
|
98
|
+
("Broadcast sent").
|
|
99
|
+
|
|
100
|
+
**Replies bypass the busy gate.** A message with `re=<some-id>` (an answer to
|
|
101
|
+
something the recipient asked) is always delivered — it resolves their pending
|
|
102
|
+
state instead of starting a new turn. So if you fan out questions to several
|
|
103
|
+
peers, every reply reaches you even while they're busy.
|
|
104
|
+
|
|
105
|
+
---
|
|
106
|
+
|
|
107
|
+
## Receiving: replies arrive on a later turn
|
|
108
|
+
|
|
109
|
+
You **do not block** waiting for a reply. The model is event-driven:
|
|
110
|
+
|
|
111
|
+
1. You call `agent_send` → status `received`.
|
|
112
|
+
2. Your turn continues / ends.
|
|
113
|
+
3. **Later** the peer finishes its own work and sends a reply.
|
|
114
|
+
4. The reply lands in your inbox. You see it the next time you call
|
|
115
|
+
`get_messages`, with `re` set to the `id` you originally sent.
|
|
116
|
+
|
|
117
|
+
No wait/sleep/poll-loop. Just call `get_messages` at the start of your turns.
|
|
118
|
+
|
|
119
|
+
### Walk-through
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
agent_send({ to: "backend", body: { q: "what's the JWT shape?" } })
|
|
123
|
+
→ Delivered to backend # status received; remember the message id
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
Your turn continues. A turn or two later:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
get_messages()
|
|
130
|
+
→ "[…] from=backend re=<your-id>
|
|
131
|
+
id=<new-id>
|
|
132
|
+
{ "shape": { "sub": "string", "exp": "number", "roles": ["string"] } }"
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
You correlate by `re` — it matches the send you made. Now you have your answer.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Replying to a message
|
|
140
|
+
|
|
141
|
+
When you receive (via `get_messages`):
|
|
142
|
+
|
|
143
|
+
```
|
|
144
|
+
from=orchestrator id=abc-uuid re=(none)
|
|
145
|
+
{ "task": "Implement POST /auth/login" }
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Reply with `re` set to that `id`, and `to` set to the sender's `from`:
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
agent_send({
|
|
152
|
+
to: "orchestrator",
|
|
153
|
+
body: { status: "done", files_changed: [...] },
|
|
154
|
+
re: "abc-uuid"
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Without `re`, the sender gets your message but can't match it to the
|
|
159
|
+
question — coordination drifts. **Always echo `re` on a reply.**
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Asking multiple peers at once
|
|
164
|
+
|
|
165
|
+
Fire multiple `agent_send` in one turn — each returns its own ACK. Replies
|
|
166
|
+
arrive on future turns as peers finish.
|
|
167
|
+
|
|
168
|
+
```
|
|
169
|
+
agent_send({ to: "backend", body: { q: "JWT shape?" } }) // received
|
|
170
|
+
agent_send({ to: "frontend", body: { q: "theme tokens?" } }) // received
|
|
171
|
+
agent_send({ to: "infra", body: { q: "ETA for Y?" } }) // busy — retry
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Track which `id` maps to which question. Don't assume replies arrive in send
|
|
175
|
+
order — use `re` to identify what each reply answers.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## Cross-PC addressing (`<pc_label>:<peer>`)
|
|
180
|
+
|
|
181
|
+
When the Owner has paired multiple PCs, remote peers appear with a prefix:
|
|
182
|
+
|
|
183
|
+
```
|
|
184
|
+
list_peers() → backend frontend casa:agent-1 trab:worker
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Send to a remote peer with the prefixed name verbatim:
|
|
188
|
+
|
|
189
|
+
```
|
|
190
|
+
agent_send({ to: "casa:agent-1", body: { ... } })
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
The relay routes it across the mesh; `received | busy | denied | timeout`
|
|
194
|
+
semantics are identical to local. When you **reply** to a cross-PC message,
|
|
195
|
+
use the sender's `from` verbatim (it already carries the prefix) as your `to`.
|
|
196
|
+
You never prefix your own name — the broker handles that.
|
|
197
|
+
|
|
198
|
+
Cross-PC failure notes:
|
|
199
|
+
- `denied` → the remote broker has no peer by that name (left, or stale cache
|
|
200
|
+
→ call `list_peers` again).
|
|
201
|
+
- `timeout` → the other PC is offline or the relay is unreachable.
|
|
202
|
+
|
|
203
|
+
---
|
|
204
|
+
|
|
205
|
+
## Broadcast and multicast
|
|
206
|
+
|
|
207
|
+
- `to: "broadcast"` → every other peer. Use for announcements
|
|
208
|
+
("wave 2 started"), never for questions (replies would be uncorrelated).
|
|
209
|
+
- Broadcast skips ACK — you don't know who received it. For delivery
|
|
210
|
+
confirmation, use individual unicast sends.
|
|
211
|
+
|
|
212
|
+
---
|
|
213
|
+
|
|
214
|
+
## When in doubt
|
|
215
|
+
|
|
216
|
+
- **Received a task you don't understand** → reply with `body.status:"error"`,
|
|
217
|
+
echoing the original `id` in `re`. Don't go silent.
|
|
218
|
+
- **Received a `re` you never sent** → late reply to something already wrapped
|
|
219
|
+
up. Ignore. Don't reply to a reply.
|
|
220
|
+
- **No messages ever arrive** → normal. You only receive when addressed. Keep
|
|
221
|
+
working; just keep calling `get_messages` each turn.
|
|
222
|
+
- **`timeout` on send** → broker restarting (failover) or peer vanished. Retry
|
|
223
|
+
once after ~10s, then escalate.
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Single-page summary
|
|
228
|
+
|
|
229
|
+
1. **Every turn**: `get_messages()` first — drain your inbox.
|
|
230
|
+
2. **Discover**: `list_peers()` → locals + `<pc>:<peer>` cross-PC. Synchronous.
|
|
231
|
+
3. **Send**: `agent_send({to, body, re?})` → inspect the status.
|
|
232
|
+
4. **Unicast status**: `received | busy | denied | timeout`. Retry on `busy`
|
|
233
|
+
(backoff); abandon on `denied`; investigate on `timeout`.
|
|
234
|
+
5. **Broadcast**: fire-and-forget, no ACK.
|
|
235
|
+
6. **Reply**: set `re` to their `id`, `to` to their `from` (prefix and all).
|
|
236
|
+
7. You never receive your own messages. The broker does not queue — if a peer
|
|
237
|
+
is busy, your message is dropped; you own the retry.
|
|
238
|
+
|
|
239
|
+
Re-read when in doubt.
|