@llblab/pi-actors 0.12.13 → 0.13.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.
package/BACKLOG.md CHANGED
@@ -6,7 +6,7 @@ Continue progressive component/pipeline expansion in small validated slices; rea
6
6
 
7
7
  - Plan organic universal communication primitives.
8
8
  - Priority: High.
9
- - Status: The actor-like model is empirically useful: async runs can emit follow-up messages upward, coordinators can send run-local commands downward, multiple parallel runs can progress independently, and recipes no longer need sleep-poll coordination. The design is captured in `docs/actor-messages.md`: `spawn`, `message`, and `inspect` as concentrated verbs; addressed actors; one symmetric message envelope; mailbox `accepts`/`emits`; and adapter mappings from runtime async actions. Initial implementation landed pure actor address/message normalization plus public `spawn`, `message`, and `inspect` tools for `run:<id>` actors; `spawn` accepts state/artifact metadata, `message` routes `run:<id>` → `coordinator` and `run:<id>` → `session:<id>` envelopes into the runtime attention path, `message` can invoke `tool:<name>` actors, `inspect target=tool:<name>` exposes registered tool actor contracts, `inspect target=coordinator` exposes current-session run inventory, all packaged async recipes declare mailbox metadata, `inspect view=mailbox` exposes recipe mailbox contracts from run metadata, recipe-authored messages now use envelope-aligned `type` fields with deterministic validated wrapping available through `utility-actor-message`, run termination now accepts actor-native `control.stop`/`control.cancel`/`control.kill` aliases while preserving legacy `runtime.*` compatibility, async command events preserve full argv details while keeping coordinator summaries bounded, and async-run operations recommendations now emit structured `message`/`inspect` objects instead of shell-like suggestion strings. Remaining work is to absorb remaining runtime async action surfaces into the actor vocabulary instead of preserving a parallel public API.
9
+ - Status: The actor-like model is empirically useful: async runs can emit follow-up messages upward, coordinators can send run-local commands downward, multiple parallel runs can progress independently, and recipes no longer need sleep-poll coordination. The design is captured in `docs/actor-messages.md`: `spawn`, `message`, and `inspect` as concentrated verbs; addressed actors; one symmetric message envelope; mailbox `accepts`/`emits`; and adapter mappings from runtime async actions. Initial implementation landed pure actor address/message normalization plus public `spawn`, `message`, and `inspect` tools for `run:<id>` actors; `spawn` accepts state/artifact metadata, `message` routes `run:<id>` → `coordinator` and `run:<id>` → `session:<id>` envelopes into the runtime attention path, `message` can invoke `tool:<name>` actors, `inspect target=tool:<name>` exposes registered tool actor contracts, `inspect target=coordinator` exposes current-session run inventory, all packaged async recipes declare mailbox metadata, `inspect view=mailbox` exposes recipe mailbox contracts from run metadata, recipe-authored messages now use envelope-aligned `type` fields with deterministic validated wrapping available through `utility-actor-message`, run termination now uses actor-native `control.stop`/`control.cancel`/`control.kill` without runtime-prefixed control aliases, async command events preserve full argv details while keeping coordinator summaries bounded, async-run operations recommendations now emit structured `message`/`inspect` objects instead of shell-like suggestion strings, `inspect view=messages` exposes run actor messages while retaining `events` as a compatibility alias, async-run operations recipes now expose `message_file`/`messages` terminology instead of public event-file args, and operator-facing docs now describe coordination with actor-message terminology before transport details, async-run docs separate public actor behavior from storage/transport mechanics more clearly, public actor-message/template guidance avoids transport-specific wording, and async-run operations recipes now use only `message_file` for actor-message inputs. Remaining work is to absorb remaining runtime async action surfaces into the actor vocabulary instead of preserving a parallel public API.
10
10
  - Scope: Design and implement a small semantic layer around addressed messages and actors while preserving low-level primitives as adapters where useful. Candidate top-level concepts are `spawn` for creating an actor/run from a recipe or template, `message` for sending typed messages to any address, and `inspect` for intentional observation/debugging. Candidate addresses include `run:<id>`, `branch:<run>/<branch>`, `coordinator`, `session:<id>`, `tool:<name>`, and future chat/session endpoints. Candidate message fields include `to`, `from`, `type`, `summary`, `body`, `reply_to`, `correlation_id`, and `metadata`.
11
11
  - Contract direction: Unify “send down” and “messages up” as one message model. `to: run:<id>` routes to a run mailbox, `to: coordinator` routes to the coordinator attention path, and branch/tool/session addresses can be layered over the same semantic envelope. Recipes should declare mailbox capability (`accepts`, `emits`) without exposing FIFO/outbox mechanics or delivery policy as their public interface.
12
12
  - Design gates: Breaking changes are allowed in this phase, so compress concepts instead of preserving accidental surfaces. Consolidate duplicated lifecycle/message/event APIs into a concentrated protocol with the fewest durable nouns and verbs that still explain the system. Duplex communication should be symmetric where the domain is symmetric: the same message envelope should represent run→coordinator, coordinator→run, run→run, branch→parent, and parent→branch traffic, with routing/transport hidden below it. Keep command templates as the portable synchronous execution graph; keep recipe files as semantic definitions; avoid leaking transports into public args; make polling an explicit diagnostic operation, not an example path; replace runtime action names with the actor API rather than preserving parallel concepts.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,31 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.13.3: Actor Vocabulary Cleanup
