@llblab/pi-actors 0.49.2 → 0.50.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.
@@ -1,27 +1,45 @@
1
- # Template Recipes
1
+ # Template Recipe Standard
2
2
 
3
- A Recipe stores a reusable command-template definition as JSON or Markdown.
3
+ A Template Recipe is a file-backed, reusable command-template graph. It adds stable identity, typed inputs, composition, optional detached execution, artifacts, Control, and provenance around the portable [Command Template Standard](./command-templates.md).
4
4
 
5
- ## JSON
5
+ ## Mental Model
6
+
7
+ A Recipe has three layers:
8
+
9
+ 1. **Recipe contract**: identity, description, arguments, defaults, imports, lifecycle, artifacts, and Control.
10
+ 2. **Command-template graph**: the executable string, sequence, parallel fanout, conditions, retry, and output behavior stored in `template`.
11
+ 3. **Run projection**: detached process state, Trace, Control delivery, artifacts, and inspection when `async: true`.
12
+
13
+ Use a Recipe when a command graph should be named, validated, reused, imported, registered as a tool, or launched as a Run. Use an inline command template when file identity and Recipe metadata add no value.
14
+
15
+ ## File Formats
16
+
17
+ Recipes may be authored as JSON or Markdown. Both formats compile to the same Recipe contract.
18
+
19
+ ### JSON
20
+
21
+ JSON is the most direct form for structured composition:
6
22
 
7
23
  ```json
8
24
  {
9
- "async": true,
10
- "description": "Create a repository health artifact",
25
+ "description": "Create a repository health report",
11
26
  "args": ["repo:path", "artifact_path:path", "model:string"],
12
- "defaults": { "artifact_path": "{state_dir}/health.md" },
13
- "imports": { "review": "swarm/quorum-review" },
14
- "artifacts": { "report": "{artifact_path}" },
27
+ "defaults": {
28
+ "artifact_path": "{state_dir}/health.md"
29
+ },
30
+ "async": true,
31
+ "artifacts": {
32
+ "report": "{artifact_path}"
33
+ },
15
34
  "template": {
16
- "name": "review",
17
- "values": { "input": "Inspect {repo}", "model": "{model}" }
35
+ "template": "pi -p {repo} --model {model}"
18
36
  }
19
37
  }
20
38
  ```
21
39
 
22
- ## Markdown
40
+ ### Markdown
23
41
 
24
- Markdown Recipes use YAML frontmatter and one executable fence:
42
+ Markdown uses YAML frontmatter for the Recipe contract and one executable fence for `template`:
25
43
 
26
44
  ````markdown
27
45
  ---
@@ -30,142 +48,283 @@ args:
30
48
  - file:path
31
49
  ---
32
50
 
33
- Human notes remain advisory.
51
+ Human-facing notes may explain intent and usage.
34
52
 
35
53
  ```template
36
54
  summarize {file}
37
55
  ```
38
56
  ````
39
57
 
40
- Fences marked `template`, `command-template`, `json`, or `recipe` can define execution. Frontmatter supports Recipe metadata and command-template flags.
58
+ Executable fences may be marked `template`, `command-template`, `json`, or `recipe`. Narrative Markdown outside the executable fence is advisory and is not executed.
59
+
60
+ Choose JSON for dense machine-oriented graphs. Choose Markdown when a short executable definition benefits from nearby human guidance.
61
+
62
+ ## Identity and Placement
63
+
64
+ Recipe identity comes from its location and filename, never from a top-level `name` field.
65
+
66
+ | Placement | Identity | Typical use |
67
+ | --- | --- | --- |
68
+ | Direct file under an active Skill's `recipes/` directory | `<skill>/<filename-stem>` | Maintained Skill capability |
69
+ | Explicit `.json` or `.md` path | Resolved file path with filename-stem evidence | Local or project-specific composition |
70
+ | File under `~/.pi/agent/recipes` | Registered user tool identity | User-maintained reusable tool |
41
71
 
