@llblab/pi-actors 0.46.0 → 0.47.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 (78) hide show
  1. package/AGENTS.md +7 -5
  2. package/CHANGELOG.md +20 -0
  3. package/README.md +2 -1
  4. package/dist/lib/async-runs.d.ts +1 -0
  5. package/dist/lib/async-runs.js +4 -1
  6. package/dist/lib/execution.d.ts +1 -0
  7. package/dist/lib/execution.js +1 -0
  8. package/dist/lib/extension-runtime.js +25 -9
  9. package/dist/lib/inspector.js +1 -0
  10. package/dist/lib/prompts.d.ts +6 -5
  11. package/dist/lib/prompts.js +22 -23
  12. package/dist/lib/recipes-context.d.ts +12 -3
  13. package/dist/lib/recipes-context.js +28 -4
  14. package/dist/lib/recipes-discovery.d.ts +22 -0
  15. package/dist/lib/recipes-discovery.js +108 -23
  16. package/dist/lib/recipes-references.d.ts +18 -0
  17. package/dist/lib/recipes-references.js +129 -38
  18. package/dist/lib/registry.d.ts +23 -6
  19. package/dist/lib/registry.js +294 -101
  20. package/dist/lib/runtime.d.ts +30 -3
  21. package/dist/lib/runtime.js +108 -9
  22. package/dist/lib/tools-inspect.d.ts +3 -0
  23. package/dist/lib/tools-inspect.js +190 -26
  24. package/dist/lib/tools-local.d.ts +2 -2
  25. package/dist/lib/tools-local.js +5 -2
  26. package/dist/lib/tools-register.js +2 -1
  27. package/dist/lib/tools-response.js +7 -1
  28. package/dist/lib/tools-spawn.d.ts +2 -2
  29. package/dist/lib/tools-spawn.js +1 -1
  30. package/dist/lib/tools.d.ts +4 -1
  31. package/dist/lib/tools.js +2 -0
  32. package/dist/scripts/conformance.mjs +1 -0
  33. package/dist/skills/actors/SKILL.md +76 -65
  34. package/dist/skills/actors/references/diagnostics.md +44 -0
  35. package/dist/skills/actors/references/persistent-tools.md +74 -0
  36. package/dist/skills/actors/references/recipes.md +51 -0
  37. package/dist/skills/actors/references/runs.md +39 -0
  38. package/dist/skills/artifacts/SKILL.md +24 -7
  39. package/dist/skills/media/SKILL.md +35 -7
  40. package/dist/skills/project-work/SKILL.md +28 -7
  41. package/dist/skills/recipe-memory/SKILL.md +27 -7
  42. package/dist/skills/swarm/SKILL.md +41 -445
  43. package/dist/skills/swarm/references/development-swarm.md +87 -539
  44. package/dist/skills/swarm/references/review-swarms.md +115 -0
  45. package/docs/README.md +5 -5
  46. package/docs/recipe-library.md +15 -10
  47. package/docs/template-recipes.md +3 -1
  48. package/docs/tool-registry.md +18 -6
  49. package/lib/async-runs.ts +5 -1
  50. package/lib/execution.ts +2 -0
  51. package/lib/extension-runtime.ts +33 -14
  52. package/lib/inspector.ts +1 -0
  53. package/lib/prompts.ts +24 -24
  54. package/lib/recipes-context.ts +49 -4
  55. package/lib/recipes-discovery.ts +186 -25
  56. package/lib/recipes-references.ts +176 -44
  57. package/lib/registry.ts +441 -113
  58. package/lib/runtime.ts +147 -12
  59. package/lib/tools-inspect.ts +254 -28
  60. package/lib/tools-local.ts +9 -3
  61. package/lib/tools-register.ts +4 -3
  62. package/lib/tools-response.ts +7 -1
  63. package/lib/tools-spawn.ts +3 -2
  64. package/lib/tools.ts +4 -1
  65. package/package.json +1 -1
  66. package/scripts/conformance.mjs +1 -0
  67. package/skills/actors/SKILL.md +76 -65
  68. package/skills/actors/references/diagnostics.md +44 -0
  69. package/skills/actors/references/persistent-tools.md +74 -0
  70. package/skills/actors/references/recipes.md +51 -0
  71. package/skills/actors/references/runs.md +39 -0
  72. package/skills/artifacts/SKILL.md +24 -7
  73. package/skills/media/SKILL.md +35 -7
  74. package/skills/project-work/SKILL.md +28 -7
  75. package/skills/recipe-memory/SKILL.md +27 -7
  76. package/skills/swarm/SKILL.md +41 -445
  77. package/skills/swarm/references/development-swarm.md +87 -539
  78. package/skills/swarm/references/review-swarms.md +115 -0
package/AGENTS.md CHANGED
@@ -2,13 +2,14 @@
2
2
 
3
3
  ## Meta-Protocol Principles
4
4
 
5
- - `README.md`: human product entrypoint.
6
- - `AGENTS.md`: durable implementation protocol.
5
+ - `README.md` and `docs/`: human-facing product entrypoint, concepts, and reference.
6
+ - `skills/`: agent-facing operating protocols and Skill-local operational references.
7
+ - injected system prompt: routing-only meta-protocol that selects the owning Skill.
8
+ - `AGENTS.md`, source, and tests: implementation protocol and executable evidence.
7
9
  - `BACKLOG.md`: canonical future-only work.