4
+
5
+ - `[Docs]` Removed remaining public FIFO/outbox phrasing from actor-message/template-recipe docs and runtime prompt guidance. Impact: agent and operator guidance now consistently describes `spawn`, `message`, and `inspect` without transport-specific vocabulary.
6
+ - `[Recipe Library]` Removed the legacy `event_file` default from async-run operations recipes. Impact: the recipe surface now uses only `message_file` for run actor-message inputs.
7
+
8
+ ## 0.13.2: Async Run Actor Vocabulary Docs
9
+
10
+ - `[Docs]` Reframed `docs/async-runs.md` around actor messages and run-local control channels, keeping file names and transport details in implementation sections. Impact: the async-run standard now separates public `spawn`/`message`/`inspect` behavior from storage/transport mechanics more clearly.
11
+
12
+ ## 0.13.1: Public Actor Vocabulary Docs
13
+
14
+ - `[Docs]` Replaced remaining public README and recipe-library wording that described run coordination as events, FIFO, or outbox paths with actor-message and run-local control-channel terminology. Impact: operator-facing docs now teach the actor vocabulary first while keeping transport details in the async-run implementation reference.
15
+
16
+ ## 0.13.0: Actor-Native Control Surface
17
+
18
+ - `[Actor Messages]` Removed `runtime.cancel` and `runtime.kill` termination aliases from `message to=run:<id>`. Impact: run termination now uses only actor-native `control.stop`, `control.cancel`, and `control.kill`; runtime-prefixed control names are no longer treated as public API.
19
+
20
+ ## 0.12.15: Run Operations Message File Vocabulary
21
+
22
+ - `[Recipe Library]` Renamed async-run operations recipe inputs from `event_file` to `message_file`, with legacy `event_file` retained only as an internal default fallback. Impact: public recipe args align with the actor-message vocabulary while existing value-based launches can still supply the old key.
23
+ - `[Recipe Utilities]` Renamed `run-ops-snapshot` output from `events` to `messages`. Impact: operations reports now describe run outbox records as actor messages instead of runtime events.
24
+
25
+ ## 0.12.14: Actor Message Inspection Alias
26
+
27
+ - `[Actor Messages]` Added `inspect view=messages` for run actors, with `events` retained as a compatibility alias for the same outbox-backed actor messages. Impact: the public inspection vocabulary now matches the actor/message model while preserving existing event-oriented diagnostics.
28
+
3
29
  ## 0.12.13: Structured Run Operations Recommendations
4
30
 
5
31
  - `[Recipe Utilities]` Changed `utility-run-ops-snapshot` recommendations from shell-like suggestion strings to structured `message` and `inspect` call objects. Impact: async-run operations reports now preserve the actor API shape directly and avoid reintroducing command-string parsing into coordinator handoffs.
package/README.md CHANGED
@@ -295,13 +295,13 @@ Start from an inline template as an addressable run actor:
295
295
  }
296
296
  ```
297
297
 
298
- Do not check it on a timer. Let follow-up events arrive from the run, then react to a run-local request or redirect a long-lived recipe without polling/restarting it:
298
+ Do not check it on a timer. Let follow-up actor messages arrive from the run, then react to a run-local request or redirect a long-lived recipe without polling/restarting it:
299
299
 
300
300
  ```json
301
301
  { "to": "run:docs-review", "type": "control.continue", "body": "continue" }
302
302
  ```
303
303
 
304
- Read recent events or logs only after a follow-up asks for inspection, at a real decision point, or during diagnosis:
304
+ Read recent actor messages or logs only after a follow-up asks for inspection, at a real decision point, or during diagnosis:
305
305
 
306
306
  ```json
307
307
  { "target": "run:docs-review", "view": "tail", "lines": "80" }
@@ -376,12 +376,12 @@ See [`docs/recipe-library.md`](./docs/recipe-library.md) for install notes and r
376
376
  - Obvious high-risk templates such as shells, interpreter eval modes, and broad filesystem mutation surface lightweight warnings without blocking existing tools.
377
377
  - `async: true` on a recipe selects detached run lifecycle; omitted or false async runs the recipe foreground through registered tools.
378
378
  - Layer boundaries stay explicit: command templates define synchronous execution graphs; template recipes add saved JSON metadata/import resolution and named `artifacts`; async runs add detached lifecycle, state, IPC, and observability.
