@llblab/pi-actors 0.47.0 → 0.48.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ > Each release keeps at most 8 outcome records of at most 512 characters.
4
+
5
+ ## 0.48.1: Persistent Skill Composition
6
+
7
+ - `Persistent Skill Composition`: Made `register_tool from=<skill>/<recipe>` use Pi's authoritative active-session Skill snapshot across every admitted Skill location and activate synchronous or asynchronous tools from the resolved effective contract. Compact user Recipes retain logical delegation without copied contracts, absolute helper paths, symlinks, or ambient runtime re-resolution.
8
+
9
+ ## 0.48.0: Host-Coordinated Swarms
10
+
11
+ - `Coordinator And Swarm Methodology`: Defined gatewayless host coordination with companion transports as presence only; the coordinator accepts declarative outcomes, creates explicit Runs, stays available, and owns integration/final validation. Reasoning is role-allocated: bounded authors default off, independent reviewers/integrators use medium, and the coordinator selects evidence-worthy fanout. Swarm retains overhead admission, disjoint ownership, isolation, mutation freeze, and event/timer observation.
12
+
3
13
  ## 0.47.0: Agent-Native Actor UX
4
14
 
5
15
  - `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.
@@ -7,7 +17,6 @@
7
17
  - `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
18
  - `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
19
  - `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
20
  - `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
21
  - `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
22
 
package/README.md CHANGED
@@ -11,6 +11,12 @@ Run = Recipe + Trace + Control
11
11
 
12
12
  An **actor** is any runnable local capability: a script, tool, service, pipeline, or subagent. A **Recipe** is its reusable executable definition. `spawn` creates a **Run**—one concrete actor instance—which captures its Recipe, appends observable **Trace**, and may consume actor-local **Control**.
13
13
 
14
+ ## Local Coordinator Model
15
+
16
+ Multi-instance systems commonly put instance creation and routing in an external gateway. pi-actors supports a different topology: the current Pi instance remains the coordinator, companion extensions such as Telegram provide presence, and explicit Runs perform bounded delegated work. The coordinator receives high-level outcomes, decomposes them, stays available for decisions, and owns integration plus final validation instead of becoming another undifferentiated worker.
17
+
18
+ This topology does not require every task to become a subagent. Short work with one natural validation boundary stays inline; delegation pays when clean context, asynchronous execution, independent judgement, parallel ownership, or coordinator availability exceeds its coordination cost. Bounded implementation can run with reasoning off while the coordinator selectively launches clean-context reasoning-enabled reviewers; several independent reviews can provide broader evidence than one author self-review. Terminal follow-ups, durable Trace, and declared artifacts replace tight polling loops.
19
+
14
20
  ## Install
15
21
 