8
10
  - `CHANGELOG.md`: completed delivery history.
9
- - `docs/README.md`: documentation index.
10
11
 
11
- Keep these surfaces distinct and reconcile them after meaningful changes. Every release section, historical or new, keeps at most 8 outcome records of at most 512 characters.
12
+ Do not make normal-use Skills depend on README/docs, do not copy Skill operating manuals into the system prompt, and do not present implementation evidence as the agent operating path. Keep these surfaces distinct and reconcile them after meaningful changes. Every release section, historical or new, keeps at most 8 outcome records of at most 512 characters.
12
13
 
13
14
  ## Concept
14
15
 
@@ -37,7 +38,8 @@ Pi host
37
38
  -> lib/inspector*.ts owner-filtered actor-instance inspection
38
39
  -> scripts/*.mjs process/service entrypoints
39
40
  -> skills/*/recipes/* Skill-owned Recipe components
40
- -> skills/* + docs/* agent and human guidance
41
+ -> skills/* agent operating protocols
42
+ -> README.md / docs/* human product guidance
41
43
  ```
42
44
 
43
45
  `index.ts` wires Pi ports and must not own domain behavior. Keep the local TypeScript import graph acyclic. For architecture-affecting work, load and follow `.agents/skills/domain-dag/SKILL.md`; its validator is local agent tooling, not an npm, CI, or release gate.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.47.0: Agent-Native Actor UX
4
+
5
+ - `Skill-First Operation`: Replaced the injected product manual with a compact Skill-routing meta-protocol. `actors` is now the decision-first authority for generic Recipe/tool/Run mechanics, capability Skills own capability choice, and `swarm` owns only multi-actor methodology.
6
+ - `Persistent Capability Authoring`: Added explicit, mutually exclusive `register_tool from`, `template`, and `draft` modes; public caller `defaults`; canonical Skill/file resolution; compact direct delegation; inherited descriptions, async contracts, typed args, artifacts, Control, and runtime origins; and removal of public `values`.
7
+ - `Registration Truth UX`: Registration now reports logical source, effective required/optional args, persistence, registry/host/active-tool state, callability, activation boundary, and bounded next actions without raw config or executable template payloads. Failed activation retains rollback guarantees.
8
+ - `Focused Diagnosis`: Added `inspect target=recipes view=doctor identity=<skill>/<recipe>` with active ownership, exact resolvability, partial-catalog state, portable source, generation, rejection, and next actions. Tool status now includes source, effective args, activation boundary, and separate spawn/tool usage.
9
+ - `Capability Protocols`: Rewrote all six Skill descriptions as routing triggers and made Media, Artifacts, Project Work, and Recipe Memory compact agent operating guides. Human installation, product, catalog, development, and release guidance remains independently owned by README/docs.
10
+ - `Swarm Methodology`: Reduced Swarm to overhead admission, decomposition, disjoint ownership, lenses, quorum, conflict evidence, integration, and stop rules; moved deep review/development methods to Skill-local references and delegated all generic Run/Recipe mechanics to `actors`.
11
+ - `Safe Recovery`: Inactive, missing, duplicate, removed, malformed, rejected, partial-catalog, and inactive-tool failures now preserve logical identity, redact physical Skill paths, and teach bounded public diagnosis/retry actions without copied contracts, helper paths, shell evaluation, backgrounding, or spawn substitution.
12
+ - `Journey and Package Evidence`: Added deterministic Journeys A-G, reviewed fresh-agent Journey B evidence, and packed first-session parity for final Skills/prompt/references, `from` registration, source-equivalent schema, same-session activation, focused doctor, actual tool invocation, and unshipped `.agents/` evidence.
13
+
14
+ ## 0.46.1: Registration Truth
15
+
16
+ - `Live Resolution`: Spawn, registration, registry admission/reload, schema derivation, and Inspect now consume one immutable session Recipe context. Skill-dependent user wrappers reconcile only after Pi supplies active Skills, watcher reloads retain the current generation, and stale session consumers fail closed.
17
+ - `Effective Admission`: One user-Recipe admission path resolves direct delegation before persistence, inheriting async behavior, typed arguments/defaults, artifacts, Control, and runtime origins without copying maintained contracts. Malformed or mistyped wrappers fail before mutation, and failed updates roll back prior bytes, registry state, host definitions, and active tools.
18
+ - `Schema Ownership`: Caller schemas preserve enum, bool, integer, number, path, and array types while centrally excluding runtime-owned inputs such as `recipe_dir`, `skill_dir`, `state_dir`, Trace/run identity, and runtime state roots. The intentional async `run_id` override remains public.
19
+ - `Fail-Soft Catalog`: Active-Skill inventory returns valid components alongside bounded per-component rejections and an explicit partial state. Invalid unrelated Recipes and duplicate namespaces remain diagnosable without poisoning exact resolution of valid components.
20
+ - `Activation and Observability`: Registration reports resolved, validated, persisted, registry, host, active-tool, and callable states from Pi host evidence. Recipe inspection adds generation, scan, watcher, portable-root, and partial-catalog state; tool status reports current activation and separate spawn/tool usage.
21
+ - `Launch Truth and Dogfood`: Spawn and registered-tool launches expose distinct `launch_kind` evidence. Source and packed-package regressions activate `media/player`, quarantine an unrelated stale component, register and invoke a compact `music_player` in the same session, preserve inherited Control/schema, exercise repair reloads and negative cases, and reject shell/copy workarounds.
22
+
3
23
  ## 0.46.0: Skill-Owned Capability Packs
4
24
 
5
25
  - `Breaking Recipe Grammar`: File-backed identity now comes only from the filename; top-level Recipe `name`, nested Skill identities, JSON/Markdown stem collisions, bare references, and the old `std:` / `skill:` prefixes fail with migration guidance. Composition accepts exact `<active-skill>/<stem>` references or explicit `.json` / `.md` paths, with entry paths based at invocation cwd and relative imports based at their owning Recipe.
package/README.md CHANGED
@@ -74,6 +74,7 @@ inspect target=run:test view=trace source=lifecycle lines=40
74
74
  inspect target=run:test view=control
75
75
  inspect target=runtime view=status
76
76
  inspect target=recipes view=status
77
+ inspect target=recipes view=doctor identity=media/player
77
78
  inspect target=tool:my_tool view=status
78
79
  ```
79
80
 
@@ -81,7 +82,7 @@ A Run exposes exactly `recipe`, `trace`, and `control` views.
81
82
 
82
83
  ### `register_tool`
83
84
 
84
- Persist a trusted command template or Recipe-backed capability under `~/.pi/agent/recipes`. Registration remains separate from running Control.
85
+ Persist a maintained Recipe with `register_tool name=<tool> from=<skill>/<recipe> defaults={...}`, or register a trusted command through the separate `template` mode. Definitions live under `~/.pi/agent/recipes`. Treat a tool as callable in the current session only when the result reports `callable_now: true`; persistence, Recipe spawning, and registered-tool invocation are distinct states.
85
86
 
86
87
  ## Recipe
87
88
 
@@ -68,6 +68,7 @@ export interface AsyncRunMeta {
68
68
  argv: string[];
69
69
  createdAt: string;
70
70
  cwd: string;
71
+ launch_kind?: AsyncRunLaunchSource;
71
72
  launch_source?: AsyncRunLaunchSource;
72
73
  launch_correlation?: {
73
74
  correlation_id?: string;
@@ -326,7 +326,10 @@ export function startRun(params, cwd, options = {}) {
326
326
  createdAt: new Date().toISOString(),
327
327
  cwd,
328
328
  ...(startParams.launch_source
329
- ? { launch_source: startParams.launch_source }
329
+ ? {
330
+ launch_kind: startParams.launch_source,
331
+ launch_source: startParams.launch_source,
332
+ }
330
333
  : {}),
331
334
  ...(startParams.launch_correlation
332
335
  ? { launch_correlation: startParams.launch_correlation } : {}),
@@ -72,6 +72,7 @@ export interface RegisteredToolExecutionResult {
72
72
  command: string;
73
73
  fullOutputPath?: string;
74
74
  killed: boolean;
75
+ launch_kind: "tool";
75
76
  stderrBytes?: number;
76
77
  stderrCapturedBytes?: number;
77
78
  stderrFile?: string;
@@ -709,6 +709,7 @@ export async function executeRegisteredTool(cfg, params, exec, cwd, signal) {
709
709
  command,
710
710
  fullOutputPath: result.stdoutFile ?? formatted.fullOutputPath,
711
711
  killed: result.killed,
712
+ launch_kind: "tool",
712
713
  ...getCaptureDetails(result),
713
714
  ...(executed.branches.length > 0 ? { branches: executed.branches } : {}),
714
715
  ...(executed.failures.length > 0
@@ -8,6 +8,7 @@ import * as CommandTemplates from "./command-templates.js";
8
8
  import * as Paths from "./paths.js";
9
9
  import * as Pi from "./pi.js";
10
10
  import * as Prompts from "./prompts.js";
11
+ import * as RecipeResolution from "./recipes-context.js";
11
12
  import * as RecipesReferences from "./recipes-references.js";
12
13
  import * as RunUiRuntime from "./run-ui-runtime.js";
13
14
  import * as Runtime from "./runtime.js";
@@ -16,10 +17,16 @@ import * as Tools from "./tools.js";
16
17
  import * as ToolsResponse from "./tools-response.js";
17
18
  export function createActorExtensionRuntime(pi) {
18
19
  let activeRunContext;
19
- const skillContextsBySession = new Map();
20
+ const recipeResolutionContextsBySession = new Map();
20
21
  const getRunOwnerId = Pi.getSessionId;
21
- const getSkillContext = (ctx) => skillContextsBySession.get(getRunOwnerId(ctx)) ??
22
- RecipesReferences.EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT;
22
+ const getRecipeResolutionContext = (ctx) => {
23
+ const sessionId = getRunOwnerId(ctx);
24
+ const resolutionContext = recipeResolutionContextsBySession.get(sessionId);
25
+ if (!resolutionContext) {
26
+ throw new Error(`Recipe resolution context is unavailable for session ${sessionId}.`);
27
+ }
28
+ return resolutionContext;
29
+ };
23
30
  const automaticReview = AutomaticReviewRuntime.createAutomaticReviewRuntime({
24
31
  getActiveContext: () => activeRunContext,
25
32
  getRunOwnerId,
@@ -44,7 +51,7 @@ export function createActorExtensionRuntime(pi) {
44
51
  if (ctx && typeof ctx === "object") {
45
52
  nextArgs[4] = {
46
53
  ...ctx,
47
- activeSkillRecipeContext: getSkillContext(ctx),
54
+ recipeResolutionContext: getRecipeResolutionContext(ctx),
48
55
  getThinkingLevel: () => pi.getThinkingLevel(),
49
56
  };
50
57
  }
@@ -61,6 +68,7 @@ export function createActorExtensionRuntime(pi) {
61
68
  configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
62
69
  exec: CommandTemplates.execCommandTemplate,
63
70
  getActiveTools: () => pi.getActiveTools(),
71
+ getAllTools: () => pi.getAllTools(),
64
72
  registerTool: (definition) => {
65
73
  const wrapped = withCurrentThinkingContext(definition);
66
74
  actorToolDefinitions.set(wrapped.name, wrapped);
@@ -69,10 +77,17 @@ export function createActorExtensionRuntime(pi) {
69
77
  reservedToolNames: Tools.RESERVED_TOOL_NAMES,
70
78
  setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
71
79
  });
72
- const recipeReload = Runtime.createRecipeToolReloadWatcher(runtime);
80
+ const recipeReload = Runtime.createRecipeToolReloadWatcher(runtime, {
81
+ getResolutionContext: () => activeRunContext
82
+ ? getRecipeResolutionContext(activeRunContext)
83
+ : undefined,
84
+ });
73
85
  return {
74
86
  beforeAgentStart(systemPrompt, skills, ctx) {
75
- skillContextsBySession.set(getRunOwnerId(ctx), RecipesReferences.createActiveSkillRecipeContext(skills));
87
+ const sessionId = getRunOwnerId(ctx);
88
+ const resolutionContext = RecipeResolution.createRecipeResolutionContext(sessionId, ctx.cwd, RecipesReferences.createActiveSkillRecipeContext(skills));
89
+ recipeResolutionContextsBySession.set(sessionId, resolutionContext);
90
+ runtime.loadTools(ctx, resolutionContext);
76
91
  return {
77
92
  systemPrompt: `${systemPrompt}\n\n${Prompts.ONBOARDING_SYSTEM_PROMPT}`,
78
93
  };
@@ -87,14 +102,15 @@ export function createActorExtensionRuntime(pi) {
87
102
  automaticReview.schedule();
88
103
  },
89
104
  onSessionShutdown(reason, ctx) {
90
- skillContextsBySession.delete(getRunOwnerId(ctx));
105
+ recipeResolutionContextsBySession.delete(getRunOwnerId(ctx));
91
106
  activeRunContext = undefined;
92
107
  automaticReview.close();
93
108
  recipeReload.close();
94
109
  runUiRuntime.shutdown(reason, ctx);
95
110
  },
96
111
  async onSessionStart(ctx) {
97
- skillContextsBySession.set(getRunOwnerId(ctx), RecipesReferences.EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT);
112
+ const sessionId = getRunOwnerId(ctx);
113
+ recipeResolutionContextsBySession.set(sessionId, RecipeResolution.createEmptyRecipeResolutionContext(sessionId, ctx.cwd));
98
114
  ctx.ui.setWidget("zz-pi-actors-comms", undefined);
99
115
  activeRunContext = ctx;
100
116
  runUiRuntime.close();
@@ -104,7 +120,6 @@ export function createActorExtensionRuntime(pi) {
104
120
  if (activeRunContext !== ctx)
105
121
  return;
106
122
  automaticReview.start(ctx);
107
- runtime.loadTools(ctx);
108
123
  runUiRuntime.start(ctx);
109
124
  recipeReload.watch(ctx);
110
125
  },
@@ -113,6 +128,7 @@ export function createActorExtensionRuntime(pi) {
113
128
  configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
114
129
  getActiveTools: () => pi.getActiveTools(),
115
130
  getRuntimeTool: (name) => Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) => actorToolDefinitions.get(activeName)),
131
+ getRuntimeToolStatus: runtime.getToolStatus,
116
132
  handleRuntimeControl: automaticReview.handleControl,
117
133
  registryRuntime: runtime,
118
134
  setActiveTools: (toolNames) => pi.setActiveTools(toolNames),
@@ -115,6 +115,7 @@ export function readActorInspectorRecipe(stateDir) {
115
115
  logical_reference: primaryLogicalReference,
116
116
  ...(typeof primary?.skill === "string" ? { skill: primary.skill } : {}),
117
117
  source_kind: primarySourceKind,
118
+ launch_kind: meta.launch_kind ?? meta.launch_source,
118
119
  launch_source: meta.launch_source,
119
120
  }),
120
121
  launch: redactedRecord({
@@ -4,20 +4,21 @@
4
4
  * Owns LLM-facing descriptions, prompt snippets, guidelines, and parameter descriptions
5
5
  */
