@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
@@ -0,0 +1,424 @@
1
+ # Command Template Standard
2
+
3
+ Command templates are the portable integration format for deterministic local automation.
4
+
5
+ **Meta-contract:** transportable (bit-for-bit identical across projects), high-density (zero fluff), constant (evolve by crystallizing, not speculating), optimal minimum (add only when it hurts).
6
+
7
+ **Scope:** portable synchronous command execution format — shell-free exec, composition/pipes, optional timeout, delay-before-start, bounded retry, failure propagation, recover cleanup, output artifact selection, and handler-level fallback. Single JSON standard; no platform lock-in.
8
+
9
+ ---
10
+
11
+ Extensions may choose their own config files, selectors, placeholder sources, and examples, but should preserve this core contract.
12
+
13
+ Layer boundary: command templates own only the synchronous execution graph. Recipe imports, import-reference expressions, recipe lookup, `async: true`, run ids, state dirs, mailbox controls, and actor-message routing are host/recipe/async-run configuration layers, not portable command-template syntax.
14
+
15
+ ## Layer Ownership
16
+
17
+ Command-template standard owns:
18
+
19
+ - Command string splitting and direct argv execution.
20
+ - Placeholder resolution, typed public args, defaults, `??`, ternary string selection, and array-index placeholders.
21
+ - Synchronous graph shape: sequence, `parallel`, `when`, `repeat`, stdin flow, stdout joins, and output selection.
22
+ - Per-node execution controls: `timeout`, `delay`, `retry`, `failure`, and `recover`.
23
+
24
+ Command-template standard does not own:
25
+
26
+ - Where templates are stored or how they are named.
27
+ - Recipe imports, import references, or file lookup.
28
+ - Detached lifecycle, run ids, state dirs, logs, cancellation, mailbox controls, or actor-message routing.
29
+ - Registry metadata such as tool descriptions, package install paths, or operator policy.
30
+
31
+ ## Shape
32
+
33
+ A command template is either a command-line string or an ordered array of command-template leaves:
34
+
35
+ ```json
36
+ {
37
+ "template": "/path/to/stt --file {file} --lang {lang=ru}"
38
+ }
39
+ ```
40
+
41
+ When the surrounding schema already implies a command template, the compact string form is equivalent:
42
+
43
+ ```json
44
+ "/path/to/stt --file {file} --lang {lang=ru}"
45
+ ```
46
+
47
+ There is no portable `command` field. The command is derived from `template`: after splitting, the first word is the executable and the remaining words are argv args. Templates do not infer flags: `{file}` is one positional arg; `--file {file}` is a flag arg plus its value.
48
+
49
+ Common object fields:
50
+
51
+ - `label`: Optional human label for diagnostics and parallel branch reports.
52
+ - `parallel`: Optional boolean for array templates. Default is `false` for sequence; `true` runs children concurrently.
53
+ - `when`: Optional node guard. A false guard skips the node; strings may be `flag`, `!flag`, or `{flag?yes:no}` style expressions.
54
+ - `args`: Optional placeholder declarations. Untyped names remain valid; compact typed forms such as `file:path`, `request_timeout:int`, `speed:number`, `dry_run:bool`, `prompts:array`, and `mode:enum(check,fix)` are valid when the host supports typed tool schemas. Defaults belong in `defaults` or inline placeholder defaults; hosts may normalize interactive shorthand such as `request_timeout:int=60000` before persistence.
55
+ - `defaults`: Placeholder default values by name.
56
+ - `timeout`: Optional execution timeout in milliseconds. Omit it, or set `0`, to leave the command unbounded. Set an explicit positive timeout when a tool must fail closed instead of waiting indefinitely. Numeric control fields may be literal numbers or placeholders such as `"{timeout_ms}"`.
57
+ - `delay`: Optional wait in milliseconds before starting this node. Default is no delay. It may be a literal number or placeholder.
58
+ - `output`: Optional result selector. Default is `"stdout"`; runtime values such as `"ogg"` are valid.
59
+ - `retry`: Optional max attempts including the first. Default is `1`.
60
+ - `failure`: Optional failure propagation scope: `continue`, `branch`, or `root`. Default is `continue`.
61
+ - `recover`: Optional command template run between failed retry attempts. Recovery output is ignored; recovery failure stops retries.
62
+ - `template`: Required command string or ordered composition array.
63
+
64
+ For object form, write `template` last. Read the node flags first, then the executable content. Storage paths, labels, selectors, descriptions, and registry-specific metadata belong to each extension's local schema.
65
+
66
+ ## Execution
67
+
68
+ A runtime must:
69
+
70
+ 1. Split the template into shell-like words with simple single quotes, double quotes, and backslash escapes
71
+ 2. Substitute placeholders inside each split word
72
+ 3. Execute command + args directly, without shell evaluation
73
+ 4. Treat exit code `0` as success and non-zero as failure
74
+ 5. Use stdout as the default result channel and stderr only for diagnostics
75
+
76
+ Implementations may expand `~` in command position and may resolve relative command paths against the caller cwd.
77
+
78
+ ## Placeholders
79
+
80
+ Supported forms:
81
+
82
+ | Form | Meaning |
83
+ | ------------------- | ------------------------------------------------ |
84
+ | `{name}` | Required value from runtime values or `defaults` |
85
+ | `{name=default}` | Inline default when no value is provided |
86
+ | `{name??fallback}` | Fallback when value is missing, null, or empty |
87
+ | `{name?yes:no}` | Ternary string selected by truthiness of `name` |
88
+ | `{items[index]}` | Array item selected by literal or repeat index |
89
+
90
+ Resolution order is runtime values → `defaults` → inline default → error. Nullish coalescing and ternary conditions treat missing, empty, `false`, `0`, and `no` as false. Use `??` for value fallback and ternaries for small string selection such as optional CLI flags; larger policy branches should stay in recipes, scripts, or separate template nodes. Default values that are themselves a single placeholder, such as `{prompt}` resolving to `{prompts[index]}`, are resolved recursively with a small depth guard. A repeat node may set `repeat` to `{items.length}` when an array arg should determine fanout width.
91
+
92
+ ```json
93
+ {
94
+ "template": "/path/to/tts --text {text} --lang {lang=ru} --rate {rate=+30%}"
95
+ }
96
+ ```
97
+
98
+ With runtime values `{ "text": "hello" }`, argv is:
99
+
100
+ ```text
101
+ ["--text", "hello", "--lang", "ru", "--rate", "+30%"]
102
+ ```
103
+
104
+ Use `defaults` for visible configuration data; use inline defaults for compact local literals. Prefer flag-style examples such as `/path/to/tool --file {file} --lang {lang=ru}` for readability, but positional forms such as `/path/to/tool {file} {lang=ru}` are valid when the invoked script defines that CLI contract.
105
+
106
+ Fallback values can be selected with nullish coalescing:
107
+
108
+ ```json
109
+ {
110
+ "template": "deploy --env {env??dev} --region {region??local}"
111
+ }
112
+ ```
113
+
114
+ Optional flags can be mapped from boolean args with a ternary:
115
+
116
+ ```json
117
+ {
118
+ "args": ["target:path", "all:bool"],
119
+ "defaults": { "all": "true" },
120
+ "template": "validate-recipe {target} {all?--all:}"
121
+ }
122
+ ```
123
+
124
+ Typed declarations annotate the public tool interface, not the shell command. They may live in `args` or inline placeholders such as `{request_timeout:int=60000}` and `{mode:enum(check,fix)=check}`. Use metadata-first authoring (`args` plus `defaults`) when long templates should stay visually short; use inline-first authoring when one self-contained `template` property is clearer. They do not sandbox or reinterpret the executable; they only let the host generate narrower input schemas and normalize runtime values before placeholder substitution. Untyped `args` and untyped placeholders continue to work unchanged.
125
+
126
+ Node control fields can also read public args. Use distinct arg names so execution controls stay visually separate from public inputs:
127
+
128
+ ```json
129
+ {
130
+ "args": ["timeout_ms:int"],
131
+ "timeout": "{timeout_ms}",
132
+ "template": "npm test"
133
+ }
134
+ ```
135
+
136
+ ## Quoting
137
+
138
+ Placeholder values are not shell-escaped because no shell is used. A value containing spaces remains one argv item when it replaces one split word:
139
+
140
+ ```text
141
+ template="echo {text}"
142
+ text="hello world"
143
+ args=["hello world"]
144
+ ```
145
+
146
+ A placeholder may also be embedded inside one word:
147
+
148
+ ```text
149
+ template="/path/to/tool --file={file}"
150
+ file="/tmp/a b.ogg"
151
+ args=["--file=/tmp/a b.ogg"]
152
+ ```
153
+
154
+ Use quotes only for literal template words that should contain spaces before placeholder substitution:
155
+
156
+ ```text
157
+ template="echo 'literal words' {text}"
158
+ ```
159
+
160
+ ## Composition
161
+
162
+ `template: [...]` means sequential composition by default; each leaf is a command template executed with one shared runtime value map:
163
+
164
+ ```json
165
+ {
166
+ "template": [
167
+ "/path/to/tts --text {text} --lang {lang=ru} --out {mp3}",
168
+ "ffmpeg -y -i {mp3} -c:a libopus {ogg}"
169
+ ],
170
+ "output": "ogg"
171
+ }
172
+ ```
173
+
174
+ Composition rules:
175
+
176
+ - Execute leaves in order when `parallel` is omitted or `false`
177
+ - Execute child templates concurrently when `parallel` is `true`
178
+ - Parallel composition uses soft-quorum semantics by default: failed children are reported as degraded branches unless failure propagation escalates
179
+ - Non-critical failures are recorded and execution continues, while `failure: "branch"` stops the current branch and `failure: "root"` aborts the root composition
180
+ - Treat the whole composition as one handler for selector matching and fallback
181
+ - Top-level `args` and `defaults` apply to every leaf unless the leaf defines private values
182
+ - Leaf `args` replace inherited `args`; leaf `defaults` merge over inherited defaults; `timeout` and `output` are not inherited into leaves
183
+ - Timeout is disabled by default; configure a positive `timeout` for bounded commands that should fail closed
184
+ - Each sequence leaf receives the previous leaf's stdout on stdin by default, while the final leaf stdout remains the default composition result
185
+ - Skipped nodes preserve current stdin/stdout flow and do not execute commands
186
+ - Each parallel child receives the same stdin, and child stdout values are joined in stable array order before flowing to the next sequence leaf
187
+ - Parallel branch joins include branch label and status, and tool details include branch metadata plus coverage summary
188
+ - Each leaf still applies its own inline defaults
189
+
190
+ ```json
191
+ {
192
+ "template": [
193
+ "/path/to/tts --text {text} --lang {lang} --out {mp3}",
194
+ {
195
+ "defaults": { "codec": "libopus" },
196
+ "template": "ffmpeg -y -i {mp3} -c:a {codec} {ogg}"
197
+ }
198
+ ],
199
+ "args": ["text", "lang", "mp3", "ogg"],
200
+ "defaults": { "lang": "en" },
201
+ "output": "ogg"
202
+ }
203
+ ```
204
+
205
+ `output` selects the primary result channel. Omitted `output` means `"stdout"`, and explicitly writing `"output": "stdout"` is valid standard syntax. Artifact-producing handlers may instead name a runtime value or placeholder path, e.g. `"ogg"` or `"{ogg}"`. Do not use `artifacts` in command-template nodes; named artifact manifests belong to the template-recipe layer.
206
+
207
+ ### Repeat
208
+
209
+ `repeat` expands one command-template node N times before execution. It works with both sequence and parallel nodes and is useful when many branches differ only by a number.
210
+
211
+ ```json
212
+ {
213
+ "parallel": true,
214
+ "repeat": 8,
215
+ "template": "render page{_(index+1)}.html --prev page{_(prev+1)}.html --next page{_(next+1)}.html --zero page{_index}.html"
216
+ }
217
+ ```
218
+
219
+ Reserved repeat placeholders are injected into each repeated node:
220
+
221
+ - `{index}`: current zero-based index, `0..repeat-1`
222
+ - `{prev}` / `{next}`: wrapped zero-based neighbors
223
+ - `{repeat}`: total repeat count
224
+
225
+ Human 1-based numbering is intentionally expressed as limited arithmetic: `{index+1}`, `{prev+1}`, `{next+1}`.
226
+
227
+ Leading underscores on repeat placeholders request zero padding. One underscore means width 2, two underscores mean width 3, and so on:
228
+
229
+ ```text
230
+ {_index} → 00, 01, ...
231
+ {_(index+1)} → 01, 02, ...
232
+ {__(index+1)} → 001, 002, ...
233
+ {_(prev+1)} → wrapped previous page number, padded to width 2
234
+ {_(next+1)} → wrapped next page number, padded to width 2
235
+ ```
236
+
237
+ Repeat expressions support only integers, `index`, `prev`, `next`, `repeat`, parentheses, and `+`, `-`, `*`, `/`, `%`. They are not JavaScript and cannot call functions or access properties.
238
+
239
+ Repeat placeholders are local generated values. Call-time args should not use these reserved names to override the repeat index.
240
+
241
+ Parallel nodes use the same object shape. Flags come first and `template` stays last:
242
+
243
+ ```json
244
+ {
245
+ "template": [
246
+ "prepare {out_dir}",
247
+ {
248
+ "parallel": true,
249
+ "template": [
250
+ {
251
+ "label": "gpt-5.5",
252
+ "timeout": 300000,
253
+ "template": "review-gpt {scope}"
254
+ },
255
+ {
256
+ "label": "deepseek-pro",
257
+ "timeout": 300000,
258
+ "template": "review-deepseek {scope}"
259
+ },
260
+ {
261
+ "label": "kimi",
262
+ "timeout": 300000,
263
+ "template": "review-kimi {scope}"
264
+ }
265
+ ]
266
+ },
267
+ "merge {out_dir}"
268
+ ]
269
+ }
270
+ ```
271
+
272
+ A degraded parallel join is still usable when at least one branch succeeds:
273
+
274
+ ```text
275
+ --- branch: gpt-5.5 status: done ---
276
+ review text
277
+ --- branch: deepseek-pro status: failed ---
278
+ exit: 1
279
+ stderr: provider balance exhausted
280
+ ```
281
+
282
+ Some local schemas may accept `pipe` as an alias, but the portable standard is `template: [...]`.
283
+
284
+ ## Fail-Open Default Policy
285
+
286
+ By default, composition continues on failure: the failed step is logged and the next step executes. This is analogous to `make -k` — the user sees all failures at once and decides what to fix.
287
+
288
+ ## Failure Propagation
289
+
290
+ By default, failed steps use `failure: "continue"`: record the failure, clear stdout for that step, and continue the current sequence. This preserves the fail-open profile.
291
+
292
+ Use `failure` when a node should stop more aggressively:
293
+
294
+ - `"continue"`: record the failure and continue the current sequence.
295
+ - `"branch"`: stop the current sequence/subtree and return a failed branch to the nearest parent. In a parallel node, sibling branches keep running and the join becomes degraded. At the root, branch failure is still a tool failure.
296
+ - `"root"`: abort the outermost composition.
297
+
298
+ ```json
299
+ {
300
+ "parallel": true,
301
+ "template": [
302
+ {
303
+ "label": "agent-a",
304
+ "failure": "branch",
305
+ "template": [
306
+ "agent-a-work {scope}",
307
+ "agent-a-validate {scope}",
308
+ "agent-a-push {scope}"
309
+ ]
310
+ },
311
+ {
312
+ "label": "agent-b",
313
+ "failure": "branch",
314
+ "template": [
315
+ "agent-b-work {scope}",
316
+ "agent-b-validate {scope}",
317
+ "agent-b-push {scope}"
318
+ ]
319
+ }
320
+ ]
321
+ }
322
+ ```
323
+
324
+ If `agent-a-validate` fails, `agent-a-push` is skipped, `agent-b` can still finish, and the parallel join reports degraded branch coverage.
325
+
326
+ ## Retry
327
+
328
+ Set `retry: N` to attempt execution up to `N` times including the first. The first successful attempt stops the retry loop.
329
+
330
+ On leaf commands, retry repeats that command. On sequence or parallel nodes, retry repeats the whole node. A retried group only retries when the group returns a failure, so validator checkpoints normally pair group retry with `failure: "branch"` or `failure: "root"`.
331
+
332
+ ```json
333
+ {
334
+ "failure": "branch",
335
+ "retry": 3,
336
+ "template": ["implement {scope}", "npm test", "git diff --check"]
337
+ }
338
+ ```
339
+
340
+ Here the whole group runs again when a validator fails. Without `failure: "branch"`, the failed validator would be logged and the group would continue by default.
341
+
342
+ ## Recover
343
+
344
+ Set `recover` on a retried node to run cleanup after a failed attempt and before the next attempt. `recover` is another command template: it can be a string command, sequence, or parallel tree. Its output is ignored and the next retry receives the original stdin.
345
+
346
+ ```json
347
+ {
348
+ "failure": "branch",
349
+ "retry": 3,
350
+ "recover": "git -C {work_dir} reset --hard HEAD",
351
+ "template": ["pi -p --tools read,edit,bash {scope_file}", "npm test"]
352
+ }
353
+ ```
354
+
355
+ `recover` is not a fallback success path. It is cleanup between attempts. Practical uses include resetting a worktree, removing temp files, clearing generated output, releasing a local lock, or stopping a helper process before trying the node again. If recovery fails, retries stop and the recovery failure is returned. Recovery uses fail-closed semantics by default; set an explicit `failure` inside a recover template only when a softer cleanup failure is intentional.
356
+
357
+ ## Conditional Nodes
358
+
359
+ Set `when` to skip a node unless a boolean condition is true. This is node-level branching, not placeholder text selection. It is useful for optional validation, artifact, or reporting steps.
360
+
361
+ ```json
362
+ {
363
+ "template": [
364
+ "prepare {target}",
365
+ { "when": "run_tests", "template": "npm test" },
366
+ { "when": "!run_tests", "template": "echo tests skipped" }
367
+ ]
368
+ }
369
+ ```
370
+
371
+ Falsy values are missing, empty, `false`, `0`, and `no`. In a sequence, a skipped node preserves the previous stdout for the next step. In a parallel branch, a skipped node succeeds with empty branch output.
372
+
373
+ ## Delay
374
+
375
+ Set `delay` to wait before starting a node. The value is milliseconds. Delay is not inherited into child nodes, just like `timeout`.
376
+
377
+ ```json
378
+ {
379
+ "template": [
380
+ "prepare {scope}",
381
+ { "delay": 1000, "template": "review {scope}" }
382
+ ]
383
+ }
384
+ ```
385
+
386
+ On a sequence node, `delay` waits before the sequence begins. On a parallel node, `delay` waits before launching its children. On a branch, `delay` waits before that branch starts, without blocking sibling branches.
387
+
388
+ Use `delay` only for explicit backoff, rate pacing, or staged launch. Do not use it as a scheduler.
389
+
390
+ ## Progressive Disclosure
391
+
392
+ The standard uses a single `template` field that grows with the user's needs:
393
+
394
+ ```text
395
+ string → leaf command
396
+ string[] → sequential composition
397
+ { template } → leaf command object
398
+ { parallel, template } → sequence or parallel subtree
399
+ { parallel, when, args, defaults, delay, retry, failure, recover, output, template } → full node
400
+ ```
401
+
402
+ Start with a string. Add composition when needed. Add `parallel: true` when independent work can run concurrently. Add `when` when a node is conditional. Add delay when launch pacing matters. Add retry when flaky. Add `failure` when propagation scope matters. Add `recover` when a retried node needs cleanup before another attempt. Same contract, growing capability, no dead weight.
403
+
404
+ `parallel: true` is the synchronous fanout shape. Saved JSON belongs to the separate [Template Recipe Standard](./template-recipes.md); detached lifecycle, logs, cancellation, and durable state belong to the separate [Async Run Standard](./async-runs.md).
405
+
406
+ ## Trust Boundary
407
+
408
+ Command templates avoid shell interpolation by splitting the template into argv first and substituting placeholders per arg. A placeholder value containing spaces remains one argv value, not a shell fragment.
409
+
410
+ This is not a sandbox. The executable still runs with the same user permissions as the host agent. Shells, interpreter eval modes, destructive filesystem commands, and local scripts remain trusted code. Examples that deserve extra operator attention:
411
+
412
+ - `bash`, `sh`, `zsh`, or `fish`, especially with `-c`.
413
+ - `node -e`, `python -c`, `ruby -e`, `perl -e`, or similar eval modes.
414
+ - `rm`, `mv`, `cp`, or `rsync` over broad paths or placeholder-derived paths.
415
+
416
+ Hosts may surface lightweight warnings for these obvious high-risk shapes. Warnings should inform review without blocking existing tools, because many trusted local wrappers intentionally use shells or filesystem mutation.
417
+
418
+ ## Tool Boundary
419
+
420
+ Agent tools are a separate abstraction. A tool name is not a portable command template because the pi extension API exposes tool registration metadata, not a public extension-to-extension `executeTool(name, args)` contract. Until such an API exists, extensions should use command templates for deterministic local automation.
421
+
422
+ ## Compatibility
423
+
424
+ Consumers should share this contract, not private registry fields or implementation details from any specific extension.
@@ -0,0 +1,148 @@
1
+ # Component Recipes
2
+
3
+ Component recipes are small saved recipe definitions that expose one coordination capability each. They are the construction kit for higher-level subagent coordinators: a coordinator composes components instead of embedding one large orchestration DSL.
4
+
5
+ ## Boundary
6
+
7
+ This is a weak abstract contract, not a hard dependency model.
8
+
9
+ - `pi-actors` provides root `recipes/` actor component definitions and runtime bindings.
10
+ - Portable coordination skills should target capabilities, not this extension by name.
11
+ - Local adapters bind abstract components to concrete recipes, command templates, async runs, model aliases, files, and tool registries.
12
+ - A component should be replaceable by another implementation with the same capability contract.
13
+
14
+ ## Component Contract
15
+
16
+ Every reusable component recipe should make the following clear:
17
+
18
+ - **Capability**: the one operation it performs.
19
+ - **Args**: caller-controlled prompts, scopes, paths, models, and policy knobs.
20
+ - **Output**: the expected shape of stdout or artifact paths.
21
+ - **Messages**: optional actor-message envelopes for checkpoints, questions, progress, or findings.
22
+ - **Failure policy**: whether failures stop the root, only fail a branch, or are recoverable.
23
+ - **Non-goals**: coordination behavior the component intentionally does not own.
24
+
25
+ Reusable components should expose common policy knobs instead of baking in local choices: `model`, `thinking`, `tools`, `output_format`, `evidence_policy`, `risk_policy`, source policy, continuity/resume policy, handoff format, merge mode, model pools, and stage-specific models. Higher-level recipes may pass these knobs through so the same component can run as a safe no-tools reviewer, a file-reading reviewer, a release gate, a research synthesizer, a task-card author, or a high-thinking merger.
26
+
27
+ Keep components narrow. Higher-level recipes should own composition, not hidden behavior inside a leaf.
28
+
29
+ ## Spectrum of Components
30
+
31
+ ### Launchers
32
+
33
+ Start one subagent or branch with a caller-provided prompt and model. Launchers do not judge or merge output.
34
+
35
+ Example: `recipes/subagent-prompt.json`.
36
+
37
+ ### Reviewers
38
+
39
+ Inspect a scope through a declared lens and return evidence-grounded findings.
40
+
41
+ Seed example: `recipes/subagent-review.json`.
42
+
43
+ ### Critics
44
+
45
+ Attack assumptions, edge cases, and failure modes. Critics should not rewrite the plan unless asked.
46
+
47
+ Seed example: `recipes/subagent-critic.json`.
48
+
49
+ ### Planners
50
+
51
+ Turn a goal into bounded slices, validation gates, risks, and stop conditions.
52
+
53
+ Seed example: `recipes/subagent-plan.json`.
54
+
55
+ ### Verifiers
56
+
57
+ Check a claim, artifact, or proposed result against evidence. Verifiers should separate proven, disproven, and unknown.
58
+
59
+ Seed example: `recipes/subagent-verify.json`.
60
+
61
+ ### Evidence and Contradiction Mappers
62
+
63
+ Map source support, weak evidence, contradictions, unresolved assumptions, and missing source classes before synthesis.
64
+
65
+ Seed examples: `recipes/subagent-evidence-map.json` and `recipes/subagent-contradiction-map.json`.
66
+
67
+ ### Mergers
68
+
69
+ Combine multiple branch outputs into a single synthesis. Mergers preserve minority findings and mark unsupported additions.
70
+
71
+ Seed example: `recipes/subagent-merge.json`.
72
+
73
+ ### Normalizers, Artifacts, and Events
74
+
75
+ Convert variable branch output into stable JSON, Markdown sections, file artifacts, or actor-message records for downstream recipes.
76
+
77
+ Seed examples: `recipes/subagent-normalize.json`, `recipes/subagent-artifact.json`, and `recipes/subagent-message.json`.
78
+
79
+ ### Quorum Operators
80
+
81
+ Run the same task across several independent models or instances and preserve vote shape for a later merger.
82
+
83
+ Seed example: `recipes/subagent-quorum.json`.
84
+
85
+ ### Tasking and Conflict Handoffs
86
+
87
+ Produce bounded task cards or conflict reports for development swarms and integrator workflows.
88
+
89
+ Seed examples: `recipes/subagent-task-card.json` and `recipes/subagent-conflict-report.json`.
90
+
91
+ ### Checkpoint Emitters
92
+
93
+ Emit bounded coordinator questions, partial state, or branch decisions as coordinator-bound actor messages. Checkpoint components should not pretend same-context resume exists unless the adapter can prove it.
94
+
95
+ Seed example: `recipes/subagent-checkpoint.json`.
96
+
97
+ ### Follow-up Continuations
98
+
99
+ Resume or continue a branch with a bounded reply. If same-context continuation is unavailable, the component must declare a degraded mode such as creating a new branch with the checkpoint artifact included.
100
+
101
+ Seed example: `recipes/subagent-followup.json`.
102
+
103
+ ### Judges
104
+
105
+ Evaluate report quality, evidence preservation, severity calibration, consensus purity, and internal consistency. Judges should not silently become another domain reviewer.
106
+
107
+ Seed example: `recipes/subagent-judge.json`.
108
+
109
+ ## Composition Shape
110
+
111
+ A coordinator recipe can stay small by composing components:
112
+
113
+ ```text
114
+ launch/review fanout → verify claims → merge → judge → final synthesis
115
+ ```
116
+
117
+ Seed example: `recipes/subagent-review-coordinator.json` composes reviewer fanout, verification, merge, judge, and normalization.
118
+
119
+ Higher-level examples:
120
+
121
+ - `recipes/pipeline-review-readiness.json`: Release/readiness gate over selected lenses.
122
+ - `recipes/pipeline-quorum-review.json`: Same prompt across a model pool, then merge, judge, and normalize vote shape.
123
+ - `recipes/pipeline-architect-coordinator.json`: Architecture direction synthesis with lens fanout, critique, verification, merge, and next-slice output.
124
+ - `recipes/pipeline-research-synthesis.json`: Plan, evidence map, contradiction map, verification, merge, and normalized research synthesis.
125
+ - `recipes/pipeline-checkpoint-continuation.json`: Checkpoint artifact, follow-up continuation, and normalized handoff with explicit degraded-mode handling.
126
+ - `recipes/pipeline-development-tasking.json`: Plan, task card, critique, and normalized integrator handoff for bounded implementation work.
127
+ - `recipes/pipeline-artifact-report.json`: Normalized report → durable artifact-shaped output → actor-message-shaped record.
128
+
129
+ For high-risk work, split breadth and confidence:
130
+
131
+ ```text
132
+ lens swarm → quorum per lens → merger → post-merge judge
133
+ ```
134
+
135
+ For implementation work, combine coordination with local ownership policy:
136
+
137
+ ```text
138
+ task cards → scoped branch agents → conflict reports → integrator merge → review
139
+ ```
140
+
141
+ ## Design Rules
142
+
143
+ - Prefer public args/defaults over baked-in local policy.
144
+ - Use `failure: "branch"` for independent fanout branches unless one failure invalidates the whole run.
145
+ - Keep model pools and provider aliases configurable.
146
+ - Use artifacts or actor messages for intermediate outputs that must survive compaction.
147
+ - Do not hide broad coordinator behavior inside a component named like a leaf.
148
+ - Do not introduce scheduler, goto, or workflow-only syntax; compose saved recipes and command templates.