379
- - `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, `tool:<name>` calls, or coordinator/session attention paths, and `inspect` intentionally reads `run:<id>` status/tail/events/mailbox metadata, coordinator/session run status, or registered `tool:<name>` contracts while the broader actor/message protocol is refined.
380
- - `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/events/list belongs to `inspect`. Prefer `control.stop` and `control.kill` for run termination; legacy `runtime.cancel` and `runtime.kill` remain compatibility aliases.
379
+ - `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, `tool:<name>` calls, or coordinator/session attention paths, and `inspect` intentionally reads `run:<id>` status/tail/messages/mailbox metadata, coordinator/session run status, or registered `tool:<name>` contracts while the broader actor/message protocol is refined.
380
+ - `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`; `events` remains a compatibility inspection view. Use `control.stop`, `control.cancel`, and `control.kill` for run termination; runtime-prefixed control aliases are no longer part of the public surface.
381
381
  - Actor management returns compact text by default; pass `verbose: true` to `inspect` when full JSON state is needed.
382
382
  - Detached runs inject `{run_id}` and `{state_dir}` into template values for run-local artifacts or recipe-specific control endpoints.
383
- - Runtime actor messages are stored in `<state_dir>/outbox.jsonl`; 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.
384
- - Native Windows should use WSL or a recipe-specific transport for FIFO-controlled recipes; Linux uses stricter `/proc` runner ownership checks for stale PID protection.
383
+ - 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.
384
+ - 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.
385
385
  - Registered tools may set `template` to a recipe JSON path/name; calling them follows that recipe's `async` mode.
386
386
  - 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.
387
387
  - Interactive sessions show ambient async activity as stable `▷` triangles aggregated across runs started by the current agent session. Each running async run 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.
@@ -8,7 +8,7 @@ Compress communication to three durable verbs:
8
8
 
9
9
  - `spawn`: create an addressable actor from a recipe, template, or tool.
10
10
  - `message`: send one typed message to one address.
11
- - `inspect`: intentionally observe state, logs, events, or artifacts.
11
+ - `inspect`: intentionally observe state, logs, actor messages, or artifacts.
12
12
 
13
13
  Everything else is an adapter until proven otherwise.
14
14
 
@@ -78,8 +78,8 @@ coordinator -> tool
78
78
 
79
79
  Transports differ, but the public contract does not:
80
80
 
81
- - `to: run:<id>` may route to FIFO, mailbox file, socket, or process stdin.
82
- - `to: coordinator` routes to outbox/watch/follow-up delivery 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` events and explicit coordinator/session-bound messages include the actor envelope fields alongside the runtime event fields.
81
+ - `to: run:<id>` routes through the run-local control channel selected by that recipe or runtime adapter.
82
+ - `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.
83
83
  - `to: branch:<run>/<branch>` routes through the parent run mailbox with the full envelope preserved so the run can dispatch branch-local control.
84
84
  - `to: tool:<name>` invokes an executable pi tool by name. Object bodies become tool parameters; primitive bodies are passed as `{ "input": body }`.
85
85
 
@@ -92,13 +92,18 @@ Recipes can declare their conversational surface:
92
92
  ```json
93
93
  {
94
94
  "mailbox": {
95
- "accepts": ["control.continue", "control.revise", "control.approve", "control.stop"],
95
+ "accepts": [
96
+ "control.continue",
97
+ "control.revise",
98
+ "control.approve",
99
+ "control.stop"
100
+ ],
96
101
  "emits": ["checkpoint.needs_scope", "branch.done", "run.done"]
97
102
  }
98
103
  }
99
104
  ```
100
105
 
101
- `mailbox.accepts` is a contract for coordinator-to-actor messages. `mailbox.emits` is a contract for actor-to-coordinator or actor-to-actor messages. Packaged interactive and message-producing recipes declare mailbox metadata so coordinators can discover semantic message types without reading FIFO details. Message-producing recipes produce actor-message-envelope-shaped records with `to`, `from`, `type`, `summary`, `body`, optional `correlation_id`/`reply_to`, and optional `metadata` fields. Coordinator follow-ups preserve bounded body previews and metadata so checkpoints do not lose their actionable payload. Deterministic pipelines should prefer `utility-actor-message` for this wrapping so message shape is validated and guaranteed instead of delegated to a prompt; its recipe args intentionally mirror the envelope field names.
106
+ `mailbox.accepts` is a contract for coordinator-to-actor messages. `mailbox.emits` is a contract for actor-to-coordinator or actor-to-actor messages. Packaged interactive and message-producing recipes declare mailbox metadata so coordinators can discover semantic message types without reading transport details. Message-producing recipes produce actor-message-envelope-shaped records with `to`, `from`, `type`, `summary`, `body`, optional `correlation_id`/`reply_to`, and optional `metadata` fields. Coordinator follow-ups preserve bounded body previews and metadata so checkpoints do not lose their actionable payload. Deterministic pipelines should prefer `utility-actor-message` for this wrapping so message shape is validated and guaranteed instead of delegated to a prompt; its recipe args intentionally mirror the envelope field names.
102
107
 
103
108
  ## Spawn
104
109
 
@@ -126,7 +131,7 @@ Recipes can declare their conversational surface:
126
131
  }
127
132
  ```
128
133
 
129
- The implementation supports `status`, `tail`, `events`, `artifacts`, `files`, and `mailbox` for `run:<id>` actors, `status`/`runs` for `coordinator`, `session:<id>`, and `session:all` actors with optional status filtering, and `status`/`schema` for registered `tool:<name>` actors. `inspect target=coordinator` requires a current coordinator session; use `session:<id>` or `session:all` when the session is intentionally explicit. Direct `run:<id>` inspection respects coordinator-session ownership when the current session is known. `inspect` is for decision points and diagnosis only; examples must not teach sleep-then-inspect polling.
134
+ The implementation supports `status`, `tail`, `messages`, `events`, `artifacts`, `files`, and `mailbox` for `run:<id>` actors, `status`/`runs` for `coordinator`, `session:<id>`, and `session:all` actors with optional status filtering, and `status`/`schema` for registered `tool:<name>` actors. Prefer `messages` for actor-envelope inspection; `events` remains a compatibility alias for the same run message stream. `inspect target=coordinator` requires a current coordinator session; use `session:<id>` or `session:all` when the session is intentionally explicit. Direct `run:<id>` inspection respects coordinator-session ownership when the current session is known. `inspect` is for decision points and diagnosis only; examples must not teach sleep-then-inspect polling.
130
135
 