16
22
  ```bash
package/banner.jpg CHANGED
Binary file
@@ -127,6 +127,9 @@ export function createActorExtensionRuntime(pi) {
127
127
  Pi.registerToolDefinitions(pi, Tools.createCoreActorToolDefinitions({
128
128
  configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
129
129
  getActiveTools: () => pi.getActiveTools(),
130
+ getRecipeResolutionContext: () => activeRunContext
131
+ ? getRecipeResolutionContext(activeRunContext)
132
+ : undefined,
130
133
  getRuntimeTool: (name) => Tools.resolveActiveRuntimeTool(name, runtime.getTools(), (activeName) => actorToolDefinitions.get(activeName)),
131
134
  getRuntimeToolStatus: runtime.getToolStatus,
132
135
  handleRuntimeControl: automaticReview.handleControl,
@@ -5,6 +5,7 @@
5
5
  */
6
6
  import * as CommandTemplates from "./command-templates.ts";
7
7
  import * as Config from "./config.ts";
8
+ import * as RecipesContext from "./recipes-context.ts";
8
9
  export interface RegisterToolInput {
9
10
  name?: string;
10
11
  description?: string;
@@ -55,6 +56,7 @@ export interface RegisterToolRuntimeDeps<TContext> {
55
56
  recipeRoot?: string;
56
57
  getToolNameBlocker: (name: string) => string | undefined;
57
58
  getTools: () => Map<string, Config.RegisteredTool>;
59
+ getRecipeResolutionContext?: () => RecipesContext.RecipeResolutionContext | undefined;
58
60
  getActiveTools: () => string[];
59
61
  notify: (ctx: TContext, message: string, type: "info" | "warning" | "error") => void;
60
62
  registerRuntimeTool: (cfg: Config.RegisteredTool) => RuntimeActivation | void;
@@ -233,9 +233,10 @@ function getInputTemplate(value) {
233
233
  throw new Error(ExecutionOutput.formatToolText("Tool template must be a string, object, or sequence."));
234
234
  }
235
235
  function getRegistrationResolutionContext(ctx, deps) {
236
- if (ctx &&
237
- typeof ctx === "object" &&
238
- "recipeResolutionContext" in ctx) {
236
+ const runtimeContext = deps.getRecipeResolutionContext?.();
237
+ if (runtimeContext)
238
+ return runtimeContext;
239
+ if (ctx && typeof ctx === "object" && "recipeResolutionContext" in ctx) {
239
240
  const resolutionContext = ctx.recipeResolutionContext;
240
241
  if (resolutionContext)
241
242
  return resolutionContext;
@@ -415,15 +416,18 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
415
416
  let persisted = false;
416
417
  let activation;
417
418
  let cfg;
419
+ let transactionStage = "persist";
418
420
  try {
419
421
  persistToolRecipe(deps, name, authoredRecipe);
420
422
  persisted = true;
423
+ transactionStage = "persisted_admission";
421
424
  const admitted = RecipesDiscovery.admitUserRecipe(recipePath, resolutionContext);
422
425
  if (!admitted.validated || !admitted.tool) {
423
426
  throw new Error(`Persisted tool recipe admission failed: ${admitted.diagnostics.join("; ")}`);
424
427
  }
425
428
  cfg = admitted.tool;
426
429
  tools.set(name, cfg);
430
+ transactionStage = "runtime_activation";
427
431
  activation = deps.registerRuntimeTool(cfg) ?? undefined;
428
432
  if (activation &&
429
433
  (!activation.host_registered ||
@@ -447,7 +451,7 @@ function executeRegisterToolUnlocked(params, ctx, deps) {
447
451
  tools.delete(name);
448
452
  }
449
453
  deps.setActiveTools(activeBefore);
450
- throw new Error(ExecutionOutput.formatToolText(`Tool registration transaction failed: ${error instanceof Error ? error.message : String(error)}`));
454
+ throw new Error(ExecutionOutput.formatToolText(`Tool registration transaction failed at ${transactionStage} (${resolutionContext.generation}; active Skills: ${activeSkillSummary(resolutionContext)}): ${error instanceof Error ? error.message : String(error)}`));
451
455
  }
452
456
  deps.notify(ctx, `Tool activated: ${name}`, "info");
453
457
  const templateWarnings = CommandTemplates.getCommandTemplateWarnings(typeof cfg.recipe?.template === "object" && !Array.isArray(cfg.recipe.template)
@@ -93,8 +93,9 @@ export function createRuntimeToolDefinition(cfg, exec) {
93
93
  const paramSchema = {};
94
94
  const required = [];
95
95
  const isRecipe = RecipesReferences.isRecipeTool(cfg.template, cfg.recipe);
96
- const isAsyncRecipe = cfg.recipe?.async === true ||
97
- RecipesReferences.isAsyncRecipeReference(cfg.template);
96
+ const isAsyncRecipe = cfg.recipe
97
+ ? cfg.recipe.async === true
98
+ : RecipesReferences.isAsyncRecipeReference(cfg.template);
98
99
  const recipeTemplate = cfg.recipe?.template ?? RecipesReferences.getRecipeTemplate(cfg.template);
99
100
  const requiredTemplate = recipeTemplate ?? cfg.template;
100
101
  const requiredTemplateConfig = typeof requiredTemplate === "object" && !Array.isArray(requiredTemplate)
@@ -112,7 +113,7 @@ export function createRuntimeToolDefinition(cfg, exec) {
112
113
  const requiredArgs = isRecipe && cfg.storedArgs !== undefined
113
114
  ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg) &&
114
115
  !Object.hasOwn(recipeInlineDefaults, arg)))
115
- : RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
116
+ : !cfg.recipe && RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
116
117
  ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
117
118
  : Schema.getRequiredToolArgNames(requiredTemplateConfig);
118
119
  for (const arg of cfg.args) {
@@ -14,6 +14,7 @@ export interface ActorToolDefinition {
14
14
  export interface CoreActorToolDefinitionDeps<TContext extends RuntimeToolContext> {
15
15
  configPath: string;
16
16
  getActiveTools: () => string[];
17
+ getRecipeResolutionContext: () => import("./recipes-context.ts").RecipeResolutionContext | undefined;
17
18
  getRuntimeTool: (name: string) => unknown;
18
19
  getRuntimeToolStatus: (name: string) => Record<string, unknown> | undefined;
19
20
  handleRuntimeControl?: (action: string, input: unknown) => Record<string, unknown>;
package/dist/lib/tools.js CHANGED
@@ -30,6 +30,7 @@ export function createCoreActorToolDefinitions(deps) {
30
30
  getActiveTools: deps.getActiveTools,
31
31
  getToolNameBlocker: deps.registryRuntime.getToolNameBlocker,
32
32
  getTools: deps.registryRuntime.getTools,
33
+ getRecipeResolutionContext: deps.getRecipeResolutionContext,
33
34
  notify: deps.registryRuntime.notify,
34
35
  registerRuntimeTool: deps.registryRuntime.registerRuntimeTool,
35
36
  reservedToolNames: RESERVED_TOOL_NAMES,
@@ -52,7 +52,7 @@ direct delegation ≠ named import composition
52
52
  Run Control ≠ actor chat
53
53
  ```
54
54
 
55
- A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool` creates or updates a persistent user tool. A tool is callable in the current session only when activation evidence says `callable_now: true`.
55
+ A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool from=<skill>/<recipe>` persists compact logical delegation and activates from the resolved effective contract without copying, symlinking, or ambient re-resolution. A tool is callable in the current session only when activation evidence says `callable_now: true`.
56
56
 
57
57
  `actors` owns generic Recipe/tool/Run mechanics. The owning capability Skill owns capability-specific selection and constraints. `swarm` owns multi-actor decomposition and integration methodology.
58
58
 
@@ -76,6 +76,17 @@ Then:
76
76
 
77
77
  Use direct delegation for the same maintained capability under a persistent name or narrower defaults. Use named imports only when one Recipe graph contains reusable child nodes. See [persistent tools](./references/persistent-tools.md) and [Recipes](./references/recipes.md).
78
78
 
79
+ ## Local coordinator topology
80
+
81
+ There are two distinct multi-instance shapes:
82
+
83
+ - A gateway-centric system owns ingress, agent-instance creation, routing, and lifecycle outside the agents.
84
+ - A host-coordinator system keeps the current Pi instance as the control plane; companion extensions such as Telegram provide presence, while pi-actors creates explicit local Runs for delegated work.
85
+
86
+ In host-coordinator mode, the top-level agent receives declarative outcomes, preserves user authority and global context, delegates bounded concrete execution, and owns integration plus final validation. It is not merely another worker after delegation begins. One bounded implementation worker normally runs with reasoning off; consequential output receives a separate reasoning-enabled review. Several independent participants or reviewers additionally use `swarm`.
87
+
88
+ Delegation is not mandatory for every prompt. Work inline when one short bounded act has one natural validation boundary and spawning would add more coordination than isolation, latency hiding, clean context, or continued coordinator availability can repay. For admitted delegation, prefer terminal follow-up and durable Trace/artifacts; inspect on meaningful attention, operator request, or an evidence-based overdue timer rather than busy polling.
89
+
79
90
  ## Run workflow
