pi-link 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-link",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "WebSocket-based inter-terminal communication for Pi. Connect multiple Pi terminals over a local link network.",
5
5
  "author": "alvivar",
6
6
  "license": "MIT",
@@ -1,114 +1,124 @@
1
- ---
2
- name: pi-link-coordination
3
- description: Guidance for coordinating work across Pi terminals using pi-link. Use when delegating tasks, choosing between link_prompt and link_send, planning async vs sync work, batching parallel jobs, managing a remote terminal's context with link_compact, or avoiding busy/conflict patterns.
4
- ---
5
-
6
- # Pi-Link Coordination
7
-
8
- How to coordinate work across Pi terminals via pi-link.
9
-
10
- Each terminal is an independent agent: they share no memory or conversation history — link only passes messages and prompts between them. Anything a remote terminal needs — file paths, task state, expected output, where to send its callback — must be in the message itself.
11
-
12
- ---
13
-
14
- ## Tool Selection Rule
15
-
16
- - Need the answer back now? → `link_prompt`
17
- - Need autonomous work done? → `link_send(triggerTurn: true)`
18
- - Need to notify only? → `link_send(triggerTurn: false)`
19
- - Need to free a terminal's context? → `link_compact`
20
-
21
- ---
22
-
23
- ## The Golden Rule
24
-
25
- > After `link_send(triggerTurn: true)` to terminal X, do not `link_prompt` X until X sends a completion callback.
26
-
27
- The `DONE` / `BLOCKED` callback arrives as a normal later user message; treat that callback as the signal that it is safe to send a follow-up `link_prompt`.
28
-
29
- Pick one mode per terminal per task. Mixing sync and async on the same terminal is a common coordination failure.
30
-
31
- ---
32
-
33
- ## The Tools
34
-
35
- ### `link_list`
36
-
37
- Returns connected terminals with names, live status (`idle`, `thinking`, `tool:<name>`), and working directory (cwd). Some terminals also report context usage as `45K/272K (17%)` — how full that window is: high usage means less room remaining, though a loaded terminal may also be the one already holding the relevant task state. Your own entry is marked `(you)` — use this to discover your link name when replying to broadcast tasks.
38
-
39
- Only currently connected terminals are visible. If a target is missing, it is offline; messages to offline terminals are not queued.
40
-
41
- ### `link_prompt`
42
-
43
- Synchronous RPC. Send a prompt, wait for the response.
44
-
45
- - Fails fast if the target is yourself, not connected, or busy (local work, another remote prompt, or compaction); a mid-wait disconnect resolves as an error
46
- - 90s inactivity timeout, 30min hard ceiling
47
- - Remote agent doesn't share your context — include enough detail to complete the task
48
-
49
- ### `link_send`
50
-
51
- Fire-and-forget. Send to one terminal or `to: "*"` to broadcast to every other connected terminal; there is no exclusion filter. Sending to yourself is rejected. A send to a name that isn't connected fails with an error listing who _is_ connected — delivery failure is visible to the sender, not silent.
52
-
53
- Set `triggerTurn: true` to queue async work on the receiver. The sender does **not** get an automatic response back.
54
-
55
- Delivery shape depends on the message's `triggerTurn`:
56
-
57
- - **`triggerTurn: true`** messages go through the receiver's idle-gated inbox and surface at a turn boundary wrapped as `[Link: N message(s) received]` followed by one `From "name":` block per message. Multiple pending messages are batched into one turn.
58
- - **`triggerTurn: false`** messages bypass the inbox and surface directly as raw content — no wrapper, no `From` block. The receiver sees only the message text, so the sender must include their own identity, task tag, or artifact paths in the body.
59
-
60
- **Callback convention for `triggerTurn: true`:** the sender gets no automatic response, so ask the receiver to report back via `link_send(..., triggerTurn: true)` (which lands at a proper turn boundary with the wrapper intact). A useful convention:
61
-
62
- - `DONE` / `BLOCKED`
63
- - Output paths / artifacts created
64
- - Result summary or next question
65
-
66
- Use `triggerTurn: false` for fire-and-forget status notifications only — when you don't need to act on the reply.
67
-
68
- **Receiver rule:** If your turn opens with `[Link: N message(s) received]`, treat each `From "name":` block as assigned work. When done, send the sender a `DONE` / `BLOCKED` callback via `link_send(..., triggerTurn: true)` — unless the task says otherwise.
69
-
70
- ### `link_compact`
71
-
72
- Blocks until the target finishes compacting, then returns (3 min ceiling — the call then errors for you, though the target may still finish compacting on its own; check it before assuming failure). Ask another terminal to compact its context window into a summary, freeing space. `link_list` exposes context usage; `link_compact` is the lever when you decide a terminal should free context — and because the call only returns once compaction is done, you can immediately hand it more work with `link_send`/`link_prompt` (no sleep, no busy-bounce). Busy targets (mid-turn or already compacting) decline; retry when `link_list` shows them idle. You decide the threshold; pi-link just runs the compaction you ask for. Its optional `instructions` add an extra focus to that summary.
73
-
74
- ---
75
-
76
- ## Operating Constraints
77
-
78
- - **One remote prompt at a time per target.** Concurrent requests rejected as busy.
79
- - **Messages are ephemeral.** Offline terminals lose messages.
80
- - **Localhost only.** Same machine.
81
- - **Cwd is a hint, not proof.** Same cwd ≠ same workspace/branch/access. Use explicit paths; absolute when cwds differ or shared-root assumptions are unclear.
82
- - **Naming:** Link names are user-defined identities (often `role@domain`, e.g. `builder@pi-link`); the hub keeps them unique, suffixing collisions (`builder@pi-link-2`). Use `link_list` to confirm a target's exact name, and its cwd to tell similar-named terminals apart.
83
-
84
- ---
85
-
86
- ## Parallel batch
87
-
88
- `link_send(triggerTurn: true)` can dispatch independent tasks to several terminals at once. Their callbacks may arrive separately or batched into one turn when you next become idle — track which workers are still outstanding. Each task must be self-contained (explicit paths, absolute if cwds differ). Don't `link_prompt` a dispatched terminal until its callback arrives (Golden Rule).
89
-
90
- ---
91
-
92
- ## Anti-Patterns
93
-
94
- **❌ Mixing async and sync on the same terminal**
95
- Dispatched with `link_send(triggerTurn: true)` then sent a `link_prompt` → rejected as busy. See Golden Rule.
96
-
97
- **❌ No completion callback on async work**
98
- `triggerTurn: true` returns no result to the sender — without an agreed callback you never learn the outcome.
99
-
100
- **❌ Circular delegation**
101
- A → B → C → A won't complete — the cycle-closing `link_prompt` hits a busy target (rejected), and an async `link_send` cycle just loops. Keep delegation acyclic.
102
-
103
- ---
104
-
105
- ## Quick Reference
106
-
107
- | I need to... | Tool | Mode |
108
- | -------------------------------- | ------------------------------- | ---------------- |
109
- | See who's available | `link_list` | — |
110
- | Get an answer from another agent | `link_prompt` | Synchronous |
111
- | Delegate autonomous work | `link_send(triggerTurn: true)` | Asynchronous |
112
- | Notify without activating | `link_send(triggerTurn: false)` | Fire-and-forget |
113
- | Broadcast to all | `link_send(to: "*")` | Broadcast |
114
- | Free a loaded worker's context | `link_compact` | Await-completion |
1
+ ---
2
+ name: pi-link-coordination
3
+ description: Mechanics of coordinating work across Pi terminals with link_send, link_list, and link_compact — how delivery, batching, callbacks, and remote compaction actually behave.
4
+ ---
5
+
6
+ # Pi-Link Coordination
7
+
8
+ How the pi-link transport behaves between Pi terminals.
9
+
10
+ **Terminals share no conversation.** Each is an independent agent with its own
11
+ context. Nothing you hold — task state, file paths, an approval you were given,
12
+ what you decided a moment ago — is visible to a terminal you message. The message
13
+ is the entire shared state.
14
+
15
+ ---
16
+
17
+ ## Tools
18
+
19
+ ### `link_list`
20
+
21
+ Returns connected terminals with names, status (`idle`, `thinking`,
22
+ `compacting`, `tool:<name>`), cwd, and (when available) context usage such as
23
+ `45K/272K (17%)`. Your own entry is marked `(you)`; its status and context are
24
+ computed when listed, while peer values are their latest published snapshots.
25
+
26
+ Pi runs tools in parallel by default, and `tool:<name>` then names the first
27
+ still-active call it reported rather than all of them. It advances only when that
28
+ call ends, and becomes `thinking` only after the last call ends.
29
+
30
+ `thinking` covers every kind of unsettled work, not just an LLM call: an automatic
31
+ retry, an automatic compaction and a queued continuation all run after the visible
32
+ turn ends, and the terminal reads `thinking` until Pi reports the run settled.
33
+
34
+ `compacting` means a manual compaction has raised that terminal's delivery gate;
35
+ messages sent to it wait until the gate clears. An automatic (threshold or
36
+ overflow) compaction never shows it — it is not gated, and reads `thinking` like
37
+ the rest of the run it belongs to.
38
+
39
+ Only connected terminals are visible; nothing is stored for disconnected
40
+ terminals, so a reconnecting terminal receives no backlog.
41
+
42
+ A terminal's queued messages are invisible to you, and silence is
43
+ indistinguishable from work in progress.
44
+
45
+ ### `link_send`
46
+
47
+ The message is delivered to the receiver's model. The first message to arrive opens
48
+ a batching window of about 200ms; later arrivals do not move its deadline, so a
49
+ steady stream is delivered window by window instead of waiting for a pause. A batch
50
+ arrives as one `[Link: N message(s) received]` block, in arrival order, containing
51
+ one `From "name":` block per message.
52
+
53
+ The receiver's state is read when that batch is delivered, not when you send and
54
+ not when you last ran `link_list`. If the receiver is still running then, the batch
55
+ is steered into that run at Pi's next safe boundary — current tool calls finish
56
+ first, before the next LLM call. Otherwise it starts a turn. A receiver can settle
57
+ within the delay, so a message sent to a busy terminal may still arrive as a new
58
+ turn. There is no way to send without entering the receiver's reasoning.
59
+
60
+ Each send has exactly one recipient. There is no fan-out.
61
+
62
+ The call returns send status, not the receiver's eventual work result. A definitely
63
+ absent target fails against the local terminal list; beyond that, for a client a
64
+ successful send means the message was written to its hub connection, not that it
65
+ arrived. If the target has vanished, the routing failure is shown to the human as a
66
+ notification and never reaches the sending model.
67
+
68
+ A terminal reported as `compacting` receives nothing until its gate clears. The
69
+ messages wait and are delivered afterwards. A cancelled compaction has no ending
70
+ pi-link can see, so they wait for the terminal's next agent run, a later
71
+ successful compaction, or a three-minute deadline — whichever comes first. The
72
+ sender is told nothing meanwhile.
73
+
74
+ ### `link_compact`
75
+
76
+ Asks another terminal to compact its context and waits for a result, with a
77
+ three-minute ceiling. A target accepts only when Pi reports its session idle and no
78
+ manual compaction holds its gate; anything else declines rather than being
79
+ interrupted, so a target reading `thinking` for a retry or an automatic compaction
80
+ declines exactly as one mid-turn does. Optional `instructions` focus the summary.
81
+
82
+ The timeout bounds your wait only. Nothing aborts the target, so a timed-out call
83
+ may mean the compaction is still running.
84
+
85
+ Compaction discards detail. What survives is whatever the summary keeps, so
86
+ anything the target learned but has not written down or reported can be lost.
87
+
88
+ ---
89
+
90
+ ## Callbacks
91
+
92
+ A callback is an ordinary `link_send` from the worker back to you. There is no
93
+ request ID, no automatic response, no delivery receipt, and no protocol timeout —
94
+ nothing correlates a callback with the dispatch that asked for it except the text
95
+ of both, and nothing produces one except the receiver choosing to send it.
96
+
97
+ Waiting for one requires no live run: if the terminal is idle when the batch is
98
+ delivered, the message starts a turn by itself. Keeping a run alive only to wait —
99
+ by sleeping or polling `link_list` — is unnecessary and can postpone delivery to
100
+ the model until active tool calls end.
101
+
102
+ A callback can be sent before its sender's run settles; receiving it does not
103
+ prove the sender is idle, so a `link_compact` aimed at it can still decline as
104
+ busy.
105
+
106
+ An accepted send does not wait for a reply, so several tasks can be dispatched
107
+ before any callback arrives, and callbacks may arrive separately or batched into
108
+ one of your turns. For the same reason the protocol supplies no exit condition for
109
+ an A → B → C → A delegation chain.
110
+
111
+ ---
112
+
113
+ ## Constraints
114
+
115
+ - **Localhost only.** All terminals run on the same machine.
116
+ - **Cwd is a hint, not proof.** Same cwd does not prove the same workspace, branch,
117
+ or access. Paths named in a message are only text: they do not change the
118
+ receiver's cwd, and relative commands resolve from the receiver's own cwd.
119
+ - **Names are identities.** The hub suffixes collisions, so the name you remember
120
+ may not be the name that is connected; `link_list` shows the current one.
121
+ - **Mixed-version meshes are unsupported.** Across the current protocol break, a
122
+ message from a new sender can reach a 0.2.0 receiver as bare text — without the
123
+ `[Link: N message(s) received]` header or the `From "name":` line — and nothing
124
+ reports a fault.