42
- Skill Recipe identity is `<active Skill name>/<Recipe filename stem>`. Recipe files have no top-level `name`; both JSON and Markdown fail with migration guidance when that removed field is present. `SKILL.md` `name` remains Pi host metadata and matches the Skill directory; pi-actors introduces no additional Skill identity field. The `name` field on a command-template node still selects an imported alias and is not Recipe self-identity.
72
+ A Skill Recipe is one direct file under `<skill>/recipes/`. Nested files are not Skill components. The Skill name comes from its active `SKILL.md`; the Recipe stem comes from the direct filename.
43
73
 
44
- ## Fields
74
+ A Recipe file must not declare top-level `name`. Within a command-template graph, a node-level `name` has a different purpose: it invokes an alias declared in `imports`.
45
75
 
46
- Common Recipe fields:
76
+ ## Recipe Field Reference
47
77
 
48
- - `description`, `disabled`;
49
- - `args`, typed arg declarations, inline defaults, `defaults`, and composition `values`;
50
- - `imports` with optional binding defaults/values;
51
- - `template`;
52
- - `async`;
53
- - `singleton: true` for one explicit Skill-owned async service slot;
54
- - `artifacts`;
55
- - `control` for actual controlled services;
56
- - command-template flags such as `parallel`, `concurrency`, `min_successful`, `when`, `timeout`, `delay`, `retry`, `failure`, `recover`, `repeat`, `accept_output`, and `output`;
57
- - `retire_when: "children_terminal"` for opt-in supervisor retirement.
78
+ The following fields belong to the file-level Recipe contract. Unless noted otherwise, each field is optional.
58
79
 
59
- ## Imports
80
+ | Field | Type | Default | Contract |
81
+ | --- | --- | --- | --- |
82
+ | `description` | string | none | Human-facing purpose used by discovery and tool surfaces. Describe the outcome, not implementation history. |
83
+ | `disabled` | boolean | `false` | Prevents launch and import when `true`. Use it to make an authored Recipe intentionally unavailable without deleting the file. |
84
+ | `args` | string[] | inferred/untyped placeholders | Declares public inputs. Entries may be untyped (`input`), typed (`file:path`), enum-constrained (`mode:enum(check,fix)`), or include an inline default (`limit:int=10`). Names must be unique and agree with placeholder types. |
85
+ | `defaults` | object | `{}` | Supplies fallback values for declared inputs. A default may reference another placeholder and is resolved recursively with a depth bound. Every authored default must correspond to a declared argument. |
86
+ | `values` | object | `{}` | Binds composition values before executing the Recipe graph. Use for authored wiring between wrapper/import context and template nodes, not for caller-owned configuration. |
87
+ | `imports` | object | `{}` | Maps local aliases to other Recipes. Each value is a canonical Skill reference, explicit file path, or binding object with `from`, `defaults`, and/or `values`. Imports are resolved and validated before launch. |
88
+ | `template` | string, array, or command-template object | required | Defines the executable command-template graph. It may directly execute commands, compose nodes, invoke import aliases, or delegate to another Recipe. |
89
+ | `async` | boolean | `false` | Launches the Recipe as a detached Run when `true`. Detached execution owns durable state, Trace, terminal reconciliation, and optional Control/artifacts. |
90
+ | `singleton` | boolean | `false` | Gives one async Skill Recipe a stable `run:<skill>` service slot. Valid only with `async: true`; at most one singleton Recipe may belong to a Skill. |
91
+ | `artifacts` | object of string paths | `{}` | Declares named files produced by the Run. Paths support placeholders, resolve under containment policy, and appear in Run inspection. |
92
+ | `control` | string[] | `[]` | Declares actions consumed by an actual controlled service. Actions must be unique lowercase ASCII names, non-reserved, and at most 64 characters. |
93
+ | `retire_when` | `"children_terminal"` | none | Opts an async supervisor into retirement after all owned child Runs become terminal. Omit it for ordinary Run lifecycle. |
94
+ | `actor_context` | boolean or `"off"` | enabled | Controls injection of Recipe composition context into compatible child-agent prompts. Use `false` or `"off"` only when a deliberately minimal child prompt is required. |
95
+
96
+ ### Value Resolution
97
+
98
+ For a declared name, effective values resolve in this order:
99
+
100
+ ```text
101
+ caller values
102
+ → node/import/Recipe values
103
+ → defaults
104
+ → inline argument default
105
+ → missing-value error
106
+ ```
107
+
108
+ The selected value is then validated against its declared type or enum. Runtime-provided origin values such as `{recipe_dir}` and `{skill_dir}` are immutable and cannot be declared or overridden through `args`, `defaults`, or `values`.
109
+
110
+ ## Command-Template Fields
111
+
112
+ A Recipe may place command-template execution fields beside `template`, and any object node inside the graph may use the same fields. Their execution semantics are defined by the [Command Template Standard](./command-templates.md).
113
+
114
+ | Field | Type | Default | Purpose |
115
+ | --- | --- | --- | --- |
116
+ | `label` | string | none | Human-readable node label for diagnostics and branch reports. |
117
+ | `parallel` | boolean | `false` | Runs an array node concurrently instead of sequentially. |
118
+ | `concurrency` | positive integer or placeholder | unlimited | Caps simultaneous children of a parallel node. |
119
+ | `min_successful` | non-negative integer or placeholder | none | Requires a minimum count of successful branches with non-empty stdout. |
120
+ | `when` | boolean or expression | `true` | Skips the node when its guard resolves false. |
121
+ | `timeout` | milliseconds or placeholder | `0` / unbounded | Terminates an execution attempt after a positive duration. |
122
+ | `delay` | milliseconds or placeholder | `0` | Waits before starting the node. |
123
+ | `retry` | positive integer or placeholder | `1` | Sets total attempts, including the first attempt. |
124
+ | `failure` | `continue`, `branch`, or `root` | `continue` | Selects how a node failure propagates through composition. |
125
+ | `recover` | command template | none | Runs cleanup between failed attempts; a recovery failure ends retry. |
126
+ | `repeat` | non-negative integer or expression | none | Repeats a node, exposing the current index to placeholders. |
127
+ | `accept_output` | supported semantic contract | none | Applies fail-closed semantic validation to otherwise successful stdout. |
128
+ | `output` | string selector | `stdout` | Selects the result channel returned by the graph. |
129
+
130
+ Keep Recipe metadata at the file level and execution behavior near the node it controls. For object form, place `template` last so readers encounter contract and execution flags before executable content.
131
+
132
+ ## Imports and Composition
133
+
134
+ Imports are local aliases within one resolved execution graph:
60
135
 
