@llblab/pi-actors 0.17.0 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/BACKLOG.md +15 -11
- package/CHANGELOG.md +6 -1
- package/README.md +171 -302
- package/docs/actor-messages.md +3 -1
- package/docs/recipe-library.md +1 -0
- package/index.ts +73 -28
- package/lib/actor-inspector-tui.ts +214 -108
- package/lib/actor-rooms.ts +4 -0
- package/package.json +1 -1
- package/recipes/pipeline-room-swarm.json +49 -0
- package/scripts/room-swarm.mjs +244 -0
- package/skills/actors/SKILL.md +2 -2
- package/skills/swarm/SKILL.md +1 -1
package/README.md
CHANGED
|
@@ -1,236 +1,178 @@
|
|
|
1
1
|
# pi-actors
|
|
2
2
|
|
|
3
|
-
> Actor
|
|
3
|
+
> Local Actor Kernel for Pi
|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+

|
|
6
6
|
|
|
7
|
-
`pi-actors` turns local programs, scripts, services,
|
|
7
|
+
`pi-actors` turns trusted local programs, scripts, recipes, services, pipelines, and sub-agents into addressable actors that agents can spawn, message, inspect, and compose.
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
## Start Here
|
|
12
|
-
|
|
13
|
-
- [Project Context](./AGENTS.md)
|
|
14
|
-
- [Open Backlog](./BACKLOG.md)
|
|
15
|
-
- [Changelog](./CHANGELOG.md)
|
|
16
|
-
- [Documentation](./docs/README.md)
|
|
17
|
-
- [Actors skill](./skills/actors/SKILL.md) — dense agent-facing reference for operating the extension
|
|
18
|
-
- [Swarm skill](./skills/swarm/SKILL.md) — multi-agent methodology, strategies, standards, and portable examples for actor-backed swarms
|
|
19
|
-
- [Swarm MAWP notes](./skills/swarm/references/development-swarm.md) — optional small-team development swarm reference
|
|
20
|
-
|
|
21
|
-
## What It Is
|
|
22
|
-
|
|
23
|
-
`pi-actors` is the runtime layer that lets a pi agent turn a local capability into a controllable actor:
|
|
9
|
+
It is not just a command registry. A tool is a verb. An actor is a noun with time: address, lifecycle, state, logs, mailbox, artifacts, and an interaction contract.
|
|
24
10
|
|
|
25
11
|
```text
|
|
26
|
-
program/process/service
|
|
12
|
+
program / process / service
|
|
27
13
|
→ command template
|
|
28
14
|
→ actor recipe
|
|
29
15
|
→ spawn
|
|
30
|
-
→
|
|
16
|
+
→ run:<id>
|
|
31
17
|
→ message / inspect / artifacts
|
|
32
18
|
```
|
|
33
19
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
- A sub-agent running `pi -p` in a clean context.
|
|
37
|
-
- A background music player controlled by `player.next` or `player.pause` messages.
|
|
38
|
-
- A validation or repo-health pipeline that reports completion and artifacts.
|
|
39
|
-
- A parallel quorum review with branch-level progress.
|
|
40
|
-
- Any trusted local process with a launch template and a useful control surface.
|
|
41
|
-
|
|
42
|
-
The key move is not just “register a command.” It is to wrap a process in an agent-readable contract:
|
|
43
|
-
|
|
44
|
-
- **Launch**: `spawn` starts the actor from a template or recipe.
|
|
45
|
-
- **Interface**: `mailbox` declares accepted and emitted message types.
|
|
46
|
-
- **Control**: `message` sends typed envelopes to runs, branches, tools, or the coordinator.
|
|
47
|
-
- **Observation**: `inspect` reads status, logs, messages, mailbox metadata, files, and artifacts intentionally.
|
|
48
|
-
- **Persistence**: `artifacts` and state files make outcomes durable.
|
|
49
|
-
- **Memory**: `~/.pi/agent/recipes/*.json` stores reusable actor-control wrappers across sessions.
|
|
50
|
-
|
|
51
|
-
## Key Features
|
|
52
|
-
|
|
53
|
-
- **Actor Runtime**: Starts local templates and recipes as addressable `run:<id>` actors with state, logs, message mailboxes, cancellation, and artifacts.
|
|
54
|
-
- **Agent-Managed Processes**: Wraps sub-agents, media players, pipelines, diagnostics, and other local programs as controllable entities instead of one-off commands.
|
|
55
|
-
- **Message-Oriented Control**: Uses `spawn`, `message`, and `inspect` as the public coordination vocabulary for start, control, and observation.
|
|
56
|
-
- **Actor Rooms**: Lets actors post shared messages to `room:<run>`, update join/leave rosters, inspect room timelines or members, read compact run communication snapshots, and see recent actor communication previews in the terminal without adding a heavyweight broker.
|
|
57
|
-
- **Mailbox Contracts**: Lets recipes declare what messages they accept and emit, so agents can discover how to interact with an actor.
|
|
58
|
-
- **Actor Tool Registry**: Stores persistent actor-control tools as recipe files in `~/.pi/agent/recipes/*.json` and registers them automatically on session start.
|
|
59
|
-
- **Command Template Substrate**: Keeps process launch portable with named placeholders, typed args, defaults, sequences, guarded nodes, retries, failure policy, and `parallel: true` fanout.
|
|
60
|
-
- **Composable Actor Recipes**: Stores reusable recipe JSON under `~/.pi/agent/recipes/*.json`; recipes can import other recipes, reuse defaults, declare artifacts, and opt into detached actor lifecycle with `async: true`.
|
|
61
|
-
- **Coordinator-Scoped Observability**: Shows ambient triangles for active actor runs and sends compact completion or request-for-attention follow-ups only to the launching coordinator.
|
|
62
|
-
- **Bounded Context Impact**: Returns compact output by default, truncates oversized stdout, and keeps full logs/artifacts in files for intentional inspection.
|
|
63
|
-
- **Local-First Tool Memory**: Still lets agents create durable semantic tools from trusted commands so they do not repeatedly reconstruct shell invocations.
|
|
20
|
+
## Core Contract
|
|
64
21
|
|
|
65
|
-
|
|
22
|
+
`pi-actors` compresses local agent orchestration to three durable verbs:
|
|
66
23
|
|
|
67
|
-
|
|
24
|
+
```text
|
|
25
|
+
spawn create an addressable actor
|
|
26
|
+
message send one typed envelope to one address
|
|
27
|
+
inspect intentionally read state, logs, messages, contracts, or artifacts
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Everything else is an adapter until proven otherwise.
|
|
31
|
+
|
|
32
|
+
Use `spawn` when work may outlive the current turn. Use `message` when the actor should be steered rather than restarted. Use `inspect` at decision points, after actor follow-ups, or during diagnosis. Do not build polling loops as the default coordination pattern.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
68
35
|
|
|
69
36
|
```bash
|
|
70
37
|
pi install npm:@llblab/pi-actors
|
|
71
38
|
```
|
|
72
39
|
|
|
73
|
-
|
|
40
|
+
Or from git:
|
|
74
41
|
|
|
75
42
|
```bash
|
|
76
43
|
pi install git:github.com/llblab/pi-actors
|
|
77
44
|
```
|
|
78
45
|
|
|
79
|
-
##
|
|
80
|
-
|
|
81
|
-
`pi-actors` now reads persistent actor-control tools from:
|
|
82
|
-
|
|
83
|
-
```text
|
|
84
|
-
~/.pi/agent/recipes/*.json
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
That directory is the operator-managed executable memory: user recipe files there become tools by location and survive across sessions. `register_tool` writes recipes there under the hood. Packaged recipes are the lower-priority standard library of declarative actor components; they are not tools unless copied or registered into the agent recipe root.
|
|
88
|
-
|
|
89
|
-
## Mental Model
|
|
46
|
+
## Address Surface
|
|
90
47
|
|
|
91
|
-
|
|
48
|
+
Actors and coordination endpoints are addressed with compact route strings:
|
|
92
49
|
|
|
93
50
|
```text
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
mailbox = declare interaction contract
|
|
51
|
+
run:<id> one detached actor run
|
|
52
|
+
branch:<run>/<branch> branch-local actor endpoint
|
|
53
|
+
room:<run> shared run-local task room
|
|
54
|
+
coordinator launching coordinator attention path
|
|
55
|
+
session: current session actor surface
|
|
56
|
+
session:all cross-session inventory surface
|
|
57
|
+
tool:<name> executable registered tool
|
|
102
58
|
```
|
|
103
59
|
|
|
104
|
-
|
|
105
|
-
- A **command template** is the reusable launch shape for that process, with named placeholders.
|
|
106
|
-
- An **actor recipe** is saved JSON containing a template, defaults, imports, mailbox metadata, artifacts, and optional detached lifecycle.
|
|
107
|
-
- A **registered tool** gives a template or actor recipe a stable agent-facing name.
|
|
108
|
-
- A **run actor** is one execution instance with state, logs, actor messages, mailbox metadata, status, cancellation, and kill control.
|
|
109
|
-
|
|
110
|
-
The template remains the execution substrate. The recipe is the actor definition. `async: true` opts into detached actor lifecycle. `spawn` creates actors, `message` connects or controls them, and `inspect` observes them without teaching agents to poll blindly. Async run templates receive lifecycle and communication values such as `{run_id}`, `{state_dir}`, `{actor_address}`, `{default_room}`, and `{communication_file}`. Use `inspect run:<id> view=communication` to read the compact visible communication snapshot.
|
|
111
|
-
|
|
112
|
-
## Actor Rooms
|
|
113
|
-
|
|
114
|
-
Each spawned run gets a default room at `room:<run>`. Actors can post shared messages there, discover peers through the roster, and still send private messages directly to `run:<id>` or `branch:<run>/<branch>` addresses.
|
|
60
|
+
Actor messages use one envelope shape:
|
|
115
61
|
|
|
116
62
|
```json
|
|
117
63
|
{
|
|
118
|
-
"to": "
|
|
119
|
-
"from": "
|
|
120
|
-
"type": "
|
|
121
|
-
"
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
64
|
+
"to": "run:review",
|
|
65
|
+
"from": "coordinator",
|
|
66
|
+
"type": "control.continue",
|
|
67
|
+
"summary": "Continue after checkpoint",
|
|
68
|
+
"body": "continue",
|
|
69
|
+
"reply_to": "msg_123",
|
|
70
|
+
"correlation_id": "task_456",
|
|
71
|
+
"metadata": {}
|
|
126
72
|
}
|
|
127
73
|
```
|
|
128
74
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
```text
|
|
132
|
-
inspect target=run:review view=communication
|
|
133
|
-
inspect target=room:review view=status
|
|
134
|
-
inspect target=room:review view=roster
|
|
135
|
-
inspect target=room:review view=contacts
|
|
136
|
-
inspect target=room:review view=previews
|
|
137
|
-
inspect target=room:review view=messages
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
Room posts require `from` to belong to the same run, so room rosters stay provenance-safe and do not mix actors from unrelated runs. `view=contacts` returns roster-derived direct-message targets without forcing agents to parse the full roster JSON. The extension also shows a small default terminal widget with recent room, direct actor-message, and coordinator/session broadcast previews. Full bodies remain an intentional `inspect` action.
|
|
75
|
+
Routing is inferred from `to`, actor ownership, and runtime policy. Recipes should expose semantic message types, not transport knobs.
|
|
141
76
|
|
|
142
|
-
##
|
|
77
|
+
## Golden Path
|
|
143
78
|
|
|
144
|
-
|
|
79
|
+
Create a reusable async actor recipe in the user recipe root:
|
|
145
80
|
|
|
146
|
-
```
|
|
147
|
-
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
Move to actor recipes when work is long-running, parallel, service-like, or agentic:
|
|
81
|
+
```bash
|
|
82
|
+
mkdir -p ~/.pi/agent/recipes
|
|
151
83
|
|
|
152
|
-
|
|
84
|
+
cat > ~/.pi/agent/recipes/docs_review.json <<'JSON'
|
|
153
85
|
{
|
|
154
|
-
"
|
|
86
|
+
"description": "Start an async docs review actor",
|
|
155
87
|
"async": true,
|
|
156
88
|
"args": ["scope:path", "model:string"],
|
|
157
|
-
"defaults": {},
|
|
158
89
|
"mailbox": {
|
|
159
|
-
"accepts": ["control.stop"],
|
|
90
|
+
"accepts": ["control.stop", "control.continue"],
|
|
160
91
|
"emits": ["review.completed", "run.failed"]
|
|
161
92
|
},
|
|
162
93
|
"template": "pi -p --model {model} --no-tools \"Review {scope} for unclear actor-runtime onboarding. Return concise findings.\""
|
|
163
94
|
}
|
|
95
|
+
JSON
|
|
164
96
|
```
|
|
165
97
|
|
|
166
|
-
|
|
98
|
+
Because it lives under `~/.pi/agent/recipes/`, the file becomes a persistent agent tool by location. The filename is the tool id.
|
|
99
|
+
|
|
100
|
+
Start it:
|
|
167
101
|
|
|
168
102
|
```text
|
|
169
|
-
|
|
103
|
+
docs_review scope="README.md" model="current-review-model" run_id=docs_review
|
|
170
104
|
```
|
|
171
105
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
## Compose Recipes With Imports
|
|
106
|
+
Inspect only when there is a reason:
|
|
175
107
|
|
|
176
|
-
|
|
108
|
+
```text
|
|
109
|
+
inspect target=run:docs_review view=status
|
|
110
|
+
inspect target=run:docs_review view=tail lines=80
|
|
111
|
+
inspect target=run:docs_review view=messages
|
|
112
|
+
inspect target=run:docs_review view=mailbox
|
|
113
|
+
```
|
|
177
114
|
|
|
178
|
-
|
|
115
|
+
Steer it through messages:
|
|
179
116
|
|
|
180
|
-
```
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
"args": ["scope:string", "model:string"],
|
|
184
|
-
"defaults": {},
|
|
185
|
-
"template": "pi -p --model {model} --no-tools \"Review {scope}\""
|
|
186
|
-
}
|
|
117
|
+
```text
|
|
118
|
+
message to=run:docs_review type=control.continue body=continue
|
|
119
|
+
message to=run:docs_review type=control.stop body=stop
|
|
187
120
|
```
|
|
188
121
|
|
|
189
|
-
|
|
122
|
+
## Actor Rooms
|
|
190
123
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
"
|
|
201
|
-
|
|
202
|
-
{ "name": "review", "values": { "scope": "docs/template-recipes.md" } }
|
|
203
|
-
]
|
|
204
|
-
}
|
|
124
|
+
Every spawned run can have a shared room at `room:<run>`. A room is not a broker and not a chat app. It is a run-local coordination surface: append-only timeline, compact roster, member discovery, and previews.
|
|
125
|
+
|
|
126
|
+
Actors can join, post, leave, and discover peers:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
message \
|
|
130
|
+
to=room:review \
|
|
131
|
+
from=branch:review/security \
|
|
132
|
+
type=actor.join \
|
|
133
|
+
summary="Security reviewer joined" \
|
|
134
|
+
body='{"role":"reviewer","caps":["security-review"],"claim":"Review auth boundary risks"}'
|
|
205
135
|
```
|
|
206
136
|
|
|
207
|
-
|
|
137
|
+
Inspect the room intentionally:
|
|
208
138
|
|
|
209
139
|
```text
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
140
|
+
inspect target=room:review view=status
|
|
141
|
+
inspect target=room:review view=previews
|
|
142
|
+
inspect target=room:review view=roster
|
|
143
|
+
inspect target=room:review view=contacts
|
|
144
|
+
inspect target=room:review view=messages
|
|
213
145
|
```
|
|
214
146
|
|
|
215
|
-
|
|
147
|
+
Room posts require a same-run sender, so unrelated runs do not pollute the roster. Direct messages and room messages use the same envelope; only the address changes.
|
|
148
|
+
|
|
149
|
+
## Registry Model
|
|
150
|
+
|
|
151
|
+
The persistent tool surface is file-discovered:
|
|
152
|
+
|
|
153
|
+
```text
|
|
154
|
+
~/.pi/agent/recipes/*.json
|
|
155
|
+
```
|
|
216
156
|
|
|
217
|
-
|
|
157
|
+
That directory is operator-managed executable memory.
|
|
218
158
|
|
|
219
|
-
|
|
159
|
+
Rules:
|
|
220
160
|
|
|
221
|
-
|
|
161
|
+
- User recipes in `~/.pi/agent/recipes/` are tools by location;
|
|
162
|
+
- Recipe filenames define tool ids;
|
|
163
|
+
- User recipes override same-name lower-priority recipes;
|
|
164
|
+
- Packaged recipes are standard-library components, not automatically installed operator policy;
|
|
165
|
+
- `register_tool` creates, updates, lists, or deletes user recipe files through the normal agent interface.
|
|
222
166
|
|
|
223
|
-
|
|
167
|
+
Example foreground tool:
|
|
224
168
|
|
|
225
169
|
```text
|
|
226
|
-
register_tool name=
|
|
170
|
+
register_tool name=transcribe_audio \
|
|
227
171
|
description="Transcribe a local audio file" \
|
|
228
|
-
template="/
|
|
172
|
+
template="~/bin/transcribe {file:path} {lang=ru} {model:string}"
|
|
229
173
|
```
|
|
230
174
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
For reusable actor workflows, keep the large template and mailbox contract in a recipe file and register a small tool:
|
|
175
|
+
Example recipe-backed tool:
|
|
234
176
|
|
|
235
177
|
```text
|
|
236
178
|
register_tool name=docs_review \
|
|
@@ -239,180 +181,107 @@ register_tool name=docs_review \
|
|
|
239
181
|
args="scope:path,model:string"
|
|
240
182
|
```
|
|
241
183
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
When keeping metadata and the recipe body together is clearer, `register_tool` writes a complete user recipe file:
|
|
184
|
+
Inspect the discovered registry:
|
|
245
185
|
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
"async": true,
|
|
250
|
-
"args": ["scope:path", "model:string"],
|
|
251
|
-
"template": "pi -p --model {model} --tools read,bash \"Review {scope}\""
|
|
252
|
-
}
|
|
186
|
+
```text
|
|
187
|
+
inspect target=recipes view=status
|
|
188
|
+
inspect target=recipes view=summary verbose=true
|
|
253
189
|
```
|
|
254
190
|
|
|
255
|
-
|
|
191
|
+
## Command Templates
|
|
256
192
|
|
|
257
|
-
|
|
193
|
+
A command template is the portable launch substrate. It can be a string, a sequence, or a composed graph.
|
|
258
194
|
|
|
259
|
-
|
|
260
|
-
register_tool name=call_subagent \
|
|
261
|
-
description="Run pi as a non-interactive sub-agent" \
|
|
262
|
-
template="pi -p --model {model} --no-tools {prompt}" args="prompt:string,model:string"
|
|
263
|
-
```
|
|
195
|
+
Templates support:
|
|
264
196
|
|
|
265
|
-
|
|
197
|
+
- Named placeholders: `{file}`, `{model}`, `{prompt}`;
|
|
198
|
+
- Compact types: `string`, `path`, `int`, `number`, `bool`, `enum(a,b)`;
|
|
199
|
+
- Defaults: `{lang=ru}`, `{dry_run:bool=true}`;
|
|
200
|
+
- Fallback and small ternary forms;
|
|
201
|
+
- Sequences with stdin flow;
|
|
202
|
+
- Parallel nodes;
|
|
203
|
+
- Retries, recovery, failure policy, delays, and guarded execution;
|
|
204
|
+
- Async run values such as `{run_id}`, `{state_dir}`, `{actor_address}`, `{default_room}`, and `{communication_file}`.
|
|
266
205
|
|
|
267
|
-
|
|
268
|
-
register_tool name=call_subagent \
|
|
269
|
-
description="Run a focused pi sub-agent without tools" \
|
|
270
|
-
update=true
|
|
271
|
-
```
|
|
206
|
+
The template owns execution shape. The recipe owns saved metadata, defaults, imports, mailbox, and artifacts. The run actor owns detached lifecycle, state, messages, cancellation, and inspection.
|
|
272
207
|
|
|
273
|
-
|
|
208
|
+
## Recipe Library
|
|
274
209
|
|
|
275
|
-
|
|
276
|
-
register_tool name=call_subagent template=null
|
|
277
|
-
```
|
|
210
|
+
Packaged recipes live under `recipes/` and helper scripts live under `scripts/`.
|
|
278
211
|
|
|
279
|
-
|
|
212
|
+
The library includes:
|
|
280
213
|
|
|
281
|
-
|
|
214
|
+
- Sub-agent launchers;
|
|
215
|
+
- Review, critic, planner, verifier, merger, judge, normalizer, and artifact atoms;
|
|
216
|
+
- Quorum and lens-style pipelines;
|
|
217
|
+
- Repo-health, release-summary, research-synthesis, development-tasking, docs-maintenance, and room-swarm pipelines;
|
|
218
|
+
- Coordinator-locker and actor-message utilities;
|
|
219
|
+
- Local music-player actor recipe.
|
|
282
220
|
|
|
283
|
-
|
|
284
|
-
{
|
|
285
|
-
"description": "Transcribe a local audio file",
|
|
286
|
-
"template": "/path/to/stt --file {file} --lang {lang=ru}"
|
|
287
|
-
}
|
|
288
|
-
```
|
|
221
|
+
Packaged recipes are building blocks. Copy them into `~/.pi/agent/recipes/` or register tools that point at them when they should become durable operator-facing capabilities.
|
|
289
222
|
|
|
290
|
-
|
|
291
|
-
{
|
|
292
|
-
"description": "Run pi as a non-interactive sub-agent",
|
|
293
|
-
"args": ["prompt:string", "model:string"],
|
|
294
|
-
"template": "pi -p --model {model} --no-tools {prompt}"
|
|
295
|
-
}
|
|
296
|
-
```
|
|
223
|
+
## When To Use What
|
|
297
224
|
|
|
298
|
-
|
|
225
|
+
Use a foreground registered tool when the work is short, bounded, and does not need lifecycle.
|
|
299
226
|
|
|
300
|
-
|
|
227
|
+
Use an async recipe or `spawn` when the work is long-running, service-like, parallel, agentic, artifact-producing, or needs later control.
|
|
301
228
|
|
|
302
|
-
Use `
|
|
229
|
+
Use `room:<run>` when multiple actors in the same run need shared context, roster discovery, or group-visible progress.
|
|
303
230
|
|
|
304
|
-
|
|
231
|
+
Use artifacts when outputs should survive context compression.
|
|
305
232
|
|
|
306
|
-
|
|
307
|
-
{
|
|
308
|
-
"as": "run:docs_review",
|
|
309
|
-
"template": "pi -p --model {model} --no-tools {prompt}",
|
|
310
|
-
"values": {
|
|
311
|
-
"prompt": "Review docs/spec.md for contradictions.",
|
|
312
|
-
"model": "current-review-model"
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
```
|
|
233
|
+
Use mailbox declarations when an actor has a stable conversational surface.
|
|
316
234
|
|
|
317
|
-
|
|
235
|
+
## Safety Boundary
|
|
318
236
|
|
|
319
|
-
|
|
320
|
-
{ "to": "run:docs_review", "type": "control.continue", "body": "continue" }
|
|
321
|
-
```
|
|
237
|
+
`pi-actors` is local-first, not sandbox-first.
|
|
322
238
|
|
|
323
|
-
|
|
239
|
+
Commands execute directly without shell evaluation where possible, but trusted executables still run with the same system permissions as Pi. Only register commands, scripts, recipes, and paths you trust.
|
|
324
240
|
|
|
325
|
-
|
|
326
|
-
{ "target": "run:docs_review", "view": "tail", "lines": "80" }
|
|
327
|
-
```
|
|
241
|
+
High-risk templates such as shells, interpreter eval modes, and broad filesystem mutation may surface warnings, but the runtime is not a security boundary.
|
|
328
242
|
|
|
329
|
-
|
|
243
|
+
Prefer:
|
|
330
244
|
|
|
331
|
-
|
|
245
|
+
- Narrow commands;
|
|
246
|
+
- Explicit paths;
|
|
247
|
+
- Typed args;
|
|
248
|
+
- Bounded timeouts for bounded work;
|
|
249
|
+
- Explicit tool allowlists for sub-agents;
|
|
250
|
+
- Deterministic utility recipes for filesystem writes;
|
|
251
|
+
- Human approval for destructive or external side effects.
|
|
332
252
|
|
|
333
|
-
|
|
253
|
+
## Non-Goals
|
|
334
254
|
|
|
335
|
-
|
|
255
|
+
`pi-actors` is NOT:
|
|
336
256
|
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
description="Start an async pi subagent with an explicit tool allowlist" \
|
|
344
|
-
template="subagent-tools.json"
|
|
345
|
-
|
|
346
|
-
register_tool name=subagents_prompts \
|
|
347
|
-
description="Start parallel no-tools subagents from a prompt array as one run actor" \
|
|
348
|
-
template="subagents-prompts.json"
|
|
349
|
-
|
|
350
|
-
subagent_prompt prompt="Review docs/async-runs.md for unclear wording." run_id=docs_review
|
|
351
|
-
subagent_tools prompt="Inspect package metadata and report risks." tools="read,bash" run_id=package-review
|
|
352
|
-
subagents_prompts \
|
|
353
|
-
prompts='["Review README.md for unclear release-onboarding wording. Return concise findings.","Review docs/template-recipes.md for unclear recipe-import wording. Return concise findings."]' \
|
|
354
|
-
run_id=review-prompts
|
|
355
|
-
inspect target=run:review-prompts view=tail
|
|
356
|
-
```
|
|
257
|
+
- A generic workflow DSL;
|
|
258
|
+
- A remote agent interoperability protocol;
|
|
259
|
+
- A heavyweight broker or chat subsystem;
|
|
260
|
+
- A sandbox;
|
|
261
|
+
- A facade that hides logs, artifacts, ownership, or local side effects;
|
|
262
|
+
- A polling-first async runner.
|
|
357
263
|
|
|
358
|
-
|
|
264
|
+
Its job is narrower: make trusted local capabilities addressable, messageable, inspectable, and reusable by agents.
|
|
359
265
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
template="music-player.json" \
|
|
364
|
-
args="source:string,loop:bool=true,volume:int=70,player:enum(auto,mpv,ffplay,cvlc,play)=auto"
|
|
365
|
-
|
|
366
|
-
music_player source="~/Music" volume=55 run_id=music
|
|
367
|
-
message to=run:music type=player.next body=next
|
|
368
|
-
message to=run:music type=player.pause body=pause
|
|
369
|
-
message to=run:music type=player.play body=play
|
|
370
|
-
message to=run:music type=player.stop body=stop
|
|
371
|
-
```
|
|
266
|
+
## Documentation
|
|
267
|
+
|
|
268
|
+
Start here:
|
|
372
269
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
-
|
|
378
|
-
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
-
|
|
383
|
-
-
|
|
384
|
-
-
|
|
385
|
-
-
|
|
386
|
-
-
|
|
387
|
-
-
|
|
388
|
-
- Timeout is disabled by default; set a positive `timeout` on bounded commands that should fail closed. Numeric node fields may read placeholders such as `timeout: "{timeout_ms}"`.
|
|
389
|
-
- Nodes may set `when` to skip conditional work and `delay` in milliseconds to wait before launch; delay is not inherited.
|
|
390
|
-
- Failed steps default to `failure: "continue"`, which records the failure and continues with empty stdin.
|
|
391
|
-
- `failure: "branch"` stops the current sequence/subtree without cancelling sibling parallel branches; `failure: "root"` aborts the composition.
|
|
392
|
-
- `retry` retries a leaf or whole node on non-zero exit; default attempts is `1`.
|
|
393
|
-
- `recover` runs a cleanup command template between failed retry attempts and stops retries if cleanup fails.
|
|
394
|
-
- Commands execute directly without shell evaluation, but trusted executables still run with the same permissions as pi.
|
|
395
|
-
- Obvious high-risk templates such as shells, interpreter eval modes, and broad filesystem mutation surface lightweight warnings without blocking existing tools.
|
|
396
|
-
- `async: true` on a recipe selects detached run-actor lifecycle; omitted or false runs the recipe foreground through registered tools.
|
|
397
|
-
- Layer boundaries stay explicit: command templates define synchronous execution graphs; template recipes add saved JSON metadata/import resolution and named `artifacts`; run actors add detached lifecycle, state, IPC, and observability.
|
|
398
|
-
- `spawn`, `message`, and `inspect` are high-level actor adapters. `spawn` creates `run:<id>` actors from recipes or inline templates with optional state/artifact metadata, `message` sends one typed envelope to `run:<id>` mailboxes, `branch:<run>/<branch>` mailboxes, `room:<run>` task rooms, `tool:<name>` calls, or coordinator/session attention paths, and `inspect` intentionally reads `run:<id>` status/tail/messages/mailbox metadata, `room:<run>` status/messages/previews/roster/contacts, coordinator/session run status, or registered `tool:<name>` contracts while the broader actor/message protocol is refined.
|
|
399
|
-
- `spawn`, `message`, and `inspect` are the public async coordination vocabulary. Low-level async actions map to this actor API: start belongs to `spawn`; send/control/stop/kill belongs to `message`; status/tail/messages/list belongs to `inspect`. Use `inspect view=messages` for actor-envelope streams. Use `control.stop`, `control.cancel`, and `control.kill` for run termination; runtime-prefixed control aliases are no longer part of the public surface.
|
|
400
|
-
- Actor management returns compact text by default; pass `verbose: true` to `inspect` when full JSON state is needed.
|
|
401
|
-
- Detached runs inject `{run_id}` and `{state_dir}` into template values for run-local artifacts or recipe-specific control endpoints.
|
|
402
|
-
- Runtime actor messages are persisted in the run state dir; coordinator attention is inferred by the runtime, not exposed as recipe or message-envelope input. Follow-ups preserve bounded body previews and metadata for decision messages.
|
|
403
|
-
- Native Windows should use WSL or a recipe-specific transport for run-local message-controlled recipes; Linux uses stricter `/proc` runner ownership checks for stale PID protection.
|
|
404
|
-
- Registered tools may set `template` to a recipe JSON path/name; calling them follows that recipe's `async` mode.
|
|
405
|
-
- File-backed recipes may declare `imports` and embed imported recipes with `{ "name": "alias" }` nodes, or read `{alias.defaults.key}`, `{alias.defaults.key=fallback}`, and `{alias.values.key?yes:no}` references before command-template execution.
|
|
406
|
-
- Interactive sessions show ambient actor activity as stable `▷` triangles aggregated across runs started by the current agent session. Each running run actor contributes at least one triangle; parallel active branches can contribute more. One `▶` wave moves over the active set; terminal `done`/`failed`/unhandled `killed`/`exited` messages are delivered as compact follow-up context only to the launching coordinator agent, while intentional `cancel`, `kill`, and `stop` actions stay silent because the action already reports synchronously. Failed commands and in-flight parallel branch completions can bubble through `command.done`; successful final leaf completions remain diagnostic to avoid sequential pipeline noise.
|
|
407
|
-
- Use `{file}` as the canonical local file path arg.
|
|
408
|
-
- Stored `script` entries are rejected with migration guidance.
|
|
409
|
-
|
|
410
|
-
See [`docs/command-templates.md`](./docs/command-templates.md) for the portable synchronous command-template contract; [`docs/template-recipes.md`](./docs/template-recipes.md) for saved recipe JSON; [`docs/async-runs.md`](./docs/async-runs.md) for detached lifecycle, state files, cancellation, and observability; [`docs/tool-registry.md`](./docs/tool-registry.md) for registry storage; and [`docs/recipe-library.md`](./docs/recipe-library.md) for the packaged standard recipe library.
|
|
411
|
-
|
|
412
|
-
## Notes
|
|
413
|
-
|
|
414
|
-
- Only register trusted local commands. Registered tools run with the same system permissions as pi.
|
|
415
|
-
- `index.ts` is a small composition root; reusable behavior lives in flat `/lib` domains covered by focused tests.
|
|
270
|
+
- [Project context](./AGENTS.md)
|
|
271
|
+
- [Changelog](./CHANGELOG.md)
|
|
272
|
+
- [Open backlog](./BACKLOG.md)
|
|
273
|
+
- [Documentation index](./docs/README.md)
|
|
274
|
+
- [Actors skill](./skills/actors/SKILL.md)
|
|
275
|
+
- [Swarm skill](./skills/swarm/SKILL.md)
|
|
276
|
+
|
|
277
|
+
Core docs:
|
|
278
|
+
|
|
279
|
+
- [Command templates](./docs/command-templates.md)
|
|
280
|
+
- [Template recipes](./docs/template-recipes.md)
|
|
281
|
+
- [Async runs](./docs/async-runs.md)
|
|
282
|
+
- [Actor messages](./docs/actor-messages.md)
|
|
283
|
+
- [Tool registry](./docs/tool-registry.md)
|
|
284
|
+
- [Recipe library](./docs/recipe-library.md)
|
|
416
285
|
|
|
417
286
|
## License
|
|
418
287
|
|
package/docs/actor-messages.md
CHANGED
|
@@ -94,7 +94,7 @@ Transports differ, but the public contract does not:
|
|
|
94
94
|
|
|
95
95
|
- `to: run:<id>` routes through the run-local control channel selected by that recipe or runtime adapter.
|
|
96
96
|
- `to: coordinator` routes to the runtime attention path when `from` names a run actor. `to: session:<id>` uses the same actor-message path only when the sender run is owned by that session, making explicit session-directed checkpoints possible without exposing runtime delivery knobs. Generic async-runner `command.done` messages and explicit coordinator/session-bound messages include the actor envelope fields alongside runtime metadata.
|
|
97
|
-
- `to: branch:<run>/<branch>` routes through the parent run mailbox with the full envelope preserved so the run can dispatch branch-local control.
|
|
97
|
+
- `to: branch:<run>/<branch>` routes through the parent run mailbox with the full envelope preserved so the run or recipe-specific worker protocol can dispatch branch-local control. It is not a broadcast room and it does not make an arbitrary prompt process consume the message automatically.
|
|
98
98
|
- `to: room:<run>` appends the full envelope to the room timeline and updates room state for room-control types such as `actor.join` and `actor.leave`.
|
|
99
99
|
- `to: tool:<name>` invokes an executable pi tool by name. Object bodies become tool parameters; primitive bodies are passed as `{ "input": body }`.
|
|
100
100
|
|
|
@@ -104,6 +104,8 @@ Transport is not public API unless a recipe explicitly documents a custom endpoi
|
|
|
104
104
|
|
|
105
105
|
The task room is the discovery and shared-context layer for actors whose spawn-tree positions do not give them each other's addresses. The spawn tree remains the lifecycle/provenance structure; the task room describes the group communication graph. Direct messages and room messages can share the same semantic `type` such as `chat.message`; the route (`to: branch:*` versus `to: room:*`) determines whether delivery is private or group-wide.
|
|
106
106
|
|
|
107
|
+
Use direct branch messages only when the receiving branch is backed by a worker or recipe that reads the parent run mailbox and dispatches branch-targeted envelopes. Room roster contacts are discovery hints, not a guarantee that an independent prompt process is subscribed to its branch address. For ad hoc or transcript-driven swarms, prefer room-visible replies and mentions so every participant can inspect the shared timeline.
|
|
108
|
+
|
|
107
109
|
A minimal join message:
|
|
108
110
|
|
|
109
111
|
```json
|
package/docs/recipe-library.md
CHANGED
|
@@ -82,6 +82,7 @@ Pipeline recipes demonstrate second-order composition:
|
|
|
82
82
|
- `recipes/pipeline-development-tasking.json`: Plan → task card → critique → integrator handoff.
|
|
83
83
|
- `recipes/pipeline-docs-maintenance.json`: Docs index → documentation review → maintenance plan → artifact report.
|
|
84
84
|
- `recipes/pipeline-media-library.json`: Playlist build → media-library artifact report.
|
|
85
|
+
- `recipes/pipeline-room-swarm.json`: Room participants join `room:<run>`, coordinate over repeated room-visible rounds, leave cleanly, and synthesize the room transcript into a caller-provided artifact path. Keep model/thinking/mission policy caller-owned. Custom roles can be supplied with `roles_path` as a JSON array of `{ "name", "persona", "glyph" }` objects; `name` stays ASCII-safe for `branch:<run>/<name>` addresses, while optional `glyph` is display-only for room summaries and operator scanning. The packaged swarm uses contacts for peer awareness but does not rely on direct branch delivery unless a caller-specific worker protocol consumes branch envelopes. Set `locker=true` to compose a local `coordinator-locker` cell under `{state_dir}/locker` for artifact ownership, resource lease locks, and a decision journal without merging locker policy into the room-participant script.
|
|
85
86
|
- `recipes/pipeline-artifact-report.json`: Normalize → artifact-shaped output → actor-message-shaped record. This pipeline prepares a candidate artifact and emits `artifact.prepared`/`artifact.blocked`; the `artifact_path` is a target path, not a guarantee that the file was written.
|
|
86
87
|
- `recipes/pipeline-artifact-write.json`: Normalize → artifact-shaped output → deterministic artifact write → actor-message-shaped record. Use only when the caller explicitly wants filesystem writes; `write_mode` is `create`, `overwrite`, or `append`.
|
|
87
88
|
- `recipes/pipeline-artifact-bundle.json`: Optional validation → deterministic artifact write → machine-readable manifest generation → deterministic manifest write → actor-message-shaped record. Use when the caller explicitly wants a filesystem handoff bundle with both artifact and manifest paths.
|