80
91
 
81
92
  A Run is one concrete execution of a Recipe:
@@ -28,6 +28,8 @@ register_tool
28
28
 
29
29
  `from` means logical direct delegation. The source remains authoritative for async behavior, caller args and types, source defaults, artifacts, Control, and runtime-owned origins. The persistent user Recipe stores only the compact specialization; do not copy inherited fields.
30
30
 
31
+ Resolution uses Pi's authoritative active-session Skill snapshot across every Skill location Pi admits. Registration resolves and validates the maintained source, persists only its logical `<skill>/<recipe>` reference plus caller specialization, and projects the already-resolved effective contract into the runtime tool. Never replace this composition with a copied Recipe, absolute helper path, symlink, or ambient runtime re-resolution.
32
+
31
33
  Use `description` to narrow agent-facing intent when useful. Every supplied default must name a caller-owned source arg and satisfy its type or enum. Never default runtime-owned origins.
32
34
 
33
35
  ## Prove registration
@@ -9,6 +9,25 @@ Use multi-actor execution only when at least two scopes or evidence lenses are m
9
9
 
10
10
  Read `actors` first for generic Recipe, spawn, Run, Trace, Control, artifact, and lifecycle operation. This Skill owns only multi-actor methodology: decomposition, scope ownership, independence, synthesis, integration, and completion proof.
11
11
 
12
+ ## Coordinator topology
13
+
14
+ A swarm can be coordinated without an external gateway. In this model the current host agent is the declarative control plane, the actor kernel creates explicit participant Runs, and companion transports provide ingress or presence without owning hidden agent creation. The coordinator retains user authority, global context, decomposition, shared-surface ownership, integration, and final validation; participants own bounded concrete tasks and report evidence.
15
+
16
+ This resembles gateway orchestration in dependency direction but not in ownership: the coordinator is itself an agent instance with inspectable Runs, not an infrastructure service that implicitly creates sessions. Preserve that distinction in prompts, docs, recovery, and target routing.
17
+
18
+ Once work is delegated, keep the coordinator available for decisions and integration instead of duplicating participant implementation. Wait for terminal follow-up by default; use meaningful attention or evidence-based timers for overdue work rather than a tight inspection loop.
19
+
20
+ ## Reasoning allocation
21
+
22
+ Allocate reasoning by role instead of making one long thread implement and judge itself:
23
+
24
+ - Bounded implementation/authorship participants default to reasoning off when the task card fixes scope, invariants, checks, and escalation. Enable reasoning only when unresolved diagnosis or local design judgement is part of their assignment.
25
+ - Reviewers default to independent medium reasoning and clean context. For consequential work, several reviewers with distinct lenses or repeated independent judgement usually provide better error discovery than increasing one author's reasoning and relying on self-review.
26
+ - Synthesizers and integrators use medium reasoning because they reconcile evidence, conflicts, shared contracts, and retained state.
27
+ - The coordinator decides whether review fanout is worth its cost, preserves dissent, and never treats reviewer count as evidence quality by itself.
28
+
29
+ Do not change a running participant's profile merely because policy changed. Replace or add a later independent review only when fresh evidence is still needed.
30
+
12
31
  ## Choose the shape
13
32
 
14
33
  | Need | Shape | Primary Recipe |
@@ -29,18 +48,22 @@ The coordinator owns the whole result even when participants choose local implem
29
48
  1. State the goal, non-goals, evidence standard, integration owner, and stop condition.
30
49
  2. Partition work into disjoint read or write scopes. Give shared contracts one owner.
31
50
  3. Give each participant a bounded task card with allowed scope, avoided scope, expected artifact, checks, and escalation rule.
32
- 4. Preflight required model/tool access before expensive fanout.
33
- 5. Launch independent work without cross-contaminating lenses. Do not let participants silently expand scope.
34
- 6. Preserve every terminal result, including failures, disagreements, and partial evidence.
35
- 7. Merge through one named synthesizer or integrator. Resolve conflicts from explicit intent and invariants, not textual convenience.
36
- 8. Run fresh integrated validation and, for consequential outputs, an independent post-merge review.
37
- 9. Report complete, degraded, or insufficient-data status honestly; name residual owners and next actions.
51
+ 4. Assign each participant an explicit execution profile and isolation mode under the reasoning-allocation contract.
52
+ 5. Preflight required model/tool access before expensive fanout.
53
+ 6. Launch independent work without cross-contaminating lenses. Do not let participants silently expand scope.
54
+ 7. Preserve every terminal result, including failures, disagreements, and partial evidence; avoid doing participant work in the coordinator while a valid owner remains active.
55
+ 8. Merge through one named synthesizer or integrator. Resolve conflicts from explicit intent and invariants, not textual convenience.
56
+ 9. Run fresh integrated validation and, for consequential outputs, an independent post-merge review.
57
+ 10. Report complete, degraded, or insufficient-data status honestly; name residual owners and next actions.
38
58
 
39
59
  ## Scope and coordination rules
40
60
 
41
61
  - One writable scope has one owner. Parallel readers may share a stable target.
42
62
  - Public contracts, schemas, central configuration, and integration surfaces require exclusive ownership.