6
6
  export declare const REGISTER_TOOL_DESCRIPTION: string;
7
- export declare const REGISTER_TOOL_PROMPT_SNIPPET = "Register persistent command templates as agent-callable tools";
7
+ export declare const REGISTER_TOOL_PROMPT_SNIPPET = "Register persistent Recipes or command templates as agent-callable tools";
8
8
  export declare const REGISTER_TOOL_GUIDELINES: string[];
9
- export declare const ONBOARDING_SYSTEM_PROMPT = "pi-actors quick model:\n- Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.\n- Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.\n- Command templates stay sync and shell-free: string leaves split into executable + argv, infer .js/.mjs through node\u2192bun\u2192deno run and .sh through bash, and treat operators such as && as literal arguments; use template arrays for sequencing or an explicit trusted shell/script when shell semantics are required. Flags include args/defaults, parallel, concurrency, min_successful, when, timeout, delay, retry, failure, recover, repeat, accept_output, output.\n- Placeholders support typed/default args plus {value??fallback} and {flag?yes:no}.\n- ~/.pi/agent/recipes/*.json is actor muscle memory: every recipe there is auto-registered as an agent tool across sessions; register_tool writes there.\n- Recipes own template directly and may declare metadata/defaults/imports/control/artifacts; files >1 MiB or import depth >32 fail closed.\n- Recipe imports are local variables; imported recipes are definitions, not nested async runs; parent async:true creates one run.\n- Actor-mode trigger: if work may outlive this turn, need steering/follow-up/artifacts, run as a service, fan out, or be resumed/inspected later, use spawn -> message -> inspect instead of ad hoc shell backgrounding.\n- Use spawn/message/inspect for actor-level start/send/observe; short foreground checks can stay ordinary tools/templates; avoid internal transport vocabulary in public guidance.\n- Run state lives under ~/.pi/agent/tmp/pi-actors/runs. Inspect intentionally and avoid busy-polling. Terminal and coordinator-bound notifications queue as Pi follow-ups so concurrently completed actors can reach the coordinator after current work instead of steering between tool calls. Terminal follow-up content stays minimal: run, status, one base path, and relative artifact names only; semantic output stays in non-LLM details and run state. When a deferred actor result gates the next step, wait for its terminal follow-up; do not schedule continuation loops, repeatedly inspect, or mutate its reviewed scope while it runs. Inspect early only for an operator request, a meaningful actor event, or diagnosis of an overdue/stuck run.\n- Maintain ~/.pi/agent/recipes like MEMORY.md for capabilities: keep useful tools, curate stale ones, and fix/remove/disable invalid recipes flagged by registry warnings; active-Skill and explicit file Recipes remain components outside user tool discovery; offer to save successful recurring patterns only after confirmation.\n- Prefer maintained active-Skill Recipes with spawn recipe=<skill>/<recipe> before ad hoc scripts/wrappers; explicit file Recipes use exact .json/.md paths; review swarms inherit current model/thinking, preflight before fanout, and expose quorum/concurrency/TTL knobs unless explicit args are passed.\n- For any non-trivial actor use or pi-actors change, read the bundled actors skill first. Before launching multiple actors/subagents for parallel implementation, independent artifact generation, delegated audit, or review, also read the bundled swarm skill; the coordinator owns decomposition, disjoint scopes, launch correctness, integration, and final validation. For deeper guidance, inspect installed extension sources/docs/recipes because README/docs are not automatically in context.";
9
+ export declare const ONBOARDING_SYSTEM_PROMPT = "pi-actors Skill routing:\n- Treat active bundled Skills as the operating authority.\n- For non-trivial pi-actors operation, diagnosis, or development, load and read the actors Skill before acting.\n- For work requiring multiple actors or subagents, additionally load and read the swarm Skill.\n- For capability-specific selection or constraints, load the owning capability Skill; actors owns generic mechanics and swarm owns multi-actor methodology.\n- Keep a Skill Recipe distinct from a registered tool and a Recipe spawn distinct from registered-tool invocation; actors owns the proof rules.\n- Treat persistence or registration as distinct from current callability; actors owns activation proof.\n- On failure or disagreement, preserve the logical Recipe identity, stop, and follow actors diagnosis; never bypass the owning Skills with copied contracts, helper paths, shell evaluation, or background-process workarounds.\n- If a capability Skill conflicts with actors about generic mechanics, follow actors and report the stale capability guidance.\n- README and docs are human-facing references, not the normal agent operating path.\n- AGENTS, source, and tests are implementation protocol and evidence; use them when changing or debugging the extension, not as substitutes for operating Skills.";
10
10
  export declare const REGISTER_TOOL_PARAM_DESCRIPTIONS: {
11
11
  readonly name: "Tool name in snake_case (e.g., 'transcribe')";
12
12
  readonly description: "Describe what the tool does for the LLM. Required unless deleting; omitted updates keep the old description.";
13
- readonly draft: "Promote a draft recipe path from ~/.pi/agent/recipes/drafts into an active named recipe under ~/.pi/agent/recipes. Requires name; use update=true to overwrite.";
13
+ readonly from: "Recipe to specialize by canonical <skill>/<recipe> identity or explicit .json/.md path. Inherits async, args/types, source defaults, artifacts, Control, and runtime origins.";
14
+ readonly defaults: "Optional caller-owned defaults. Keys and values must satisfy the effective source or command-template argument contract.";
15
+ readonly draft: "Promote a captured draft Recipe path from ~/.pi/agent/recipes/drafts. This is a source mode; do not combine it with from or template.";
14
16
  readonly async: "Set true for a co-located async template recipe. Omit for ordinary command templates or file-backed recipe references.";
15
- readonly template: "Command template with {arg} or {arg=default} placeholders, or a template recipe JSON path/name. With async, this is the co-located recipe body. Bare recipe names resolve under ~/.pi/agent/recipes. Omitted updates keep the old template. Empty string deletes the tool.";
17
+ readonly template: "Trusted command template with {arg} or {arg=default} placeholders. To specialize a Recipe, use from instead. Omitted updates keep the old template; empty string deletes the tool.";
16
18
  readonly templateArray: "Sequential command-template composition array. Leaves may be strings or objects with template/defaults/timeout/retry/failure/recover.";
17
19
  readonly templateNull: "Delete the tool when template is null.";
18
20
  readonly args: "Optional comma-separated placeholder declarations. Usually omit because args are derived from template placeholders. Interactive shorthand defaults are accepted and normalized. Example: file,lang,mode=fast";
19
21
  readonly update: "Set to true to overwrite an existing tool registration.";
20
- readonly values: "Optional default runtime placeholder values for a co-located template recipe.";
21
22
  };