61
136
  ```json
62
137
  {
138
+ "description": "Review and format one report",
139
+ "args": ["input:string", "thinking:string=medium"],
63
140
  "imports": {
64
141
  "review": "swarm/quorum-review",
65
- "report": {
142
+ "format": {
66
143
  "from": "../shared/report.md",
67
- "defaults": { "thinking": "medium" }
144
+ "defaults": {
145
+ "thinking": "{thinking}"
146
+ }
68
147
  }
69
148
  },
70
149
  "template": [
71
- { "name": "review", "values": { "input": "{input}" } },
72
- { "name": "report", "values": { "input": "Use prior output" } }
150
+ {
151
+ "name": "review",
152
+ "values": {
153
+ "input": "{input}"
154
+ }
155
+ },
156
+ {
157
+ "name": "format",
158
+ "values": {
159
+ "input": "Use prior output"
160
+ }
161
+ }
73
162
  ]
74
163
  }
75
164
  ```
76
165
 
77
- Imports are local definitions. Named nodes call imported templates inside the same execution graph and Run. Effective values follow `caller > node/import/Recipe values > defaults > inline arg default > missing-value error`, then the selected value is checked against its declared type or enum.
166
+ ### Accepted References
78
167
 
79
- Imports accept exactly `<skill>/<recipe>` or an explicit `.json` / `.md` file path. A Skill reference selects one direct filename stem under the exact Skill currently active through Pi resource discovery; duplicate active Skill identities and JSON/Markdown stem collisions fail closed. Explicit paths may be relative (`./local-review.json`, `../shared/report.md`) or absolute (`/absolute/path/to/recipe.json`). An entry file path resolves from invocation `cwd`; a relative import resolves from the importing Recipe's directory. No bare or ambient lookup remains.
168
+ An import `from` value accepts exactly one of these forms:
80
169
 