43
- - Participants record out-of-scope needs instead of opportunistically editing them.
63
+ - Concurrent writers use disjoint paths, isolated worktrees, or declared patch/artifact outputs.
64
+ - Shared ledgers, lockfiles, generated contracts, metadata, schemas, release surfaces, and cross-domain configuration belong to one named integrator unless a task card transfers one surface to another exclusive owner.
65
+ - Participants record shared-surface and other out-of-scope needs in handoff instead of editing them opportunistically.
66
+ - Reasoning and model profiles are task-card inputs, not implicit properties of the whole swarm.
44
67
  - Coordinator checkpoints are bounded decision requests, not free-form actor chat.
45
68
  - Locks support scope ownership but do not replace coordinator judgement. Every lock must be bounded and releasable.
46
69
  - One integrator owns merge order, conflict resolution, and final validation.
@@ -14,6 +14,39 @@ Use a development swarm only when all are true:
14
14
 
15
15
  Do not parallelize implementation when tasks need the same central files, semantic ordering dominates wall-clock time, or the likely conflicts would invalidate the decomposition. Use planning or review first.
16
16
 
17
+ ## Coordinator role separation
18
+
19
+ In a host-coordinator topology, the current Pi instance owns the declarative outcome and participant graph rather than acting as the default implementation worker. It may receive intent through Telegram or another companion extension, but transport does not become a gateway or gain hidden instance-creation authority; participant creation remains an explicit actor-kernel Run.
20
+
21
+ The coordinator should:
22
+
23
+ - Translate high-level intent into bounded task cards and dependency edges.
24
+ - Keep user authority, shared contracts, integration order, and final validation local.
25
+ - Remain available for checkpoints, permissions, conflicts, and changing evidence.
26
+ - Consume terminal handoffs, durable artifacts, and Trace attention instead of mirroring participant work.
27
+ - Check overdue work on an evidence-based timer; never replace event-driven completion with a rapid polling loop.
28
+
29
+ A participant should:
30
+
31
+ - Own one concrete execution or evidence boundary.
32
+ - Avoid global orchestration and undeclared participant creation.
33
+ - Return a bounded handoff that lets the coordinator decide without replaying the entire task.
34
+
35
+ Use one ordinary Run under `actors` when only one worker is delegated. Activate this development-swarm protocol when two or more participants, parallel ownership, or explicit integration edges exist. Keep trivial single-boundary work inline when delegation overhead has no compensating value.
36
+
37
+ ## Reasoning profiles
38
+
39
+ | Role | Default | Raise or fan out when |
40
+ | --- | --- | --- |
41
+ | Bounded implementation author | Reasoning off | The card explicitly owns unresolved diagnosis or design judgement |
42
+ | Reviewer | Medium reasoning, clean context | Stakes require independent lenses or repeated judges |
43
+ | Synthesizer / integrator | Medium reasoning | Evidence conflicts, shared contracts move, or merge order is semantic |
44
+ | Coordinator | Sufficient for decomposition and decisions | Scope, authority, or architecture remains unresolved |
45
+
46
+ Prefer independent review after implementation over asking one author thread to implement, retain all local assumptions, and then certify itself. When risk justifies the cost, use multiple independent reviewers: different lenses increase breadth, while repeated judges increase confidence. Preserve minority high-impact findings and merge only evidence-backed conclusions.
47
+
48
+ More reviewers are not automatically better. Do not fan out when they would inspect unstable code, share contaminated context, repeat one unsupported claim, or exceed the value of the decision. Never change an already-running participant solely to enforce a newer profile; add a fresh review boundary if evidence remains open.
49
+
17
50
  ## Decompose by ownership
18
51
 
19
52
  Prefer mutation-zone ownership over broad feature labels.
@@ -38,6 +71,9 @@ Goal:
38
71
  Non-goals:
39
72
  Allowed files or logical scope:
40
73
  Avoided files or shared contracts:
74
+ Execution profile:
75
+ Isolation mode: exclusive paths | isolated worktree | artifact-only
76
+ Shared surfaces reserved for integrator:
41
77
  Expected artifact or patch:
42
78
  Required evidence:
43
79
  Checks:
@@ -60,6 +96,14 @@ A useful task card names the smallest scope that can independently reach a valid
60
96
 
61
97
  If a participant discovers that another scope must change, it emits a dependency or conflict report and stops that edge. The coordinator either transfers ownership, serializes the work, or replans.
62
98
 
99
+ ## Isolation modes
100
+
101
+ - `Exclusive paths`: Writers share one worktree only when their complete writable path sets are disjoint and the shared baseline remains stable.
102
+ - `Isolated worktree`: Use when compilation, generated files, imports, or likely dependencies can touch shared repository state.
103
+ - `Artifact-only`: Use for reports, inventories, proposed patches, fixtures, or reviews that the integrator applies later.
104
+
105
+ The integrator exclusively owns `BACKLOG.md`, `CHANGELOG.md`, lockfiles, generated metadata, public schemas, release manifests, and cross-domain configuration by default. A task card may transfer one of these surfaces to another participant, but never create concurrent ownership. Authors report required shared-surface changes in handoff instead of applying them outside scope.
106
+
63
107
  ## Coordinator checkpoints
64
108
 
65
109
  A checkpoint preserves useful local context while requesting one decision:
@@ -129,13 +173,14 @@ The integrator resolves from both reports. Architecture conflicts stop affected
129
173
 
130
174
  The named integrator:
131
175
 