22
23
  export declare function formatRegisteredToolPromptSnippet(template: unknown): string;
23
24
  export declare function formatRecipeToolPromptSnippet(recipe: string, asyncRecipe: boolean): string;
@@ -3,41 +3,40 @@
3
3
  * Zones: prompts, onboarding, tool schema copy
4
4
  * Owns LLM-facing descriptions, prompt snippets, guidelines, and parameter descriptions
5
5
  */
6
- export const REGISTER_TOOL_DESCRIPTION = "Register a persistent custom tool from a command template, template recipe path, or co-located template recipe. " +
7
- "Definitions are stored as recipe files under ~/.pi/agent/recipes across reloads. " +
8
- "Use update=true to overwrite an existing tool, template=null/empty to delete.";
9
- export const REGISTER_TOOL_PROMPT_SNIPPET = "Register persistent command templates as agent-callable tools";
6
+ export const REGISTER_TOOL_DESCRIPTION = "Register a persistent custom tool from one maintained Recipe, command template, or captured draft. " +
7
+ "Use from for Recipe specialization, template for trusted commands, or draft for promotion. " +
8
+ "Definitions persist under ~/.pi/agent/recipes; activation is reported separately.";
9
+ export const REGISTER_TOOL_PROMPT_SNIPPET = "Register persistent Recipes or command templates as agent-callable tools";
10
10
  export const REGISTER_TOOL_GUIDELINES = [
11
- "Use register_tool to wrap trusted local commands, scripts, programs, libraries, or template recipes as persistent pi tools.",
12
- "After register_tool succeeds, the new tool is immediately callable and remains available after reload.",
11
+ "Use register_tool from=<skill>/<recipe> with defaults={...} to specialize a maintained Recipe without copying its contract.",
12
+ "Use register_tool template only for trusted command templates, and use register_tool draft only for captured draft promotion.",
13
+ "After register_tool succeeds, trust its callable_now and activation result; persistence alone is not callability.",
13
14
  'Set template=null or template="" in register_tool to delete a persisted tool.',
14
15
  "Set update=true in register_tool to overwrite an existing tool registration.",
15
16
  ];