131
136
  ## Runtime Direction
132
137
 
@@ -144,7 +149,7 @@ intentional observe -> inspect
144
149
  ## Non-goals
145
150
 
146
151
  - No generic expression language in templates.
147
- - No public FIFO/outbox vocabulary in recipe args.
152
+ - No public transport-path vocabulary in recipe args.
148
153
  - No polling-first examples.
149
154
  - No separate upward and downward message schemas.
150
155
  - No broad facade that hides artifacts, logs, or ownership checks.
@@ -2,11 +2,11 @@
2
2
 
3
3
  Async runs are detached executions of a template recipe or inline command template.
4
4
 
5
- **Meta-contract:** the command template is still the execution graph; the async run is only a lifecycle envelope with state, logs, script-authored events, status, cancellation, and coordinator-scoped observability.
5
+ **Meta-contract:** the command template is still the execution graph; the async run is only a lifecycle envelope with state, logs, actor messages, status, cancellation, and coordinator-scoped observability.
6
6
 
7
- **Scope:** run id, state path, runner pid, process-group cancellation, logs, status, tail, list, script-authored event outbox, line-message send to a run-local Unix FIFO, cancel, force-kill, terminal result state, ambient activity indicators, and extension-owned temp storage. No scheduler, queue daemon, workflow DSL, distributed worker, or second execution language.
7
+ **Scope:** run id, state path, runner pid, process-group cancellation, logs, status, tail, list, script-authored actor messages, run-local control messages, cancel, force-kill, terminal result state, ambient activity indicators, and extension-owned temp storage. No scheduler, queue daemon, workflow DSL, distributed worker, or second execution language.
8
8
 
9
- Layer boundary: async-run configuration may inject lifecycle values such as `{run_id}` and `{state_dir}` and may choose detached execution through `async: true`, but it does not add command-template graph syntax. Recipe imports and recipe-local references belong to the template-recipe layer; status, send, events, cancel, and kill belong to the async-run layer.
9
+ Layer boundary: async-run configuration may inject lifecycle values such as `{run_id}` and `{state_dir}` and may choose detached execution through `async: true`, but it does not add command-template graph syntax. Recipe imports and recipe-local references belong to the template-recipe layer; status, control messages, actor messages, cancel, and kill belong to the async-run layer.
10
10
 
11
11
  ---
12
12
 
@@ -15,7 +15,7 @@ Layer boundary: async-run configuration may inject lifecycle values such as `{ru
15
15
  Async-run standard owns:
16
16
 
17
17
  - Detached process lifecycle for one execution instance.
18
- - Run identity, state directory, pid/process-group tracking, logs, status, list, tail, events, send, cancel, and kill.
18
+ - Run identity, state directory, pid/process-group tracking, logs, status, list, tail, actor-message inspection, run-local control, cancel, and kill.
19
19
  - Injected lifecycle values such as `{run_id}` and `{state_dir}`.
20
20
  - Coordinator-scoped observability and script-authored actor messages.
21
21
 
@@ -31,8 +31,8 @@ Async-run standard does not own:
31
31
  ```text
32
32
  recipe = saved JSON definition
33
33
  run = one execution instance
34
- lifecycle = state/logs/events/status/send/cancel/kill envelope
35
- state dir = ordinary files for status/logs/events/result
34
+ lifecycle = state/logs/messages/status/control/cancel/kill envelope
35
+ state dir = ordinary files for status/logs/messages/result
36
36
  coordinator = agent session that started the run
37
37
  ```
38
38
 
@@ -80,8 +80,8 @@ Use ordinary files under the extension temp directory so status tools stay simpl
80
80
 
81
81
  - `run.json`: pid, optional source metadata (`tool`, `recipe`, `recipe_file`), command-template config, cwd, coordinator owner id, values, named `artifacts`, mailbox metadata, created time, and state dir.
82
82
  - `progress.json`: phase, active command count, completed count, failures, and updated time.
83
- - `events.jsonl`: append-only lifecycle events.
84
- - `outbox.jsonl`: optional script-authored JSONL actor-message events for coordinator inspection, notifications, or follow-up context. Coordinator follow-ups preserve bounded `body` previews plus message metadata for decision points.
83
+ - `events.jsonl`: append-only implementation lifecycle log.
84
+ - `outbox.jsonl`: implementation storage for actor-message envelopes used by `inspect view=messages`, coordinator notifications, or follow-up context. Coordinator follow-ups preserve bounded `body` previews plus message metadata for decision points.
85
85
  - `stdout.log` and `stderr.log`: detached process output.
86
86
  - `result.json`: final code, killed flag, output selector, and optional full-output path.
87
87
 
@@ -107,7 +107,7 @@ Terminal status is `done` for result code 0 and `failed` for non-zero result cod
107
107
 
108
108
  ## Reactive Coordinator Loop
109
109
 
110
- Async runs are designed for event-driven coordination, not polling loops. A good coordinator starts long-lived or multi-agent work, lets completion and decision-point events bubble through `outbox.jsonl`, and sends corrective commands only when the run asks for input or the operator changes direction.
110
+ Async runs are designed for message-driven coordination, not polling loops. A good coordinator starts long-lived or multi-agent work, lets completion and decision-point actor messages bubble upward, and sends corrective commands only when the run asks for input or the operator changes direction.
111
111
 
112
112
  The core loop is:
113
113
 
@@ -117,7 +117,7 @@ The core loop is:
117
117
  { "recipe": "music-player.json", "as": "run:music" }
118
118
  ```
