@llblab/pi-actors 0.12.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.
Files changed (86) hide show
  1. package/AGENTS.md +72 -0
  2. package/BACKLOG.md +38 -0
  3. package/CHANGELOG.md +179 -0
  4. package/README.md +338 -0
  5. package/docs/README.md +21 -0
  6. package/docs/actor-messages.md +149 -0
  7. package/docs/async-runs.md +335 -0
  8. package/docs/command-templates.md +424 -0
  9. package/docs/component-recipes.md +148 -0
  10. package/docs/recipe-library.md +176 -0
  11. package/docs/task-first-recipes.md +233 -0
  12. package/docs/template-recipes.md +285 -0
  13. package/docs/tool-registry.md +142 -0
  14. package/index.ts +198 -0
  15. package/lib/actor-messages.ts +120 -0
  16. package/lib/async-runs.ts +688 -0
  17. package/lib/command-templates.ts +795 -0
  18. package/lib/config.ts +266 -0
  19. package/lib/execution.ts +720 -0
  20. package/lib/file-state.ts +24 -0
  21. package/lib/identity.ts +29 -0
  22. package/lib/observability.ts +525 -0
  23. package/lib/output.ts +123 -0
  24. package/lib/paths.ts +35 -0
  25. package/lib/prompts.ts +75 -0
  26. package/lib/recipe-references.ts +586 -0
  27. package/lib/registry.ts +302 -0
  28. package/lib/runtime.ts +101 -0
  29. package/lib/schema.ts +402 -0
  30. package/lib/temp.ts +44 -0
  31. package/lib/tools.ts +651 -0
  32. package/package.json +52 -0
  33. package/recipes/music-player.json +25 -0
  34. package/recipes/pipeline-architect-coordinator.json +88 -0
  35. package/recipes/pipeline-artifact-report.json +52 -0
  36. package/recipes/pipeline-artifact-write.json +66 -0
  37. package/recipes/pipeline-async-run-ops.json +67 -0
  38. package/recipes/pipeline-checkpoint-continuation.json +57 -0
  39. package/recipes/pipeline-development-tasking.json +73 -0
  40. package/recipes/pipeline-docs-maintenance.json +72 -0
  41. package/recipes/pipeline-media-library.json +51 -0
  42. package/recipes/pipeline-quorum-review.json +72 -0
  43. package/recipes/pipeline-release-readiness.json +83 -0
  44. package/recipes/pipeline-repo-health.json +81 -0
  45. package/recipes/pipeline-research-synthesis.json +87 -0
  46. package/recipes/pipeline-review-readiness.json +49 -0
  47. package/recipes/subagent-artifact.json +26 -0
  48. package/recipes/subagent-checkpoint.json +27 -0
  49. package/recipes/subagent-conflict-report.json +25 -0
  50. package/recipes/subagent-contradiction-map.json +26 -0
  51. package/recipes/subagent-critic.json +28 -0
  52. package/recipes/subagent-evidence-map.json +26 -0
  53. package/recipes/subagent-followup.json +27 -0
  54. package/recipes/subagent-judge.json +26 -0
  55. package/recipes/subagent-merge.json +26 -0
  56. package/recipes/subagent-message.json +29 -0
  57. package/recipes/subagent-normalize.json +24 -0
  58. package/recipes/subagent-plan.json +26 -0
  59. package/recipes/subagent-prompt.json +22 -0
  60. package/recipes/subagent-quorum.json +41 -0
  61. package/recipes/subagent-review-coordinator.json +107 -0
  62. package/recipes/subagent-review.json +30 -0
  63. package/recipes/subagent-task-card.json +28 -0
  64. package/recipes/subagent-tools.json +17 -0
  65. package/recipes/subagent-verify.json +27 -0
  66. package/recipes/subagents-prompts.json +32 -0
  67. package/recipes/utility-actor-message.json +24 -0
  68. package/recipes/utility-artifact-manifest.json +17 -0
  69. package/recipes/utility-artifact-write.json +17 -0
  70. package/recipes/utility-changelog-head.json +12 -0
  71. package/recipes/utility-changelog-section.json +14 -0
  72. package/recipes/utility-git-log.json +12 -0
  73. package/recipes/utility-git-status.json +10 -0
  74. package/recipes/utility-jsonl-tail.json +11 -0
  75. package/recipes/utility-markdown-index.json +15 -0
  76. package/recipes/utility-package-summary.json +12 -0
  77. package/recipes/utility-playlist-build.json +18 -0
  78. package/recipes/utility-playlist-scan.json +12 -0
  79. package/recipes/utility-run-state-files.json +14 -0
  80. package/recipes/utility-run-summary.json +12 -0
  81. package/recipes/utility-validate-recipe.json +14 -0
  82. package/recipes/utility-validation-wrapper.json +14 -0
  83. package/scripts/async-runner.mjs +170 -0
  84. package/scripts/music-player.mjs +637 -0
  85. package/scripts/recipe-utils.mjs +273 -0
  86. package/scripts/validate-recipe.mjs +89 -0