132
- 1. reads task cards, handoffs, dependency edges, and conflict reports;
133
- 2. verifies each result stayed within scope;
134
- 3. integrates in dependency order, one ownership edge at a time;
135
- 4. resolves conflicts while preserving stated invariants;
136
- 5. runs checks after risky edges and the full agreed validation at the end;
137
- 6. obtains fresh review for conflict-resolved or shared-contract changes;
138
- 7. reports integrated tasks, rejected or deferred work, checks, and residual risks.
176
+ 1. freezes new author mutations and preserves every terminal handoff before integration;
177
+ 2. reads task cards, handoffs, dependency edges, and conflict reports;
178
+ 3. verifies each result stayed within scope;
179
+ 4. integrates in dependency order, one ownership edge at a time;
180
+ 5. resolves conflicts while preserving stated invariants;
181
+ 6. runs checks after risky edges and the full agreed validation at the end;
182
+ 7. obtains fresh review for conflict-resolved or shared-contract changes;
183
+ 8. reports integrated tasks, rejected or deferred work, checks, and residual risks.
139
184
 
140
185
  Do not treat a clean merge, participant-local tests, or a collection of terminal Runs as integrated completion. Completion requires retained shared state plus coordinator-owned validation evidence.
141
186
 
@@ -73,7 +73,7 @@ Usage and lineage live in locked metadata ledgers rather than authored Recipe fi
73
73
 
74
74
  ## Specializing Existing Recipes
75
75
 
76
- Use `register_tool from=<skill>/<recipe> defaults={...}` for one maintained capability under a persistent name or narrower defaults. The stored user Recipe remains compact direct delegation; it does not copy async, args/types, Control, artifacts, helpers, or runtime-owned `{recipe_dir}`/`{skill_dir}`. Named imports remain for multi-node Recipe composition, not one-source specialization. Skill Recipes remain components and are never exposed merely because their Skill is active. Install only specific capabilities; internal automatic-review Recipes must not become user-callable tools.
76
+ Use `register_tool from=<skill>/<recipe> defaults={...}` for one maintained capability under a persistent name or narrower defaults. Pi supplies one authoritative active-session Skill snapshot across global, project, package, settings, CLI, and extension-contributed locations. Registration resolves the source from that snapshot, stores only the logical direct-delegation reference plus caller specialization, and activates the tool from the already-resolved effective contract without ambient re-resolution. It does not copy async, args/types, Control, artifacts, helpers, or runtime-owned `{recipe_dir}`/`{skill_dir}`; symlinks and absolute helper paths are not substitutes. Named imports remain for multi-node Recipe composition, not one-source specialization. Skill Recipes remain components and are never exposed merely because their Skill is active. Install only specific capabilities; internal automatic-review Recipes must not become user-callable tools.
77
77
 
78
78
  ## Safety
79
79
 