119
119
 
120
- 2. Let terminal events, `command.done`, and script-authored `followup` messages reach the launching coordinator automatically.
120
+ 2. Let terminal completion, `command.done`, and script-authored follow-up messages reach the launching coordinator automatically.
121
121
 
122
122
  3. Respond with explicit run-local messages when needed:
123
123
 
@@ -125,7 +125,7 @@ The core loop is:
125
125
  { "to": "run:music", "type": "player.next", "body": "next" }
126
126
  ```
127
127
 
128
- 4. Do not inspect just because time passed. Inspect `status`, `tail`, or `events` only when a follow-up asks for inspection, a real decision depends on it, or a suspected stuck run needs diagnosis.
128
+ 4. Do not inspect just because time passed. Inspect `status`, `tail`, or `messages` only when a follow-up asks for inspection, a real decision depends on it, or a suspected stuck run needs diagnosis.
129
129
 
130
130
  Addressed `message` calls and coordinator follow-ups are the paired control plane: run-to-coordinator actor messages flow upward, while coordinator-to-run actor messages flow downward. Recipe scripts own the message vocabulary (`next`, `pause`, `approve`, `revise`, `continue`, and so on); pi-actors owns the safe run-local transport, coordinator-session ownership checks, and coordinator attention policy.
131
131
 
@@ -135,13 +135,13 @@ The actor-level surface is:
135
135
 
136
136
  - `spawn`: start a detached `run:<id>` actor from `file`, `recipe`, or inline `template`.
137
137
  - `message`: send one typed envelope to `run:<id>`, `branch:<run>/<branch>`, `tool:<name>`, `coordinator`, or `session:<id>`.
138
- - `inspect`: intentionally read owned `run:<id>` status, tail, events, artifacts, files, or mailbox metadata; read current `coordinator` run inventory only when a coordinator session is known; read `session:<id>` or `session:all` run inventory with optional status filtering when the session is explicit; read `tool:<name>` status or schema for registered tool actors.
138
+ - `inspect`: intentionally read owned `run:<id>` status, tail, messages, events, artifacts, files, or mailbox metadata; read current `coordinator` run inventory only when a coordinator session is known; read `session:<id>` or `session:all` run inventory with optional status filtering when the session is explicit; read `tool:<name>` status or schema for registered tool actors.
139
139
 
140
140
  Low-level async actions map into the actor surface instead of forming a second public model:
141
141
 
142
142
  - start → `spawn`
143
143
  - send/control → `message`
144
- - status/tail/events/list → `inspect`
144
+ - status/tail/messages/events/list → `inspect`
145
145
  - stop/kill → `message` with `control.stop` or `control.kill`, with synchronous results
146
146
 
147
147
  Compact text is returned by default so async management does not flood agent context; use verbose inspection when the full state object is needed. List output intentionally shares one state root across music, subagents, timers, and other async work; source fields such as `tool` and `recipe` distinguish run purpose when the launcher recorded them. Registered tools are the preferred user-facing surface for reusable recipes.
@@ -150,13 +150,7 @@ Compact text is returned by default so async management does not flood agent con
150
150
 
151
151
  `message` is the explicit coordinator-to-actor command channel. Use it when a running recipe exposes a control vocabulary, a branch needs parent-mediated control, a registered tool should be invoked as `tool:<name>`, or the coordinator needs to redirect work without killing or restarting it.
152
152
 
153
- On Unix-like hosts, async runs may expose a control FIFO at:
154
-
155
- ```text
156
- <state_dir>/control.fifo
157
- ```
158
-
159
- When present, a caller can send a typed actor message:
153
+ Some recipes expose a run-local control channel. When present, a caller can send a typed actor message:
160
154
 
161
155
  ```json
162
156
  {
@@ -166,23 +160,19 @@ When present, a caller can send a typed actor message:
166
160
  }