package/README.md ADDED
@@ -0,0 +1,338 @@
1
+ # pi-actors
2
+
3
+ Actor runtime and persistent local tool registry extension for the pi coding agent.
4
+
5
+ `pi-actors` is a local-first, cybernetic actor layer for agents. It is MCP-adjacent in spirit, but instead of waiting for external servers to define every capability, the agent can turn trusted local commands, scripts, and recipes into durable tools itself. Those tools persist across reloads as a kind of operational muscle memory: short semantic names, typed args, reusable recipes, and async runs replace repeated shell reconstruction.
6
+
7
+ ## Start Here
8
+
9
+ - [Project Context](./AGENTS.md)
10
+ - [Open Backlog](./BACKLOG.md)
11
+ - [Changelog](./CHANGELOG.md)
12
+ - [Documentation](./docs/README.md)
13
+
14
+ ## Key Features
15
+
16
+ - **Local-First Tool Memory**: Lets agents create and persist their own trusted local tools, forming durable operational muscle memory instead of one-off shell commands.
17
+ - **Commands Become Capabilities**: Turns stable local workflows into semantic agent tools, so the agent chooses what it can do instead of reconstructing how to run shell commands.
18
+ - **Persistent Tool Registry**: Stores tool definitions in `~/.pi/agent/tools.json` and registers them automatically on session start.
19
+ - **Compact Semantic Interface**: Exposes short tool names, descriptions, named args, and defaults instead of long paths, positional command-arg order, and repeated command boilerplate.
20
+ - **Safer Local Automation**: Wraps trusted command templates as narrow tools using split-first command-arg construction, placeholder substitution, and no shell evaluation.
21
+ - **Reusable Building Blocks**: Makes skill scripts, sub-agent wrappers, diagnostics, and project workflows available as composable agent capabilities.
22
+ - **Immediate Updates**: Registered and updated tools become callable in the active session; deleted tools are removed from active tools and fully disappear after reload.
23
+ - **Bounded Output**: Tool stdout is returned to the agent with truncation safeguards; full oversized output is saved to a temp file.
24
+ - **Template Recipes**: Stores reusable command-template JSON under `~/.pi/agent/recipes/*.json`; recipes can import other recipes, reuse defaults, declare ordered named `artifacts`, and run foreground or declare `async: true` for detached lifecycle.
25
+ - **Actor Runs**: Starts detached recipe or inline-template runs as addressable actors backed by state files under `~/.pi/agent/tmp/pi-actors`.
26
+ - **Context Onboarding**: Injects a compact system-prompt note explaining templates, recipes, async runs, tasks, and agent fanout so installed sessions have the mental model available by default.
27
+ - **Coordinator-Scoped Run Observability**: Shows at least one stable triangle per running async run started by the current agent session, adds triangles for active parallel branches, then injects compact completion events only back to the launching coordinator when attention is needed.
28
+
29
+ ## Install
30
+
31
+ From npm:
32
+
33
+ ```bash
34
+ pi install npm:@llblab/pi-actors
35
+ ```
36
+
37
+ From git:
38
+
39
+ ```bash
40
+ pi install git:github.com/llblab/pi-actors
41
+ ```
42
+
43
+ ## Mental Model
44
+
45
+ `pi-actors` has one execution idea that grows in place:
46
+
47
+ ```text
48
+ command
49
+ → command template
50
+ → template recipe
51
+ → registered tool
52
+ → async run
53
+ ```
54
+
55
+ - A **command** is one concrete local process.
56
+ - A **command template** is the reusable shape of that process, with named placeholders.
57
+ - A **template recipe** is saved JSON containing a template plus defaults and run mode.
58
+ - A **registered tool** gives a command template or recipe a stable agent-facing name.
59
+ - An **async run** is one execution instance with state, logs, script-authored events, status, tail, message send, cancel, and kill.
60
+
61
+ The template remains the execution language. The recipe is saved actor configuration. `async: true` is the detached lifecycle switch. The extension injects this compact mental model into the system prompt on each agent turn, including where to look first (`README.md`, `docs/README.md`, recipe/async docs, and `recipes/`) so an agent asked to inspect pi-actors can quickly understand the model and start composing async subagents or other long-running recipes.
62
+
63
+ ## Operator Onboarding
64
+
65
+ Start with foreground templates for short deterministic work:
66
+
67
+ ```text
68
+ register_tool name=lint_docs description="Lint docs" template="npm run lint:docs"
69
+ ```
70
+
71
+ Move to async recipes when work is long-running, parallel, or agentic:
72
+
73
+ ```json
74
+ {
75
+ "name": "shader-ring-8-parallel",
76
+ "async": true,
77
+ "parallel": true,
78
+ "template": ["..."]
79
+ }
80
+ ```
81
+
82
+ Expose a reusable recipe as a normal capability:
83
+
84
+ ```text
85
+ register_tool name=shader_ring description="Start shader ring" template="shader-ring-8-parallel.json" args="theme,out_dir"
86
+ ```
87
+
88
+ `Task` is the user's work item. `Template` is the execution graph. `Recipe` is saved JSON. `Run` is one execution instance with status, logs, cancellation, and ambient triangles.
89
+
90
+ ## Compose Recipes With Imports
91
+
92
+ Recipes can import other recipe files and reuse them as named nodes. This keeps reusable steps small while letting a parent recipe decide whether the combined graph runs foreground or as one async run.
93
+
94
+ `review-one.json`:
95
+
96
+ ```json
97
+ {
98
+ "name": "review-one",
99
+ "args": ["scope:string", "model:string"],
100
+ "defaults": { "model": "openai-codex/gpt-5.5" },
101
+ "template": "pi -p --model {model} --no-tools \"Review {scope}\""
102
+ }
103
+ ```
104
+
105
+ `review-pair.json`:
106
+
107
+ ```json
108
+ {
109
+ "name": "review-pair",
110
+ "async": true,
111
+ "imports": {
112
+ "review": "review-one.json"
113
+ },
114
+ "parallel": true,
115
+ "failure": "branch",
116
+ "template": [
117
+ { "name": "review", "values": { "scope": "README.md" } },
118
+ { "name": "review", "values": { "scope": "docs/template-recipes.md" } }
119
+ ]
120
+ }
121
+ ```
122
+
123
+ Register only the parent when that is the operator-facing capability:
124
+
125
+ ```text
126
+ register_tool name=review_pair \
127
+ description="Start a parallel async docs review" \
128
+ template="review-pair.json"
129
+ ```
130
+
131
+ Imported recipes are recipe definitions, not nested async runs. The parent recipe's `async: true` creates one run with one state dir; imported recipes contribute command-template graph, args, defaults, and values.
132
+
133
+ ## Register Tools
134
+
135
+ `register_tool` lists, registers, updates, or deletes persistent tools. Call it without arguments to list the current registry.
136
+
137
+ ### Local command: transcription
138
+
139
+ `pi-actors` is useful for exposing stable local commands as normal tools. For example, register an STT command:
140
+
141
+ ```text
142
+ register_tool name=transcribe \
143
+ description="Transcribe a local audio file" \
144
+ template="/path/to/stt --file {file} --lang {lang=ru}"
145
+ ```
146
+
147
+ ### Template recipe
148
+
149
+ For reusable workflows, keep the large template in a recipe file and register a small tool:
150
+
151
+ ```text
152
+ register_tool name=shader_ring \
153
+ description="Start the shader ring recipe" \
154
+ template="shader-ring-8-parallel.json" \
155
+ args="theme,out_dir"
156
+ ```
157
+
158
+ If the recipe file contains `async: true`, calling `shader_ring` starts a detached run and returns metadata immediately. If `async` is omitted or false, the same recipe runs foreground and returns normal tool output.
159
+
160
+ A recipe can also be co-located in `tools.json` when keeping metadata and the recipe body together is clearer:
161
+
162
+ ```json
163
+ {
164
+ "review_docs": {
165
+ "description": "Start an async docs review",
166
+ "name": "review-docs",
167
+ "async": true,
168
+ "template": "pi -p --model openai-codex/gpt-5.5 --tools read,bash \"Review {scope}\""
169
+ }
170
+ }
171
+ ```
172
+
173
+ A co-located recipe entry still cannot define `tool`; it must own `template` directly.
174
+
175
+ ### Sub-agent
176
+
177
+ ```text
178
+ register_tool name=call_subagent \
179
+ description="Run pi as a non-interactive sub-agent" \
180
+ template="pi -p --model {model=openai-codex/gpt-5.5} --no-tools {prompt}"
181
+ ```
182
+
183
+ Use `update=true` to overwrite an existing tool. Omit `template` during update to keep the previous template:
184
+
185
+ ```text
186
+ register_tool name=call_subagent \
187
+ description="Run a focused pi sub-agent without tools" \
188
+ update=true
189
+ ```
190
+
191
+ Delete a tool:
192
+
193
+ ```text
194
+ register_tool name=call_subagent template=null
195
+ ```
196
+
197
+ ## Resulting Config
198
+
199
+ The commands above persist entries like this in `~/.pi/agent/tools.json`; tool names come from the top-level keys. Stored entries keep `template` last so flags and metadata are read before executable content:
200
+
201
+ ```json
202
+ {
203
+ "transcribe": {
204
+ "description": "Transcribe a local audio file",
205
+ "template": "/path/to/stt --file {file} --lang {lang=ru}"
206
+ },
207
+ "call_subagent": {
208
+ "description": "Run pi as a non-interactive sub-agent",
209
+ "template": "pi -p --model {model=openai-codex/gpt-5.5} --no-tools {prompt}"
210
+ },
211
+ "shader_ring": {
212
+ "description": "Start the shader ring recipe",
213
+ "args": ["theme", "out_dir"],
214
+ "template": "shader-ring-8-parallel.json"
215
+ }
216
+ }
217
+ ```
218
+
219
+ This file is the durable registry. `register_tool` is the interactive API; `tools.json` is the persisted state that is loaded on future sessions.
220
+
221
+ ## Manage Run Actors
222
+
223
+ Use `spawn` when a command template may outlive the current turn. It starts the work now as an addressable actor, returns immediately with state metadata, and keeps ordinary files under `~/.pi/agent/tmp/pi-actors/runs/<run>` for later inspection.
224
+
225
+ Start from an inline template as an addressable run actor:
226
+
227
+ ```json
228
+ {
229
+ "as": "run:docs-review",
230
+ "template": "pi -p --model openai-codex/gpt-5.5 --no-tools {prompt}",
231
+ "values": {
232
+ "prompt": "Review docs/spec.md for contradictions."
233
+ }
234
+ }
235
+ ```
236
+
237
+ 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:
238
+
239
+ ```json
240
+ { "to": "run:docs-review", "type": "control.continue", "body": "continue" }
241
+ ```
242
+
243
+ Read recent events or logs only after a follow-up asks for inspection, at a real decision point, or during diagnosis:
244
+
245
+ ```json
246
+ { "target": "run:docs-review", "view": "tail", "lines": "80" }
247
+ ```
248
+
249
+ Reusable local recipes live in `~/.pi/agent/recipes/*.json`; recipe tools honor each file's `async` flag. Use `spawn` for explicit detached starts from a file or inline template, and `inspect target=session:<id> view=runs status=running` or `inspect target=session:all view=runs` for explicit inventory/diagnosis. List output includes `tool` and `recipe` when the launcher recorded that source context.
250
+
251
+ ## Recipe Library
252
+
253
+ Packaged standard recipes live under root `recipes/` with helper scripts under root `scripts/`. They are reusable library definitions, not automatically installed operator policy.
254
+
255
+ The subagent component recipes start non-interactive pi subagents as async runs or compose component recipes into higher-level coordinator pipelines. Use the no-tools recipe for the safest default, the explicit-tool variant when a bounded tool allowlist is needed, or the prompts fanout parent recipe to see imported subagent recipe nodes composed into one async run:
256
+
257
+ ```text
258
+ register_tool name=subagent_prompt \
259
+ description="Start an async no-tools pi subagent" \
260
+ template="subagent-prompt.json"
261
+
262
+ register_tool name=subagent_tools \
263
+ description="Start an async pi subagent with an explicit tool allowlist" \
264
+ template="subagent-tools.json"
265
+
266
+ register_tool name=subagents_prompts \
267
+ description="Start parallel no-tools subagents from a prompt array as one async run" \
268
+ template="subagents-prompts.json"
269
+
270
+ subagent_prompt prompt="Review docs/async-runs.md for unclear wording." run_id=docs-review
271
+ subagent_tools prompt="Inspect package metadata and report risks." tools="read,bash" run_id=package-review
272
+ subagents_prompts \
273
+ 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."]' \
274
+ run_id=review-prompts
275
+ inspect target=run:review-prompts view=tail
276
+ ```
277
+
278
+ The music player recipe starts a local file, URL, directory, or playlist as an async run, keeps the agent unblocked, shows the ambient triangle indicator in the launching coordinator, and can be controlled with addressed `message` calls. The standard library ships one Node.js wrapper recipe:
279
+
280
+ ```text
281
+ register_tool name=music_player \
282
+ description="Start async music player playback through the Node.js wrapper" \
283
+ template="music-player.json" \
284
+ args="source:string,loop:bool=true,volume:int=70,player:enum(auto,mpv,ffplay,cvlc,play)=auto"
285
+
286
+ music_player source="~/Music" volume=55 run_id=music
287
+ message to=run:music type=player.next body=next
288
+ message to=run:music type=player.pause body=pause
289
+ message to=run:music type=player.play body=play
290
+ message to=run:music type=player.stop body=stop
291
+ ```
292
+
293
+ See [`docs/recipe-library.md`](./docs/recipe-library.md) for install notes and recipe requirements.
294
+
295
+ ## Runtime Contract
296
+
297
+ - Tool names are normalized to snake_case.
298
+ - Reserved built-in names are blocked.
299
+ - Templates are split into shell-like words first, then placeholders are substituted per command arg.
300
+ - Tool args are derived from placeholders when `args` is omitted.
301
+ - Typed arg declarations are progressive: `file:path`, `request_timeout:int=60000`, `speed:number=1.5`, `dry_run:bool=true`, `prompts:array`, and `mode:enum(check,fix)=check` can live in `args` or inline placeholders such as `{request_timeout:int=60000}`. They generate narrower tool schemas and runtime validation while existing untyped `args` and placeholders keep working.
302
+ - `{arg=default}` inline defaults resolve after runtime values and stored `defaults`; `{arg??fallback}` handles empty/null fallback values; `{flag?--flag:}` ternaries map small truthy/falsy values to strings such as optional CLI flags.
303
+ - `template: [...]` sequences execute left to right; each successful step passes stdout to the next step on stdin.
304
+ - Object nodes may set `parallel: true`; children receive the same stdin and joined stdout flows to the next sequence step.
305
+ - Parallel nodes use soft-quorum semantics: failed branches are reported as degraded coverage unless failure propagation escalates to the root.
306
+ - For long-running work or agentic fanout, prefer `async: true` recipes or `spawn` so lifecycle and ambient activity status remain visible.
307
+ - 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}"`.
308
+ - Nodes may set `when` to skip conditional work and `delay` in milliseconds to wait before launch; delay is not inherited.
309
+ - Failed steps default to `failure: "continue"`, which records the failure and continues with empty stdin.
310
+ - `failure: "branch"` stops the current sequence/subtree without cancelling sibling parallel branches; `failure: "root"` aborts the composition.
311
+ - `retry` retries a leaf or whole node on non-zero exit; default attempts is `1`.
312
+ - `recover` runs a cleanup command template between failed retry attempts and stops retries if cleanup fails.
313
+ - Commands execute directly without shell evaluation, but trusted executables still run with the same permissions as pi.
314
+ - Obvious high-risk templates such as shells, interpreter eval modes, and broad filesystem mutation surface lightweight warnings without blocking existing tools.
315
+ - `async: true` on a recipe selects detached run lifecycle; omitted or false async runs the recipe foreground through registered tools.
316
+ - 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.
317
+ - `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 the coordinator attention path, and `inspect` intentionally reads `run:<id>` status/tail/events/mailbox metadata or `session:<id>` run status while the broader actor/message protocol is refined.
318
+ - `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 belongs to `message`; status/tail/events/list belong to `inspect`; stop/kill are runtime control messages with synchronous results.
319
+ - Actor management returns compact text by default; pass `verbose: true` to `inspect` when full JSON state is needed.
320
+ - Detached runs inject `{run_id}` and `{state_dir}` into template values for run-local artifacts or recipe-specific control endpoints.
321
+ - 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.
322
+ - Native Windows should use WSL or a recipe-specific transport for FIFO-controlled recipes.
323
+ - Registered tools may set `template` to a recipe JSON path/name; calling them follows that recipe's `async` mode.
324
+ - 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.
325
+ - 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. Packaged multi-agent fanout recipes emit `command.done` messages by default so parallel subtask completions reach the coordinator.
326
+ - Use `{file}` as the canonical local file path arg.
327
+ - Stored `script` entries are rejected with migration guidance.
328
+
329
+ 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.
330
+
331
+ ## Notes
332
+
333
+ - Only register trusted local commands. Registered tools run with the same system permissions as pi.
334
+ - `index.ts` is a small composition root; reusable behavior lives in flat `/lib` domains covered by focused tests.
335
+
336
+ ## License
337
+
338
+ MIT
package/docs/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # Documentation Index
2
+
3
+ Living index of all documentation in the `/docs` directory.
4
+
5
+ ## Documents
6
+
7
+ - [command-templates.md](./command-templates.md) — Portable synchronous command execution standard
8
+ - [template-recipes.md](./template-recipes.md) — Saved JSON recipe standard, imports, and reusable command-template graph composition
9
+ - [async-runs.md](./async-runs.md) — Detached run lifecycle, state files, actor messages, cancellation, and ambient indicators
10
+ - [actor-messages.md](./actor-messages.md) — Actor/message protocol for symmetric communication primitives
11
+ - [tool-registry.md](./tool-registry.md) — Local `pi-actors` registry storage and `register_tool` adaptation
12
+ - [recipe-library.md](./recipe-library.md) — Packaged standard recipe library such as async subagents, coordinator pipelines, utilities, and music playback
13
+ - [task-first-recipes.md](./task-first-recipes.md) — Task-first design map for deriving high-level recipes and missing component cells
14
+ - [component-recipes.md](./component-recipes.md) — Weak component-recipe contract for composing subagent coordinator building blocks
15
+
16
+ ## Root Context
17
+
18
+ - [Project Context](../AGENTS.md)
19
+ - [Open Backlog](../BACKLOG.md)
20
+ - [Changelog](../CHANGELOG.md)
21
+ - [Root README](../README.md)
@@ -0,0 +1,149 @@
1
+ # Actor Messages
2
+
3
+ Protocol target for organic communication across pi-actors.
4
+
5
+ ## Contract
6
+
7
+ Compress communication to three durable verbs:
8
+
9
+ - `spawn`: create an addressable actor from a recipe, template, or tool.
10
+ - `message`: send one typed message to one address.
11
+ - `inspect`: intentionally observe state, logs, events, or artifacts.
12
+
13
+ Everything else is an adapter until proven otherwise.
14
+
15
+ ## Nouns
16
+
17
+ - **Actor**: any addressable execution or coordination endpoint.
18
+ - **Address**: stable route string for an actor or sub-actor.
19
+ - **Message**: typed envelope flowing between addresses.
20
+ - **Artifact**: durable result path declared by recipe or produced by actor.
21
+ - **Inspection**: explicit diagnostic/read operation, not a coordination loop.
22
+
23
+ ## Addresses
24
+
25
+ Initial address forms:
26
+
27
+ ```text
28
+ run:<id>
29
+ branch:<run>/<branch>
30
+ coordinator
31
+ session:<id>
32
+ tool:<name>
33
+ ```
34
+
35
+ Future forms may include `chat:<id>` or package-specific endpoints, but the envelope stays the same.
36
+
37
+ ## Message Envelope
38
+
39
+ One shape covers upward, downward, lateral, parent-to-branch, and branch-to-parent traffic:
40
+
41
+ ```json
42
+ {
43
+ "to": "run:review",
44
+ "from": "coordinator",
45
+ "type": "control.approve",
46
+ "summary": "Approve checkpoint",
47
+ "body": "approve",
48
+ "reply_to": "msg_123",
49
+ "correlation_id": "task_456",
50
+ "metadata": {}
51
+ }
52
+ ```
53
+
54
+ Field rules:
55
+
56
+ - `to`: required address.
57
+ - `from`: optional address; runtime fills when known.
58
+ - `type`: required semantic message type.
59
+ - `summary`: short human-facing line for notifications/follow-ups.
60
+ - `body`: string or JSON payload.
61
+ - routing/delivery is inferred from `to`, actor ownership, and coordinator runtime policy; recipes should not expose delivery knobs.
62
+ - `reply_to`: optional message id for conversational checkpoints.
63
+ - `correlation_id`: optional task/run/workflow id.
64
+ - `metadata`: optional structured routing or domain hints.
65
+
66
+ ## Symmetry
67
+
68
+ The same `message` primitive must represent:
69
+
70
+ ```text
71
+ coordinator -> run
72
+ run -> coordinator
73
+ run -> run
74
+ parent -> branch
75
+ branch -> parent
76
+ coordinator -> tool
77
+ ```
78
+
79
+ Transports differ, but the public contract does not:
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. Generic async-runner `command.done` events and explicit coordinator-bound messages include the actor envelope fields alongside the runtime event fields.
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
+ - `to: tool:<name>` invokes an executable pi tool by name. Object bodies become tool parameters; primitive bodies are passed as `{ "input": body }`.
85
+
86
+ Transport is not public API unless a recipe explicitly documents a custom endpoint.
87
+
88
+ ## Mailbox Declaration
89
+
90
+ Recipes can declare their conversational surface:
91
+
92
+ ```json
93
+ {
94
+ "mailbox": {
95
+ "accepts": ["control.continue", "control.revise", "control.approve", "control.stop"],
96
+ "emits": ["checkpoint.needs_scope", "branch.done", "run.done"]
97
+ }
98
+ }
99
+ ```
100
+
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. 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
+
103
+ ## Spawn
104
+
105
+ `spawn` creates an actor and returns its address:
106
+
107
+ ```json
108
+ {
109
+ "recipe": "subagents-prompts.json",
110
+ "as": "run:review",
111
+ "values": {},
112
+ "artifacts": { "report": "{state_dir}/report.md" }
113
+ }
114
+ ```
115
+
116
+ `spawn` creates detached `run:<id>` actors from a recipe file/name or inline command template. Spawn metadata may include explicit `state_dir` and named `artifacts` for terminal follow-ups and inspection.
117
+
118
+ ## Inspect
119
+
120
+ `inspect` reads state intentionally:
121
+
122
+ ```json
123
+ {
124
+ "target": "run:review",
125
+ "view": "status"
126
+ }
127
+ ```
128
+
129
+ The implementation supports `status`, `tail`, `events`, `artifacts`, `files`, and `mailbox` for `run:<id>` actors, plus `status`/`runs` for `session:<id>` and `session:all` actors with optional status filtering. `inspect` is for decision points and diagnosis only; examples must not teach sleep-then-inspect polling.
130
+
131
+ ## Runtime Direction
132
+
133
+ Runtime operations use the actor/message vocabulary:
134
+
135
+ ```text
136
+ create detached work -> spawn
137
+ run-local control -> message to run:<id>
138
+ coordinator signal -> message to coordinator
139
+ tool execution -> message to tool:<name>
140
+ intentional observe -> inspect
141
+ ```
142
+
143
+ ## Non-goals
144
+
145
+ - No generic expression language in templates.
146
+ - No public FIFO/outbox vocabulary in recipe args.
147
+ - No polling-first examples.
148
+ - No separate upward and downward message schemas.
149
+ - No broad facade that hides artifacts, logs, or ownership checks.