81
- Direct delegation can use another Recipe as the entire template. The delegated Recipe remains the source of truth while the wrapper may narrow args/defaults or override selected lifecycle metadata.
170
+ | Form | Resolution |
171
+ | --- | --- |
172
+ | `<skill>/<recipe>` | One direct filename stem under the exact active Skill |
173
+ | `./file.json` or `../file.md` | Relative to the importing Recipe's directory |
174
+ | `/absolute/path/to/file.json` | Exact absolute file |
82
175
 
83
- A launched Run captures each entry/import role, filename-derived stem, logical reference, Skill identity when owned, and import alias ancestry. Private physical source paths remain execution provenance; Inspector and child-agent context expose logical identities rather than machine-local Skill locations.
176
+ An entry Recipe path resolves from invocation `cwd`. A relative import resolves from the importing Recipe, not from invocation `cwd`. Bare ambient names and implicit fallback search are not part of the contract.
84
177
 
85
- ## Migration from pre-0.46 references
178
+ Duplicate active Skill names, duplicate JSON/Markdown stems, missing references, disabled targets, import cycles, and excessive import depth fail closed. A launched Run captures the resolved graph; later catalog changes affect future launches only.
86
179
 
87
- ```text
88
- std:foo -> owning-skill/foo
89
- skill:foo/bar -> foo/bar
90
- root packaged foo -> owning-skill/new-file-stem
91
- Recipe name field -> delete; filename is identity
92
- nested skill path -> flatten filename or use explicit file path
180
+ ### Import Bindings
181
+
182
+ A string import uses the target as authored:
183
+
184
+ ```json
185
+ { "review": "swarm/quorum-review" }
93
186
  ```
94
187
 
95
- Removed `std:` and `skill:` forms fail with migration guidance; they are not aliases. Root packaged Recipes no longer exist. Flatten a maintained Skill component to a direct filename, or reference a nested/local file explicitly when it is intentionally outside the Skill component namespace.
188
+ An object binding can supply alias-local defaults or values:
96
189
 
97
- ## Singleton Services
190
+ ```json
191
+ {
192
+ "review": {
193
+ "from": "swarm/quorum-review",
194
+ "defaults": { "thinking": "medium" },
195
+ "values": { "mode": "strict" }
196
+ }
197
+ }
198
+ ```
199
+
200
+ Use `defaults` when callers may override the value. Use `values` for authored composition wiring subject to the normal resolution order.
201
+
202
+ ### Direct Delegation
203
+
204
+ A Recipe may use another Recipe as its entire template. The delegated Recipe remains authoritative while the wrapper may narrow public arguments, defaults, or selected lifecycle metadata. Singleton Run and Recipe identities remain owned by the delegated singleton; wrappers cannot create alternate service identities.
205
+
206
+ ## Async Runs and Singleton Services
98
207
 
99
- `singleton: true` is valid only for an async Skill Recipe, and one Skill may declare at most one singleton Recipe. The runtime derives `run:<skill>` and the canonical `<skill>/<recipe>` identity, then rejects a conflicting caller-supplied Run id. A compatible repeated launch returns the healthy active generation; contradictory Recipe identity, ownership, startup values, or Control fails closed. A terminal result is never reused even during runner exit; retry after that process exits starts a fresh `run_instance_id` under the same logical Run id. Actor-owned workload continuity requires a validated state artifact that restart cleanup deliberately preserves; singleton identity alone never proves restored state.
208
+ `async: true` changes execution from an inline result to a detached Run. The Run receives durable state, stdout/stderr evidence, Trace, generation identity, and terminal reconciliation.
100
209
 
101
- Direct Recipe delegation inherits the original singleton Run and Recipe identities, so registered tools and explicit wrappers cannot retarget the service or create parallel aliases.
210
+ A singleton Recipe additionally follows these rules:
211
+
212
+ - it must be a direct Recipe owned by one active Skill;
213
+ - it must declare `async: true`;
214
+ - one Skill may declare at most one singleton Recipe;
215
+ - its logical address is `run:<skill>`;
216
+ - a compatible repeated launch reuses the healthy active generation;
217
+ - conflicting Recipe identity, owner, startup values, or Control contract fails closed;
218
+ - terminal generations are never reused;
219
+ - singleton identity alone does not restore workload state after restart.
220
+
221
+ Use singleton only for a genuine long-lived Skill service. Ordinary jobs should remain non-singleton Runs.
102
222
 
103
223
  ## Control
104
224
 
105
- Only a process that consumes actor-local input declares actions:
225
+ Declare Control only when the launched process consumes actor-local input:
106
226
 
107
227
  ```json