167
161
  ```
168
162
 
169
- For `run:<id>`, `message` adapts the body to the FIFO command line. For `branch:<run>/<branch>`, it sends the full envelope through the parent run mailbox so the run can dispatch branch-local control. For `tool:<name>`, object bodies become the target tool parameters and primitive bodies are passed as `{ "input": body }`. The generic runtime records send events but does not interpret arbitrary run mailbox content. For example, a music player may accept `play`, `pause`, `next`, and `stop`, while a collaborative agent recipe may accept `continue`, `revise:<note>`, `approve`, or `abort`. Recipes may treat terminal control messages such as `stop` as synchronously handled so the later process exit does not generate a duplicate async follow-up.
163
+ For `run:<id>`, `message` adapts the body to the recipe's run-local control channel. For `branch:<run>/<branch>`, it sends the full envelope through the parent run mailbox so the run can dispatch branch-local control. For `tool:<name>`, object bodies become the target tool parameters and primitive bodies are passed as `{ "input": body }`. The generic runtime records control messages but does not interpret arbitrary run mailbox content. For example, a music player may accept `play`, `pause`, `next`, and `stop`, while a collaborative agent recipe may accept `continue`, `revise:<note>`, `approve`, or `abort`. Recipes may treat terminal control messages such as `stop` as synchronously handled so the later process exit does not generate a duplicate async follow-up.
170
164
 
171
- Native Windows does not support this Unix FIFO contract. Use WSL/Linux/macOS for FIFO-controlled recipes, or let a Windows-specific recipe expose its own transport such as a Windows named pipe or localhost socket.
165
+ The standard run-local transport is Unix-oriented. Use WSL/Linux/macOS for packaged message-controlled recipes, or let a Windows-specific recipe expose its own transport such as a Windows named pipe or localhost socket.
172
166
 
173
167
  ## Coordinator Notifications
174
168
 
175
169
  The launching coordinator should not busy-poll long-running async runs. The extension watches run state directories and delivers terminal `done`/`failed`/unhandled `killed`/`exited` transitions plus script-authored `notify`/`followup` actor messages back to the owning session. This gives the top-level async task a completion signal on the happy path while still letting recipe-local messages bubble up when scripts need finer-grained notifications. Terminal follow-ups include recipe-level named `artifacts` when declared. The generic runner also emits compact `command.done` actor messages for completed leaf commands; recipe authors declare that capability in `mailbox.emits` rather than configuring a separate delivery policy. Failures and in-flight parallel branch completions can bubble as follow-ups, while successful final leaf completions stay diagnostic to avoid flooding long sequential pipelines. Branch-level `command.done` follow-ups omit artifact manifests because the top-level terminal follow-up carries them once. Intentional `control.stop`, `control.kill`, and recipe-local stop commands stay out of follow-up context because the initiating message already returns synchronously. If a follow-up asks for direction, answer with `message` rather than starting a polling loop. Use explicit `inspect` only when a delivered follow-up requests inspection, a real decision depends on state, or a suspected stuck run needs diagnosis — never merely because a timeout elapsed.
176
170
 
177
- Ambient status indicators may refresh while work is active, but coordinator attention is event-driven from state-file changes rather than a coordinator agent loop. This lets the coordinator continue other work after `spawn`; the run signals back through `events.jsonl`, `result.json`, and `outbox.jsonl`. The ambient triangle count represents active async work units: each running async run contributes at least one triangle, and a run with multiple active parallel command/subagent branches contributes the reported active branch count. If a coordinator starts one parent run with four active parallel branches, four triangles are shown; if the same coordinator starts five independent single-branch runs, five triangles are shown.
171
+ Ambient status indicators may refresh while work is active, but coordinator attention is driven from run-state changes rather than a coordinator agent loop. This lets the coordinator continue other work after `spawn`; the run signals back through lifecycle state, results, and actor messages. The ambient triangle count represents active async work units: each running async run contributes at least one triangle, and a run with multiple active parallel command/subagent branches contributes the reported active branch count. If a coordinator starts one parent run with four active parallel branches, four triangles are shown; if the same coordinator starts five independent single-branch runs, five triangles are shown.
178
172
 
179
173
  ## Run Actor Messages
180
174
 
181
- A recipe or script may append coordinator-bound or session-bound actor message records to:
182
-
183
- ```text
184
- <state_dir>/outbox.jsonl
185
- ```
175
+ A recipe or script may emit coordinator-bound or session-bound actor message records. The runtime persists those records in the run state dir and exposes them through `inspect target=run:<id> view=messages`.
186
176
 
187
177
  Shape:
188
178
 
@@ -208,7 +198,7 @@ An async run belongs to the current user, cwd, and launching agent session at st
208
198
 
209
199
  On Unix-like systems, cancel and kill signal the runner process group when available, then fall back to the runner pid. The runner starts command-template children in that process group, so long-running descendants such as audio players stop with the run instead of becoming orphaned background processes. After the process exits, status reflects the operator action as `cancelled` or `killed` instead of a generic `exited`.
210
200
 
211
- State is append-only where practical. Final result writes should be atomic. Recipe-local control endpoints and actor-message logs may live in the state dir. pi-actors core owns only the generic Unix FIFO write action and runtime attention policy; command and message vocabularies belong to the recipe/script.
201
+ State is append-only where practical. Final result writes should be atomic. Recipe-local control endpoints and actor-message logs may live in the state dir. pi-actors core owns the generic run-local message adapter and runtime attention policy; command and message vocabularies belong to the recipe/script.
212
202
 
213
203
  ## Extension Temp Directory
214
204
 
@@ -117,9 +117,9 @@ Files:
117
117
  - `recipes/music-player.json`
118
118
  - `scripts/music-player.mjs`
119
119
 
120
- Purpose: start a local or URL audio source as an async run so the agent can continue working while playback runs in the background. The running script exposes one run-local mailbox/FIFO, so addressed `message` calls can control playback without a second recipe.
120
+ Purpose: start a local or URL audio source as an async run so the agent can continue working while playback runs in the background. The running script exposes a run-local mailbox, so addressed `message` calls can control playback without a second recipe.
121
121
 
122
- Requirements: Linux, macOS, or WSL with `mkfifo`, Node.js, and one of `mpv`, `ffplay`, `cvlc`, or SoX `play`. Native Windows is not supported because the wrapper uses a Unix FIFO and Unix signals.
122
+ Requirements: Linux, macOS, or WSL, Node.js, and one of `mpv`, `ffplay`, `cvlc`, or SoX `play`. Native Windows is not supported by the standard wrapper; use WSL or a platform-specific recipe transport.
123
123
 
124
124
  The required `source` arg accepts:
125
125
 
@@ -160,7 +160,7 @@ message to=run:music type=player.previous body=previous
160
160
  message to=run:music type=player.stop body=stop
161
161
  ```
162
162
 