16
- export const ONBOARDING_SYSTEM_PROMPT = `pi-actors quick model:
17
- - Local-first actor memory: persist trusted local capabilities instead of rebuilding shell recipes.
18
- - Layers: task -> command template -> recipe/tool -> spawn -> run:<id>; tool:<name> wraps registered capabilities.
19
- - Command templates stay sync and shell-free: string leaves split into executable + argv, infer .js/.mjs through node→bun→deno run and .sh through bash, and treat operators such as && as literal arguments; use template arrays for sequencing or an explicit trusted shell/script when shell semantics are required. Flags include args/defaults, parallel, concurrency, min_successful, when, timeout, delay, retry, failure, recover, repeat, accept_output, output.
20
- - Placeholders support typed/default args plus {value??fallback} and {flag?yes:no}.
21
- - ~/.pi/agent/recipes/*.json is actor muscle memory: every recipe there is auto-registered as an agent tool across sessions; register_tool writes there.
22
- - Recipes own template directly and may declare metadata/defaults/imports/control/artifacts; files >1 MiB or import depth >32 fail closed.
23
- - Recipe imports are local variables; imported recipes are definitions, not nested async runs; parent async:true creates one run.
24
- - Actor-mode trigger: if work may outlive this turn, need steering/follow-up/artifacts, run as a service, fan out, or be resumed/inspected later, use spawn -> message -> inspect instead of ad hoc shell backgrounding.
25
- - Use spawn/message/inspect for actor-level start/send/observe; short foreground checks can stay ordinary tools/templates; avoid internal transport vocabulary in public guidance.
26
- - Run state lives under ~/.pi/agent/tmp/pi-actors/runs. Inspect intentionally and avoid busy-polling. Terminal and coordinator-bound notifications queue as Pi follow-ups so concurrently completed actors can reach the coordinator after current work instead of steering between tool calls. Terminal follow-up content stays minimal: run, status, one base path, and relative artifact names only; semantic output stays in non-LLM details and run state. When a deferred actor result gates the next step, wait for its terminal follow-up; do not schedule continuation loops, repeatedly inspect, or mutate its reviewed scope while it runs. Inspect early only for an operator request, a meaningful actor event, or diagnosis of an overdue/stuck run.
27
- - Maintain ~/.pi/agent/recipes like MEMORY.md for capabilities: keep useful tools, curate stale ones, and fix/remove/disable invalid recipes flagged by registry warnings; active-Skill and explicit file Recipes remain components outside user tool discovery; offer to save successful recurring patterns only after confirmation.
28
- - Prefer maintained active-Skill Recipes with spawn recipe=<skill>/<recipe> before ad hoc scripts/wrappers; explicit file Recipes use exact .json/.md paths; review swarms inherit current model/thinking, preflight before fanout, and expose quorum/concurrency/TTL knobs unless explicit args are passed.
29
- - For any non-trivial actor use or pi-actors change, read the bundled actors skill first. Before launching multiple actors/subagents for parallel implementation, independent artifact generation, delegated audit, or review, also read the bundled swarm skill; the coordinator owns decomposition, disjoint scopes, launch correctness, integration, and final validation. For deeper guidance, inspect installed extension sources/docs/recipes because README/docs are not automatically in context.`;
17
+ export const ONBOARDING_SYSTEM_PROMPT = `pi-actors Skill routing:
18
+ - Treat active bundled Skills as the operating authority.
19
+ - For non-trivial pi-actors operation, diagnosis, or development, load and read the actors Skill before acting.
20
+ - For work requiring multiple actors or subagents, additionally load and read the swarm Skill.
21
+ - For capability-specific selection or constraints, load the owning capability Skill; actors owns generic mechanics and swarm owns multi-actor methodology.
22
+ - Keep a Skill Recipe distinct from a registered tool and a Recipe spawn distinct from registered-tool invocation; actors owns the proof rules.
23
+ - Treat persistence or registration as distinct from current callability; actors owns activation proof.
24
+ - On failure or disagreement, preserve the logical Recipe identity, stop, and follow actors diagnosis; never bypass the owning Skills with copied contracts, helper paths, shell evaluation, or background-process workarounds.
25
+ - If a capability Skill conflicts with actors about generic mechanics, follow actors and report the stale capability guidance.
26
+ - README and docs are human-facing references, not the normal agent operating path.
27
+ - AGENTS, source, and tests are implementation protocol and evidence; use them when changing or debugging the extension, not as substitutes for operating Skills.`;
30
28
  export const REGISTER_TOOL_PARAM_DESCRIPTIONS = {
31
29
  name: "Tool name in snake_case (e.g., 'transcribe')",
32
30
  description: "Describe what the tool does for the LLM. Required unless deleting; omitted updates keep the old description.",
33
- draft: "Promote a draft recipe path from ~/.pi/agent/recipes/drafts into an active named recipe under ~/.pi/agent/recipes. Requires name; use update=true to overwrite.",
31
+ from: "Recipe to specialize by canonical <skill>/<recipe> identity or explicit .json/.md path. Inherits async, args/types, source defaults, artifacts, Control, and runtime origins.",
32
+ defaults: "Optional caller-owned defaults. Keys and values must satisfy the effective source or command-template argument contract.",
33
+ draft: "Promote a captured draft Recipe path from ~/.pi/agent/recipes/drafts. This is a source mode; do not combine it with from or template.",
34
34
  async: "Set true for a co-located async template recipe. Omit for ordinary command templates or file-backed recipe references.",
35
- template: "Command template with {arg} or {arg=default} placeholders, or a template recipe JSON path/name. With async, this is the co-located recipe body. Bare recipe names resolve under ~/.pi/agent/recipes. Omitted updates keep the old template. Empty string deletes the tool.",
35
+ template: "Trusted command template with {arg} or {arg=default} placeholders. To specialize a Recipe, use from instead. Omitted updates keep the old template; empty string deletes the tool.",
36
36
  templateArray: "Sequential command-template composition array. Leaves may be strings or objects with template/defaults/timeout/retry/failure/recover.",
37
37
  templateNull: "Delete the tool when template is null.",
38
38
  args: "Optional comma-separated placeholder declarations. Usually omit because args are derived from template placeholders. Interactive shorthand defaults are accepted and normalized. Example: file,lang,mode=fast",
39
39
  update: "Set to true to overwrite an existing tool registration.",
40
- values: "Optional default runtime placeholder values for a co-located template recipe.",
41
40
  };
42
41
  export function formatRegisteredToolPromptSnippet(template) {
43
42
  const rendered = typeof template === "string" ? template : JSON.stringify(template);
@@ -1,10 +1,19 @@
1
1
  /**
2
- * Recipe context prompt assembly.
3
- * Zones: async runner prompt context, recipe provenance, LLM child launches
4
- * Owns compact actor recipe context records appended to child-agent prompts.
2
+ * Recipe context contracts and prompt assembly.
3
+ * Zones: live session resolution, async runner prompt context, recipe provenance, LLM child launches
4
+ * Owns the immutable live Recipe environment and compact actor context appended to child-agent prompts.
5
5
  */
6
6
  import type { CommandTemplateActorRecipeContext } from "./command-templates.ts";
7
+ import * as RecipesReferences from "./recipes-references.ts";
7
8
  import type { TemplateRecipeContextRecord } from "./recipes-references.ts";
9
+ export interface RecipeResolutionContext {
10
+ readonly activeSkills: RecipesReferences.ActiveSkillRecipeContext;
11
+ readonly cwd: string;
12
+ readonly generation: string;
13
+ readonly sessionId: string;
14
+ }
15
+ export declare function createRecipeResolutionContext(sessionId: string, cwd: string, activeSkills: RecipesReferences.ActiveSkillRecipeContext): RecipeResolutionContext;
16
+ export declare function createEmptyRecipeResolutionContext(sessionId: string, cwd: string): RecipeResolutionContext;
8
17
  export interface MarkedRecipeContextRecord extends TemplateRecipeContextRecord {
9
18
  you_are_here?: true;
10
19
  you_are_here_path?: string;
@@ -1,10 +1,34 @@
1
1
  /**
2
- * Recipe context prompt assembly.
3
- * Zones: async runner prompt context, recipe provenance, LLM child launches
4
- * Owns compact actor recipe context records appended to child-agent prompts.
2
+ * Recipe context contracts and prompt assembly.
3
+ * Zones: live session resolution, async runner prompt context, recipe provenance, LLM child launches
4
+ * Owns the immutable live Recipe environment and compact actor context appended to child-agent prompts.
5
5
  */
6
+ import { createHash } from "node:crypto";
6
7
  import { writeFileSync } from "node:fs";
7
- import { basename } from "node:path";
8
+ import { basename, resolve } from "node:path";
9
+ import * as RecipesReferences from "./recipes-references.js";
10
+ export function createRecipeResolutionContext(sessionId, cwd, activeSkills) {
11
+ const normalizedSessionId = sessionId.trim();
12
+ if (!normalizedSessionId)
13
+ throw new Error("Recipe resolution session id is required.");
14
+ const normalizedCwd = resolve(cwd);
15
+ const generation = createHash("sha256")
16
+ .update(JSON.stringify({
17
+ activeSkills: RecipesReferences.getActiveSkillRecipeNamespaces(activeSkills),
18
+ cwd: normalizedCwd,
19
+ sessionId: normalizedSessionId,
20
+ }))
21
+ .digest("hex");
22
+ return Object.freeze({
23
+ activeSkills,
24
+ cwd: normalizedCwd,
25
+ generation,
26
+ sessionId: normalizedSessionId,
27
+ });
28
+ }
29
+ export function createEmptyRecipeResolutionContext(sessionId, cwd) {
30
+ return createRecipeResolutionContext(sessionId, cwd, RecipesReferences.EMPTY_ACTIVE_SKILL_RECIPE_CONTEXT);
31
+ }
8
32
  function commandName(command) {
9
33
  return basename(command).toLowerCase();
10
34
  }
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import * as CommandTemplates from "./command-templates.ts";
7
7
  import type { RegisteredTool } from "./config.ts";
8
+ import type { RecipeResolutionContext } from "./recipes-context.ts";
8
9
  import type { TemplateRecipeConfig } from "./recipes-references.ts";
9
10
  export interface DiscoveredRecipe {
10
11
  id: string;
@@ -18,6 +19,7 @@ export interface DiscoveredRecipe {
18
19
  disabled: boolean;
19
20
  tool: boolean;
20
21
  mutableUsage: boolean;
22
+ resolutionContext?: RecipeResolutionContext;
21
23
  diagnostics: string[];
22
24
  riskLabels: CommandTemplates.CommandTemplateRiskLabel[];
23
25
  shadows: string[];
@@ -44,6 +46,21 @@ export interface RecipesDiscoverySource {
44
46
  file?: string;
45
47
  defaultTool?: boolean;
46
48
  mutableUsage?: boolean;
49
+ resolutionContext?: RecipeResolutionContext;
50
+ }
51
+ export interface UserRecipeAdmission {
52
+ args?: string[];
53
+ argTypes?: RegisteredTool["argTypes"];
54
+ artifacts?: Record<string, string>;
55
+ async?: boolean;
56
+ control?: string[];
57
+ defaults?: Record<string, unknown>;
58
+ diagnostics: string[];
59
+ effectiveRecipe?: TemplateRecipeConfig;
60
+ identity: string;
61
+ sourcePath: string;
62
+ tool?: RegisteredTool;
63
+ validated: boolean;
47
64
  }
48
65
  export declare function hasBroadWindowsWriteAcl(icaclsOutput: string): boolean;
49
66
  export declare function discoverRecipeSources(sources: RecipesDiscoverySource[]): RecipesDiscoveryResult;
@@ -52,4 +69,9 @@ export declare function createRecipeIntegrityManifest(result: RecipesDiscoveryRe
52
69
  export declare function getShadowedLaunchDiagnostic(result: RecipesDiscoveryResult, id: string): Record<string, unknown> | undefined;
53
70
  export declare function listDraftRecipes(root: string): Array<Record<string, unknown>>;
54
71
  export declare function summarizeDiscovery(result: RecipesDiscoveryResult): Record<string, unknown>;
72
+ export declare function summarizeRegisteredToolArgs(tool: RegisteredTool): {
73
+ optional: string[];
74
+ required: string[];
75
+ };
76
+ export declare function admitUserRecipe(sourcePath: string, resolutionContext: RecipeResolutionContext, authoredRecipe?: Record<string, unknown>, mutableUsage?: boolean): UserRecipeAdmission;
55
77
  export declare function toRegisteredTool(entry: DiscoveredRecipe): RegisteredTool | undefined;