@@ -160,6 +160,10 @@ export function createActorExtensionRuntime(
160
160
  Tools.createCoreActorToolDefinitions<Pi.ExtensionContext>({
161
161
  configPath: Paths.EXTENSION_RUNTIME_PATHS.configPath,
162
162
  getActiveTools: () => pi.getActiveTools(),
163
+ getRecipeResolutionContext: () =>
164
+ activeRunContext
165
+ ? getRecipeResolutionContext(activeRunContext)
166
+ : undefined,
163
167
  getRuntimeTool: (name) =>
164
168
  Tools.resolveActiveRuntimeTool(
165
169
  name,
package/lib/registry.ts CHANGED
@@ -73,6 +73,7 @@ export interface RegisterToolRuntimeDeps<TContext> {
73
73
  recipeRoot?: string;
74
74
  getToolNameBlocker: (name: string) => string | undefined;
75
75
  getTools: () => Map<string, Config.RegisteredTool>;
76
+ getRecipeResolutionContext?: () => RecipesContext.RecipeResolutionContext | undefined;
76
77
  getActiveTools: () => string[];
77
78
  notify: (
78
79
  ctx: TContext,
@@ -422,11 +423,9 @@ function getRegistrationResolutionContext<TContext>(
422
423
  ctx: TContext,
423
424
  deps: RegisterToolRuntimeDeps<TContext>,
424
425
  ): RecipesContext.RecipeResolutionContext {
425
- if (
426
- ctx &&
427
- typeof ctx === "object" &&
428
- "recipeResolutionContext" in ctx
429
- ) {
426
+ const runtimeContext = deps.getRecipeResolutionContext?.();
427
+ if (runtimeContext) return runtimeContext;
428
+ if (ctx && typeof ctx === "object" && "recipeResolutionContext" in ctx) {
430
429
  const resolutionContext = (ctx as {
431
430
  recipeResolutionContext?: RecipesContext.RecipeResolutionContext;
432
431
  }).recipeResolutionContext;
@@ -697,9 +696,11 @@ function executeRegisterToolUnlocked<TContext>(
697
696
  let persisted = false;
698
697
  let activation: RuntimeActivation | undefined;
699
698
  let cfg: Config.RegisteredTool;
699
+ let transactionStage = "persist";
700
700
  try {
701
701
  persistToolRecipe(deps, name, authoredRecipe);
702
702
  persisted = true;
703
+ transactionStage = "persisted_admission";
703
704
  const admitted = RecipesDiscovery.admitUserRecipe(
704
705
  recipePath,
705
706
  resolutionContext,
@@ -711,6 +712,7 @@ function executeRegisterToolUnlocked<TContext>(
711
712
  }
712
713
  cfg = admitted.tool;
713
714
  tools.set(name, cfg);
715
+ transactionStage = "runtime_activation";
714
716
  activation = deps.registerRuntimeTool(cfg) ?? undefined;
715
717
  if (
716
718
  activation &&
@@ -737,7 +739,7 @@ function executeRegisterToolUnlocked<TContext>(
737
739
  deps.setActiveTools(activeBefore);
738
740
  throw new Error(
739
741
  ExecutionOutput.formatToolText(
740
- `Tool registration transaction failed: ${error instanceof Error ? error.message : String(error)}`,
742
+ `Tool registration transaction failed at ${transactionStage} (${resolutionContext.generation}; active Skills: ${activeSkillSummary(resolutionContext)}): ${error instanceof Error ? error.message : String(error)}`,
741
743
  ),
742
744
  );
743
745
  }
@@ -147,9 +147,9 @@ export function createRuntimeToolDefinition(
147
147
  const paramSchema: Record<string, JsonSchema> = {};
148
148
  const required: string[] = [];
149
149
  const isRecipe = RecipesReferences.isRecipeTool(cfg.template, cfg.recipe);
150
- const isAsyncRecipe =
151
- cfg.recipe?.async === true ||
152
- RecipesReferences.isAsyncRecipeReference(cfg.template);
150
+ const isAsyncRecipe = cfg.recipe
151
+ ? cfg.recipe.async === true
152
+ : RecipesReferences.isAsyncRecipeReference(cfg.template);
153
153
  const recipeTemplate =
154
154
  cfg.recipe?.template ?? RecipesReferences.getRecipeTemplate(cfg.template);
155
155
  const requiredTemplate = recipeTemplate ?? cfg.template!;
@@ -177,7 +177,7 @@ export function createRuntimeToolDefinition(
177
177
  !Object.hasOwn(recipeInlineDefaults, arg),
178
178
  ),
179
179
  )
180
- : RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
180
+ : !cfg.recipe && RecipesReferences.isRecipeReference(cfg.template) && !recipeTemplate
181
181
  ? new Set(cfg.args.filter((arg) => !Object.hasOwn(cfg.defaults, arg)))
182
182
  : Schema.getRequiredToolArgNames(requiredTemplateConfig);
183
183
  for (const arg of cfg.args) {
package/lib/tools.ts CHANGED
@@ -24,6 +24,7 @@ export interface CoreActorToolDefinitionDeps<
24
24
  > {
25
25
  configPath: string;
26
26
  getActiveTools: () => string[];
27
+ getRecipeResolutionContext: () => import("./recipes-context.ts").RecipeResolutionContext | undefined;
27
28
  getRuntimeTool: (name: string) => unknown;
28
29
  getRuntimeToolStatus: (name: string) => Record<string, unknown> | undefined;
29
30
  handleRuntimeControl?: (
@@ -68,6 +69,7 @@ export function createCoreActorToolDefinitions<
68
69
  getActiveTools: deps.getActiveTools,
69
70
  getToolNameBlocker: deps.registryRuntime.getToolNameBlocker,
70
71
  getTools: deps.registryRuntime.getTools,
72
+ getRecipeResolutionContext: deps.getRecipeResolutionContext,
71
73
  notify: deps.registryRuntime.notify,
72
74
  registerRuntimeTool: deps.registryRuntime.registerRuntimeTool,
73
75
  reservedToolNames: RESERVED_TOOL_NAMES,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@llblab/pi-actors",
3
- "version": "0.47.0",
3
+ "version": "0.48.1",
4
4
  "private": false,
5
5
  "description": "Local Actor Kernel for Pi",
6
6
  "keywords": [
@@ -52,7 +52,7 @@ direct delegation ≠ named import composition
52
52
  Run Control ≠ actor chat
53
53
  ```
54
54
 
55
- A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool` creates or updates a persistent user tool. A tool is callable in the current session only when activation evidence says `callable_now: true`.
55
+ A Skill Recipe is a maintained component addressed by `<skill>/<recipe>`. `spawn` creates a Run from a Recipe. `register_tool from=<skill>/<recipe>` persists compact logical delegation and activates from the resolved effective contract without copying, symlinking, or ambient re-resolution. A tool is callable in the current session only when activation evidence says `callable_now: true`.
56
56
 
57
57
  `actors` owns generic Recipe/tool/Run mechanics. The owning capability Skill owns capability-specific selection and constraints. `swarm` owns multi-actor decomposition and integration methodology.
58
58
 
@@ -76,6 +76,17 @@ Then:
76
76
 
77
77
  Use direct delegation for the same maintained capability under a persistent name or narrower defaults. Use named imports only when one Recipe graph contains reusable child nodes. See [persistent tools](./references/persistent-tools.md) and [Recipes](./references/recipes.md).
78
78
 
79
+ ## Local coordinator topology
80
+
81
+ There are two distinct multi-instance shapes:
82
+
83
+ - A gateway-centric system owns ingress, agent-instance creation, routing, and lifecycle outside the agents.
84
+ - A host-coordinator system keeps the current Pi instance as the control plane; companion extensions such as Telegram provide presence, while pi-actors creates explicit local Runs for delegated work.
85
+
86
+ In host-coordinator mode, the top-level agent receives declarative outcomes, preserves user authority and global context, delegates bounded concrete execution, and owns integration plus final validation. It is not merely another worker after delegation begins. One bounded implementation worker normally runs with reasoning off; consequential output receives a separate reasoning-enabled review. Several independent participants or reviewers additionally use `swarm`.
87
+
88
+ Delegation is not mandatory for every prompt. Work inline when one short bounded act has one natural validation boundary and spawning would add more coordination than isolation, latency hiding, clean context, or continued coordinator availability can repay. For admitted delegation, prefer terminal follow-up and durable Trace/artifacts; inspect on meaningful attention, operator request, or an evidence-based overdue timer rather than busy polling.
89
+
79
90
  ## Run workflow
80
91
 
81
92
  A Run is one concrete execution of a Recipe:
@@ -28,6 +28,8 @@ register_tool
28
28
 
29
29
  `from` means logical direct delegation. The source remains authoritative for async behavior, caller args and types, source defaults, artifacts, Control, and runtime-owned origins. The persistent user Recipe stores only the compact specialization; do not copy inherited fields.
30
30
 
31
+ Resolution uses Pi's authoritative active-session Skill snapshot across every Skill location Pi admits. Registration resolves and validates the maintained source, persists only its logical `<skill>/<recipe>` reference plus caller specialization, and projects the already-resolved effective contract into the runtime tool. Never replace this composition with a copied Recipe, absolute helper path, symlink, or ambient runtime re-resolution.
32
+
31
33
  Use `description` to narrow agent-facing intent when useful. Every supplied default must name a caller-owned source arg and satisfy its type or enum. Never default runtime-owned origins.
32
34
 
33
35
  ## Prove registration
@@ -9,6 +9,25 @@ Use multi-actor execution only when at least two scopes or evidence lenses are m
9
9
 
10
10
  Read `actors` first for generic Recipe, spawn, Run, Trace, Control, artifact, and lifecycle operation. This Skill owns only multi-actor methodology: decomposition, scope ownership, independence, synthesis, integration, and completion proof.
11
11
 
12
+ ## Coordinator topology
13
+
14
+ A swarm can be coordinated without an external gateway. In this model the current host agent is the declarative control plane, the actor kernel creates explicit participant Runs, and companion transports provide ingress or presence without owning hidden agent creation. The coordinator retains user authority, global context, decomposition, shared-surface ownership, integration, and final validation; participants own bounded concrete tasks and report evidence.
15
+
16
+ This resembles gateway orchestration in dependency direction but not in ownership: the coordinator is itself an agent instance with inspectable Runs, not an infrastructure service that implicitly creates sessions. Preserve that distinction in prompts, docs, recovery, and target routing.
17
+
18
+ Once work is delegated, keep the coordinator available for decisions and integration instead of duplicating participant implementation. Wait for terminal follow-up by default; use meaningful attention or evidence-based timers for overdue work rather than a tight inspection loop.
19
+
20
+ ## Reasoning allocation
21
+
22
+ Allocate reasoning by role instead of making one long thread implement and judge itself:
23
+
24
+ - Bounded implementation/authorship participants default to reasoning off when the task card fixes scope, invariants, checks, and escalation. Enable reasoning only when unresolved diagnosis or local design judgement is part of their assignment.
25
+ - Reviewers default to independent medium reasoning and clean context. For consequential work, several reviewers with distinct lenses or repeated independent judgement usually provide better error discovery than increasing one author's reasoning and relying on self-review.
26
+ - Synthesizers and integrators use medium reasoning because they reconcile evidence, conflicts, shared contracts, and retained state.
27
+ - The coordinator decides whether review fanout is worth its cost, preserves dissent, and never treats reviewer count as evidence quality by itself.
28
+
29
+ Do not change a running participant's profile merely because policy changed. Replace or add a later independent review only when fresh evidence is still needed.
30
+
12
31
  ## Choose the shape
13
32
 
14
33
  | Need | Shape | Primary Recipe |
@@ -29,18 +48,22 @@ The coordinator owns the whole result even when participants choose local implem
29
48
  1. State the goal, non-goals, evidence standard, integration owner, and stop condition.
30
49
  2. Partition work into disjoint read or write scopes. Give shared contracts one owner.
31
50
  3. Give each participant a bounded task card with allowed scope, avoided scope, expected artifact, checks, and escalation rule.
32
- 4. Preflight required model/tool access before expensive fanout.
33
- 5. Launch independent work without cross-contaminating lenses. Do not let participants silently expand scope.
34
- 6. Preserve every terminal result, including failures, disagreements, and partial evidence.
35
- 7. Merge through one named synthesizer or integrator. Resolve conflicts from explicit intent and invariants, not textual convenience.
36
- 8. Run fresh integrated validation and, for consequential outputs, an independent post-merge review.
37
- 9. Report complete, degraded, or insufficient-data status honestly; name residual owners and next actions.
51
+ 4. Assign each participant an explicit execution profile and isolation mode under the reasoning-allocation contract.
52
+ 5. Preflight required model/tool access before expensive fanout.
53
+ 6. Launch independent work without cross-contaminating lenses. Do not let participants silently expand scope.
54
+ 7. Preserve every terminal result, including failures, disagreements, and partial evidence; avoid doing participant work in the coordinator while a valid owner remains active.
55
+ 8. Merge through one named synthesizer or integrator. Resolve conflicts from explicit intent and invariants, not textual convenience.
56
+ 9. Run fresh integrated validation and, for consequential outputs, an independent post-merge review.
57
+ 10. Report complete, degraded, or insufficient-data status honestly; name residual owners and next actions.
38
58
 
39
59
  ## Scope and coordination rules
40
60
 
41
61
  - One writable scope has one owner. Parallel readers may share a stable target.
42
62
  - Public contracts, schemas, central configuration, and integration surfaces require exclusive ownership.
43
- - Participants record out-of-scope needs instead of opportunistically editing them.
63
+ - Concurrent writers use disjoint paths, isolated worktrees, or declared patch/artifact outputs.
64
+ - Shared ledgers, lockfiles, generated contracts, metadata, schemas, release surfaces, and cross-domain configuration belong to one named integrator unless a task card transfers one surface to another exclusive owner.
65
+ - Participants record shared-surface and other out-of-scope needs in handoff instead of editing them opportunistically.
66
+ - Reasoning and model profiles are task-card inputs, not implicit properties of the whole swarm.
44
67
  - Coordinator checkpoints are bounded decision requests, not free-form actor chat.
45
68
  - Locks support scope ownership but do not replace coordinator judgement. Every lock must be bounded and releasable.
46
69
  - One integrator owns merge order, conflict resolution, and final validation.
@@ -14,6 +14,39 @@ Use a development swarm only when all are true:
14
14
 
15
15
  Do not parallelize implementation when tasks need the same central files, semantic ordering dominates wall-clock time, or the likely conflicts would invalidate the decomposition. Use planning or review first.
16
16
 
17
+ ## Coordinator role separation
18
+
19
+ In a host-coordinator topology, the current Pi instance owns the declarative outcome and participant graph rather than acting as the default implementation worker. It may receive intent through Telegram or another companion extension, but transport does not become a gateway or gain hidden instance-creation authority; participant creation remains an explicit actor-kernel Run.
20
+
21
+ The coordinator should:
22
+
23
+ - Translate high-level intent into bounded task cards and dependency edges.
24
+ - Keep user authority, shared contracts, integration order, and final validation local.
25
+ - Remain available for checkpoints, permissions, conflicts, and changing evidence.
26
+ - Consume terminal handoffs, durable artifacts, and Trace attention instead of mirroring participant work.
27
+ - Check overdue work on an evidence-based timer; never replace event-driven completion with a rapid polling loop.
28
+
29
+ A participant should:
30
+
31
+ - Own one concrete execution or evidence boundary.
32
+ - Avoid global orchestration and undeclared participant creation.
33
+ - Return a bounded handoff that lets the coordinator decide without replaying the entire task.
34
+
35
+ Use one ordinary Run under `actors` when only one worker is delegated. Activate this development-swarm protocol when two or more participants, parallel ownership, or explicit integration edges exist. Keep trivial single-boundary work inline when delegation overhead has no compensating value.
36
+
37
+ ## Reasoning profiles
38
+
39
+ | Role | Default | Raise or fan out when |
40
+ | --- | --- | --- |
41
+ | Bounded implementation author | Reasoning off | The card explicitly owns unresolved diagnosis or design judgement |
42
+ | Reviewer | Medium reasoning, clean context | Stakes require independent lenses or repeated judges |
43
+ | Synthesizer / integrator | Medium reasoning | Evidence conflicts, shared contracts move, or merge order is semantic |
44
+ | Coordinator | Sufficient for decomposition and decisions | Scope, authority, or architecture remains unresolved |
45
+
46
+ Prefer independent review after implementation over asking one author thread to implement, retain all local assumptions, and then certify itself. When risk justifies the cost, use multiple independent reviewers: different lenses increase breadth, while repeated judges increase confidence. Preserve minority high-impact findings and merge only evidence-backed conclusions.
47
+
48
+ More reviewers are not automatically better. Do not fan out when they would inspect unstable code, share contaminated context, repeat one unsupported claim, or exceed the value of the decision. Never change an already-running participant solely to enforce a newer profile; add a fresh review boundary if evidence remains open.
49
+
17
50
  ## Decompose by ownership
18
51
 
19
52
  Prefer mutation-zone ownership over broad feature labels.
@@ -38,6 +71,9 @@ Goal:
38
71
  Non-goals:
39
72
  Allowed files or logical scope:
40
73
  Avoided files or shared contracts:
74
+ Execution profile:
75
+ Isolation mode: exclusive paths | isolated worktree | artifact-only
76
+ Shared surfaces reserved for integrator:
41
77
  Expected artifact or patch:
42
78
  Required evidence:
43
79
  Checks:
@@ -60,6 +96,14 @@ A useful task card names the smallest scope that can independently reach a valid
60
96
 
61
97
  If a participant discovers that another scope must change, it emits a dependency or conflict report and stops that edge. The coordinator either transfers ownership, serializes the work, or replans.
62
98
 
99
+ ## Isolation modes
100
+
101
+ - `Exclusive paths`: Writers share one worktree only when their complete writable path sets are disjoint and the shared baseline remains stable.
102
+ - `Isolated worktree`: Use when compilation, generated files, imports, or likely dependencies can touch shared repository state.
103
+ - `Artifact-only`: Use for reports, inventories, proposed patches, fixtures, or reviews that the integrator applies later.
104
+
105
+ The integrator exclusively owns `BACKLOG.md`, `CHANGELOG.md`, lockfiles, generated metadata, public schemas, release manifests, and cross-domain configuration by default. A task card may transfer one of these surfaces to another participant, but never create concurrent ownership. Authors report required shared-surface changes in handoff instead of applying them outside scope.
106
+
63
107
  ## Coordinator checkpoints
64
108
 
65
109
  A checkpoint preserves useful local context while requesting one decision:
@@ -129,13 +173,14 @@ The integrator resolves from both reports. Architecture conflicts stop affected
129
173
 
130
174
  The named integrator:
131
175
 
132
- 1. reads task cards, handoffs, dependency edges, and conflict reports;
133
- 2. verifies each result stayed within scope;
134
- 3. integrates in dependency order, one ownership edge at a time;
135
- 4. resolves conflicts while preserving stated invariants;
136
- 5. runs checks after risky edges and the full agreed validation at the end;
137
- 6. obtains fresh review for conflict-resolved or shared-contract changes;
138
- 7. reports integrated tasks, rejected or deferred work, checks, and residual risks.
176
+ 1. freezes new author mutations and preserves every terminal handoff before integration;
177
+ 2. reads task cards, handoffs, dependency edges, and conflict reports;
178
+ 3. verifies each result stayed within scope;
179
+ 4. integrates in dependency order, one ownership edge at a time;
180
+ 5. resolves conflicts while preserving stated invariants;
181
+ 6. runs checks after risky edges and the full agreed validation at the end;
182
+ 7. obtains fresh review for conflict-resolved or shared-contract changes;
183
+ 8. reports integrated tasks, rejected or deferred work, checks, and residual risks.
139
184
 
140
185
  Do not treat a clean merge, participant-local tests, or a collection of terminal Runs as integrated completion. Completion requires retained shared state plus coordinator-owned validation evidence.
141
186