163
- Use `inspect target=run:music view=status` only when an event or operator decision requires inspection.
163
+ Use `inspect target=run:music view=status` only when an actor message or operator decision requires inspection.
164
164
 
165
165
  The wrapper also accepts control commands directly when a caller already has the run state dir:
166
166
 
@@ -168,7 +168,7 @@ The wrapper also accepts control commands directly when a caller already has the
168
168
  scripts/music-player.mjs next ~/.pi/agent/tmp/pi-actors/runs/music
169
169
  ```
170
170
 
171
- Message body is currently adapted to one newline-delimited command written to `<run state dir>/control.fifo`. The script writes `status.txt`, `player.json`, and track-change actor messages in `outbox.jsonl` in the same state dir. Track-change messages stay diagnostic by default; interactive recipes should define a small command vocabulary for addressed messages, emit semantic actor messages for decision points, and let the coordinator react to messages rather than sleep-polling state.
171
+ Message body is adapted to the recipe's run-local control channel. The script writes `status.txt`, `player.json`, and track-change actor messages in the same state dir. Track-change messages stay diagnostic by default; interactive recipes should define a small command vocabulary for addressed messages, emit semantic actor messages for decision points, and let the coordinator react to messages rather than sleep-polling state.
172
172
 
173
173
  ## Safety Notes
174
174
 
@@ -35,7 +35,7 @@ Template-recipe standard owns:
35
35
  Template-recipe standard does not own:
36
36
 
37
37
  - How command-template nodes execute internally.
38
- - Async state files, logs, FIFO, status, cancellation, or observability.
38
+ - Async state files, logs, run-local transports, status, cancellation, or observability.
39
39
  - Tool registry naming, button UX, package installation, or operator-specific policy.
40
40
  - Domain workflows such as swarm quorum, release policy, backlog parsing, or merge policy.
41
41
 
@@ -86,7 +86,7 @@ Use recipe-level `artifacts` to declare stable artifact names and paths for the
86
86
  }
87
87
  ```
88
88
 
89
- `output` and `artifacts` are intentionally different. `output` is the command-template primary result selector and defaults to stdout; it participates in sequence/stdin flow. `artifacts` is recipe metadata: an ordered named artifact manifest for humans, async completion events, and downstream tooling. `stdout` remains the default command result channel and is not renamed by `artifacts`.
89
+ `output` and `artifacts` are intentionally different. `output` is the command-template primary result selector and defaults to stdout; it participates in sequence/stdin flow. `artifacts` is recipe metadata: an ordered named artifact manifest for humans, async completion messages, and downstream tooling. `stdout` remains the default command result channel and is not renamed by `artifacts`.
90
90
 
91
91
  ## Mailbox
92
92
 
@@ -101,7 +101,7 @@ Use recipe-level `mailbox` to document the semantic messages a recipe actor acce
101
101
  }
102
102
  ```
103
103
 
104
- `mailbox` is contract metadata, not transport configuration. It should name semantic message types, not FIFO commands, file paths, or CLI fragments.
104
+ `mailbox` is contract metadata, not transport configuration. It should name semantic message types, not transport commands, file paths, or CLI fragments.
105
105
 
106
106
  ## Actor Message Delivery
107
107
 
package/lib/prompts.ts CHANGED
@@ -38,7 +38,7 @@ export const ONBOARDING_SYSTEM_PROMPT = `pi-actors quick model:
38
38
  - Long async fanout = parent async recipe wrapping template(parallel: true) and imports; packaged fanout recipes bubble branch completion follow-ups by default.
39
39
  - If asked to explore pi-actors, read README.md, docs/README.md, docs/template-recipes.md, docs/async-runs.md, and recipes/.
40
40
  - Ambient triangles show active async commands/subagents for the launching coordinator.
41
- - After async run finish, inspect status/tail/events before final artifacts.`;
41
+ - After async run finish, inspect status/tail/messages before final artifacts.`;
42
42
 
43
43
  export const REGISTER_TOOL_PARAM_DESCRIPTIONS = {
44
44
  name: "Tool name in snake_case (e.g., 'transcribe')",
package/lib/tools.ts CHANGED
@@ -430,7 +430,7 @@ export function createInspectToolDefinition<TContext = unknown>(
430
430
  status: stringSchema("Optional session run filter: all, running, active, terminal, done, failed, cancelled, killed, or exited."),
431
431
  target: stringSchema("Actor address to inspect, e.g. run:<id>, coordinator, session:<id>, session:all, or tool:<name>."),
432
432
  verbose: booleanSchema("Return full JSON instead of compact text where available."),
433
- view: stringSchema("Inspection view: status, tail, events, artifacts, files, or mailbox."),
433
+ view: stringSchema("Inspection view: status, tail, messages, events, artifacts, files, or mailbox."),
434
434
  },
435
435
  ["target", "view"],
436
436
  ),
@@ -522,17 +522,18 @@ export function createInspectToolDefinition<TContext = unknown>(
522
522
  const text = AsyncRuns.tailRun(runId, Number(input.lines || 40));
523
523
  return { content: [{ type: "text" as const, text: `\n${text}` }], details: {} };
524
524
  }
525
+ case "messages":
525
526
  case "events": {
526
527
  assertRunAccessibleToContext(runId, ctx);
527
- const events = AsyncRuns.readRunEvents(runId, Number(input.lines || 40));
528
+ const messages = AsyncRuns.readRunEvents(runId, Number(input.lines || 40));
528
529
  return {
529
530
  content: [
530
531
  {
531
532
  type: "text" as const,
532
- text: maybeJsonText(events, input.verbose === true, compactRunEvents(events)),
533
+ text: maybeJsonText(messages, input.verbose === true, compactRunEvents(messages)),
533
534
  },
534
535
  ],
535
- details: { events },
536
+ details: { messages, events: messages },
536
537
  };
537
538
  }
538
539
  case "artifacts":
@@ -562,7 +563,7 @@ export function createInspectToolDefinition<TContext = unknown>(
562
563
  };
563
564
  }
564
565
  default:
565
- throw new Error("inspect view must be one of: status, tail, events, artifacts, files, mailbox.");
566
+ throw new Error("inspect view must be one of: status, tail, messages, events, artifacts, files, mailbox.");
566
567
  }
567
568
  },
568
569
  };
@@ -611,9 +612,9 @@ export function createActorMessageToolDefinition<TContext = unknown>(
611
612
  let result: Record<string, unknown>;
612
613
  if (address.kind === "run" && address.value) {
613
614
  assertRunAccessibleToContext(address.value, ctx);
614
- if (message.type === "control.stop" || message.type === "control.cancel" || message.type === "runtime.cancel") {
615
+ if (message.type === "control.stop" || message.type === "control.cancel") {
615
616
  result = AsyncRuns.cancelRun(address.value);
616
- } else if (message.type === "control.kill" || message.type === "runtime.kill") {
617
+ } else if (message.type === "control.kill") {
617
618
  result = AsyncRuns.killRun(address.value);
618
619
  } else {
619
620
  result = AsyncRuns.sendRunMessage(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.12.13",
3
+ "version": "0.13.3",
4
4
  "private": false,
5
5
  "description": "Actor runtime and orchestrator for agent-managed local processes",
6
6
  "type": "module",
@@ -8,7 +8,7 @@
8
8
  },
9
9
  "args": [
10
10
  "state_root:path",
11
- "event_file:path",
11
+ "message_file:path",
12
12
  "lines:int",
13
13
  "stale_minutes:int",
14
14
  "artifact_path:path",
@@ -17,7 +17,7 @@
17
17
  ],
18
18
  "defaults": {
19
19
  "state_root": "~/.pi/agent/tmp/pi-actors/runs",
20
- "event_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
20
+ "message_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
21
21
  "lines": "80",
22
22
  "stale_minutes": "60",
23
23
  "artifact_path": "./async-run-ops.md",
@@ -33,7 +33,7 @@
33
33
  "name": "snapshot",
34
34
  "values": {
35
35
  "state_root": "{state_root}",
36
- "event_file": "{event_file}",
36
+ "message_file": "{message_file}",
37
37
  "lines": "{lines}",
38
38
  "stale_minutes": "{stale_minutes}"
39
39
  }
@@ -41,7 +41,7 @@
41
41
  {
42
42
  "name": "normalizer",
43
43
  "values": {
44
- "input": "Use async run operations snapshot JSON from stdin. State root: {state_root}. Event file: {event_file}.",
44
+ "input": "Use async run operations snapshot JSON from stdin. State root: {state_root}. Message file: {message_file}.",
45
45
  "format": "Markdown sections: Active Runs, Terminal Runs, Recent Events, Stale/Risky Runs, Recommended Controls, Follow-up Needed.",
46
46
  "model": "{model}",
47
47
  "thinking": "off",
@@ -3,16 +3,16 @@
3
3
  "args": [
4
4
  "repo:path",
5
5
  "state_root:path",
6
- "event_file:path",
6
+ "message_file:path",
7
7
  "lines:int",
8
8
  "stale_minutes:int"
9
9
  ],
10
10
  "defaults": {
11
11
  "repo": "~/.pi/agent/extensions/pi-actors",
12
12
  "state_root": "~/.pi/agent/tmp/pi-actors/runs",
13
- "event_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
13
+ "message_file": "~/.pi/agent/tmp/pi-actors/runs/music/outbox.jsonl",
14
14
  "lines": "80",
15
15
  "stale_minutes": "60"
16
16
  },
17
- "template": "{repo}/scripts/recipe-utils.mjs run-ops-snapshot {state_root} {event_file} {lines} {stale_minutes}"
17
+ "template": "{repo}/scripts/recipe-utils.mjs run-ops-snapshot {state_root} {message_file} {lines} {stale_minutes}"
18
18
  }
@@ -127,7 +127,7 @@ function tailJsonl(fileValue, linesValue = "80") {
127
127
  });
128
128
  }
129
129
 
130
- function runOpsSnapshot(rootValue, eventFileValue, linesValue = "80", staleMinutesValue = "60") {
130
+ function runOpsSnapshot(rootValue, messageFileValue, linesValue = "80", staleMinutesValue = "60") {
131
131
  const runs = collectRunSummary(rootValue);
132
132
  const staleMs = Number(staleMinutesValue) * 60 * 1000;
133
133
  const now = Date.now();
@@ -150,7 +150,7 @@ function runOpsSnapshot(rootValue, eventFileValue, linesValue = "80", staleMinut
150
150
  }
151
151
  return [];
152
152
  });
153
- console.log(JSON.stringify({ runs, events: tailJsonl(eventFileValue, linesValue), recommendations }, null, 2));
153
+ console.log(JSON.stringify({ runs, messages: tailJsonl(messageFileValue, linesValue), recommendations }, null, 2));
154
154
  }
155
155
 
156
156
  function playlist(