108
228
  {
229
+ "description": "Run a controllable service",
109
230
  "async": true,
110
231
  "control": ["pause", "resume", "stop"],
111
232
  "template": "{skill_dir}/scripts/service.mjs --state-dir {state_dir}"
112
233
  }
113
234
  ```
114
235
 
115
- Actions must be lowercase ASCII, unique, non-reserved, and at most 64 characters. Serialized Control input is at most 380 bytes so every admitted wire record remains within 512 bytes on FIFO and named pipe. One-shot Recipes omit Control. Larger data belongs in a declared artifact/path; outputs belong in Trace, artifacts, execution evidence, or the command result.
236
+ Control action names are lowercase ASCII, unique, non-reserved, and at most 64 characters. Serialized Control input is limited to 380 bytes so admitted wire records remain within 512 bytes on FIFO and named pipe transports.
237
+
238
+ Do not use Control as a general data channel. Large inputs belong in declared files or artifacts; outputs belong in Trace, artifacts, execution evidence, or the command result.
116
239
 
117
240
  ## Artifacts
118
241
 
242
+ Declare deterministic outputs by stable name:
243
+
119
244
  ```json
120
245
  {
121
246
  "artifacts": {
122
247
  "report": "{state_dir}/report.md",
123
248
  "manifest": "{state_dir}/manifest.json"
124
- }
249
+ },
250
+ "template": "generate-report --output {state_dir}/report.md"
125
251
  }
126
252
  ```
127
253
 
128
- Artifact paths resolve under containment policy and appear in Run inspection. Recipes should write declared artifacts deterministically and fail when the requested write policy cannot be honored.
129
-
130
- ## File Origins
131
-
132
- Every file-backed Recipe receives immutable `{recipe_dir}`. A Recipe under an active Skill also receives `{skill_dir}`, resolved to the directory containing that Skill's `SKILL.md`; using `{skill_dir}` elsewhere fails clearly. These runtime values cannot be declared in `args`, `defaults`, or `values`, and caller input cannot override them. They expand in templates, recursive defaults/values, imports, and artifacts while existing `./` executable behavior remains relative to invocation `cwd`.
254
+ Artifact declarations do not create files. The Recipe must write them and fail when its write policy cannot be honored. Inspection reports declaration, availability, size, and digest evidence without treating undeclared arbitrary paths as public artifacts.
133
255
 
134
- ## Context and Provenance
256
+ ## Runtime Origins
135
257
 
136
- File-backed Runs capture Recipe context records for the entry and imports. File identity is the filename stem; a direct Recipe under an active Skill has the logical identity `<skill>/<stem>`. The captured bundle explains composition identity and remains generation-local evidence. Runtime origin paths remain in local Run provenance but are omitted from model-facing launch values. It does not override the authored task prompt.
258
+ Every file-backed Recipe receives immutable `{recipe_dir}`, the directory containing the Recipe file. A Recipe directly owned by an active Skill also receives `{skill_dir}`, the directory containing that Skill's `SKILL.md`.
137
259
 
138
- Recipes that need a minimal child prompt may opt out of injected Recipe context through the documented `actor_context` launch option.
260
+ | Placeholder | Availability | Meaning |
261
+ | --- | --- | --- |
262
+ | `{recipe_dir}` | every file-backed Recipe | Stable origin for Recipe-relative helpers and assets |
263
+ | `{skill_dir}` | active Skill-owned Recipe only | Stable origin for Skill-owned helpers and assets |
264
+ | `{state_dir}` | async Run context | Generation-local durable Run state directory |
265
+ | `{current_model}` | when current Pi policy is available | Current model inherited as an explicit resolved value |
266
+ | `{current_thinking}` | when current Pi policy is available | Current thinking policy inherited as an explicit resolved value |
139
267
 
140
- ## Current Policy
268
+ Origin and policy placeholders expand through templates, recursive defaults/values, imports, and artifacts where applicable. Resolution fails before launch when a required runtime value is unavailable.
141
269
 
142
- Defaults can inherit current Pi policy:
270
+ Example policy inheritance:
143
271
 
144
272
  ```json
145
273
  {
274
+ "args": ["model:string", "thinking:string"],
146
275
  "defaults": {
147
276
  "model": "{current_model}",
148
277
  "thinking": "{current_thinking}"
149
- }
278
+ },
279
+ "template": "pi -p inspect --model {model} --thinking {thinking}"
150
280
  }
151
281
  ```
152
282
 
153
- Resolution fails before launch when required current policy is unavailable. The Run persists whether values were inherited or explicit.
283
+ ## Context and Provenance
284
+
285
+ A file-backed launch captures generation-local records for the entry Recipe and every resolved import. Records include role, filename stem, logical reference, Skill identity when applicable, and import alias ancestry.
154
286
 
155
- ## Resolution Context
287
+ Logical identities are exposed to Inspector and child-agent context. Machine-local physical paths remain local execution provenance and are not promoted into model-facing launch values.
156
288
 
157
- User Recipes under `~/.pi/agent/recipes` remain intentionally registered tools, not an ambient import namespace. Each session receives one immutable resolution context from Pi's loaded Skill metadata; spawn, user-Recipe admission, registration, schema derivation, live inspection, and watcher reconciliation consume that same context rather than scanning ambient Skill roots or keeping a process-global mutable namespace. A launch captures its resolved graph, so later Skill changes affect only future launches. An invalid or missing exact target fails without fallback. Disabled Recipes cannot launch. Registry watchers converge after atomic changes without executing partial definitions.
289
+ `actor_context` controls only compatible child-prompt injection:
158
290
 
159
- Active-Skill catalog inventory is fail-soft diagnostic state, not exact-resolution authority. Invalid components are reported individually and make the catalog partial while unrelated valid `<skill>/<recipe>` references remain exactly resolvable.
291
+ ```json
292
+ {
293
+ "actor_context": false,
294
+ "template": "pi -p minimal-task"
295
+ }
296
+ ```
297
+
298
+ Disabling injected context does not remove Run provenance or change the authored task prompt.
299
+
300
+ ## Authoring Checklist
301
+
302
+ 1. Choose a direct Skill identity or explicit file location.
303
+ 2. When useful, add one outcome-oriented `description`; descriptions are optional.
304
+ 3. Declare every public input in `args`, including types where useful.
305
+ 4. Put overridable fallback configuration in `defaults`.
306
+ 5. Add imports only when composition earns a stable local alias.
307
+ 6. Keep execution flags on the node they govern.
308
+ 7. Use `async` only when detached lifecycle or durable evidence is required.
309
+ 8. Declare `control` only for actions the process actually consumes.
310
+ 9. Declare deterministic artifact paths before writing them.
311
+ 10. Validate exact references, portable paths, and platform assumptions.
160
312
 
161
313
  ## Validation
162
314
 
315
+ Validate one Recipe:
316
+
163
317
  ```bash
164
318
  node skills/actors/scripts/validate-recipe.mjs path/to/recipe.json --qa
319
+ ```
320
+
321
+ Validate all maintained Skill Recipes:
322
+
323
+ ```bash
165
324
  node skills/actors/scripts/validate-recipe.mjs skills --skills --qa --summary
166
325
  ```
167
326
 
168
- Skill validation recursively inventories every direct `<skill>/recipes/*.json|*.md` component, rejects nested files and duplicate stems, and checks filename identity, JSON/Markdown compilation, origins, imports, Control, artifacts, portable paths, helper targets, and platform notes. Files exceeding 1 MiB or import depth 32 fail closed.
327
+ Validation checks file size, filename identity, JSON/Markdown compilation, argument contracts, imports, cycles and depth, runtime origins, Control, artifacts, portable paths, helper targets, and platform notes. Recipe files larger than 1 MiB and import graphs deeper than 32 levels fail closed.
169
328
 
170
329
  ## Related
171
330
 
@@ -22,9 +22,21 @@ Specialize a maintained Recipe without copying its contract:
22
22
  register_tool name=music_player from=music-player/playback defaults={"source":"~/Music/1MIX"}
23
23
  ```
24
24
 
25
- `from`, `template`, and `draft` are distinct source modes. `from` accepts exact `<skill>/<recipe>` identity or an explicit `.json` / `.md` path and inherits async behavior, args/types, source defaults, artifacts, Control, and runtime-owned origins. `defaults` may set only effective caller-owned args and must satisfy their types. `template` is only for trusted command definitions; public `values` authoring has been removed in favor of caller defaults or an authored Recipe file.
25
+ `from`, `template`, and `draft` are distinct source modes. `from` accepts exact `<skill>/<recipe>` identity or an explicit `.json` / `.md` path and inherits async behavior, args/types, source defaults, artifacts, Control, and runtime-owned origins. `defaults` may set only effective caller-owned args and must satisfy their types. `template` is only for trusted command definitions; specialization accepts caller `defaults`, while authored composition values belong in a Recipe file.
26
26
 
27
- Promote an immutable captured draft only with its draft path and explicit target name. Name collisions require `update=true`. Invalid content fails before active mutation.
27
+ Promote an immutable captured draft only with its draft path and explicit target name:
28
+
29
+ ```text
30
+ register_tool name=repo_check draft=~/.pi/agent/recipes/drafts/<captured-recipe>.json
31
+ ```
32
+
33
+ Delete a persisted definition through the same fenced mutation path:
34
+
35
+ ```text
36
+ register_tool name=repo_check template=null
37
+ ```
38
+
39
+ An empty `template` string is the equivalent deletion form. Do not delete registry files manually. Host-visible dynamic definitions may remain visible until reload because Pi cannot unregister them, but extension-local lookup rejects the deleted definition immediately. Name collisions for creation or replacement require `update=true`. Invalid content fails before active mutation.
28
40
 
29
41
  Registration resolves the effective delegated contract before persistence, then reports logical `source`, effective `required_args` / `optional_args`, and distinct `persisted`, `registry_active`, `host_registered`, `active_tool`, and `callable_now` states. A callable result points to the actual generated tool as the next action. An uncallable result names its `activation_boundary` and status/doctor action without suggesting spawn as a substitute. Diagnose one maintained source with `inspect target=recipes view=doctor identity=<skill>/<recipe>`; diagnose final activation, source, schema summary, and separate spawn/tool usage with `inspect target=tool:<name> view=status`. Treat the tool as callable in the current session only when `callable_now` is true; persistence alone is not activation proof. Registration results omit raw persisted paths and executable template/config payloads.
30
42
 
@@ -41,10 +53,19 @@ inspect target=recipes view=status
41
53
  inspect target=tool:<name> view=status
42
54
  ```
43
55
 
44
- Recipe inspection reports generation, scan/watch state, active, shadowed, invalid, disabled, component rejection, diagnostic, risk, usage, and review evidence. Tool status reports current activation plus separate `tool_calls` and `spawn_calls`; tool schema reports the caller-owned capability contract. A registered tool is not a running actor.
56
+ Recipe inspection reports generation, scan/watch state, active, shadowed, invalid, disabled, component rejection, diagnostic, risk, usage, and review evidence. Tool status reports current activation plus separate `tool_calls` and `spawn_calls`; tool schema reports the caller-owned capability contract. Inspect the complete target/view contract in [Management Inspection](./inspection.md). A registered tool is not a running actor.
45
57
 
46
58
  `spawn recipe=<name>` executes a Recipe and reports `launch_kind: "spawn"`; it does not prove that a registered tool was exposed or invoked. Registered-tool execution reports `launch_kind: "tool"`.
47
59
 
60
+ Async registered tools add runtime-owned optional invocation parameters after resolving the Recipe contract:
61
+
62
+ | Parameter | Availability | Purpose |
63
+ | --- | --- | --- |
64
+ | `run_id` | non-singleton async tools | Overrides the generated logical Run id for this invocation |
65
+ | `transport_context` | all async tools | Preserves an originating transport route for detached terminal follow-up |
66
+
67
+ These parameters are not Recipe-authored args. Singleton tools do not expose `run_id` because their canonical Run identity is owned by the Skill Recipe.
68
+
48
69
  ## Automatic Review
49
70
 
50
71
  Automatic draft/tool review remains silent and mechanically fenced: