pi-subagents 0.24.4 → 0.27.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 (48) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +145 -27
  3. package/package.json +1 -1
  4. package/prompts/parallel-context-build.md +3 -1
  5. package/prompts/parallel-handoff-plan.md +3 -1
  6. package/prompts/review-loop.md +1 -1
  7. package/skills/pi-subagents/SKILL.md +71 -20
  8. package/src/agents/agent-management.ts +57 -15
  9. package/src/agents/agent-serializer.ts +3 -2
  10. package/src/agents/agents.ts +47 -16
  11. package/src/agents/chain-serializer.ts +120 -0
  12. package/src/extension/fanout-child.ts +171 -0
  13. package/src/extension/index.ts +7 -2
  14. package/src/extension/schemas.ts +138 -5
  15. package/src/intercom/result-intercom.ts +108 -0
  16. package/src/runs/background/async-execution.ts +185 -10
  17. package/src/runs/background/async-job-tracker.ts +41 -6
  18. package/src/runs/background/async-resume.ts +28 -15
  19. package/src/runs/background/async-status.ts +71 -31
  20. package/src/runs/background/result-watcher.ts +111 -54
  21. package/src/runs/background/run-id-resolver.ts +83 -0
  22. package/src/runs/background/run-status.ts +89 -4
  23. package/src/runs/background/stale-run-reconciler.ts +46 -1
  24. package/src/runs/background/subagent-runner.ts +648 -42
  25. package/src/runs/foreground/chain-execution.ts +331 -118
  26. package/src/runs/foreground/execution.ts +226 -10
  27. package/src/runs/foreground/subagent-executor.ts +377 -14
  28. package/src/runs/shared/acceptance-contract.ts +291 -0
  29. package/src/runs/shared/acceptance-evaluation.ts +221 -0
  30. package/src/runs/shared/acceptance-finalization.ts +161 -0
  31. package/src/runs/shared/acceptance-reports.ts +127 -0
  32. package/src/runs/shared/acceptance.ts +22 -0
  33. package/src/runs/shared/chain-outputs.ts +101 -0
  34. package/src/runs/shared/completion-guard.ts +26 -3
  35. package/src/runs/shared/dynamic-fanout.ts +293 -0
  36. package/src/runs/shared/nested-events.ts +819 -0
  37. package/src/runs/shared/nested-path.ts +52 -0
  38. package/src/runs/shared/nested-render.ts +115 -0
  39. package/src/runs/shared/parallel-utils.ts +31 -1
  40. package/src/runs/shared/pi-args.ts +73 -5
  41. package/src/runs/shared/structured-output.ts +77 -0
  42. package/src/runs/shared/subagent-prompt-runtime.ts +77 -7
  43. package/src/runs/shared/workflow-graph.ts +206 -0
  44. package/src/shared/formatters.ts +2 -2
  45. package/src/shared/settings.ts +53 -4
  46. package/src/shared/types.ts +345 -0
  47. package/src/slash/slash-commands.ts +41 -3
  48. package/src/tui/render.ts +268 -43
package/CHANGELOG.md CHANGED
@@ -2,9 +2,38 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.27.0] - 2026-05-30
6
+
7
+ ### Changed
8
+ - Reworked public acceptance config to be object-only and evidence-driven, removing public `level`/disable shorthands. Explicit acceptance now triggers a same-session self-review/repair finalization loop, with `maxFinalizationTurns` controlling the cap.
9
+ - Documented goal-style acceptance guidance so `/goal`, “active goal”, and “work until evidence says done” requests map to run-scoped `acceptance` contracts.
10
+ - Refined acceptance finalization prompts and status output to emphasize evidence, blockers, stop rules, and finalization progress such as `completed after 1/3 turns`.
11
+
12
+ ### Fixed
13
+ - Treat explicit acceptance as the completion contract for acceptance-enabled runs, avoiding implementation completion-guard false positives when the visible output is only an `acceptance-report` or a finalization self-review turn does not need a repair edit.
14
+
15
+ ## [0.26.0] - 2026-05-29
16
+
17
+ ### Added
18
+ - Added first-wave acceptance gates with optional public `acceptance` config, inferred effective policies, structured child reports, provenance ledgers, checked evidence gates, explicit runtime verification commands, async/status persistence, and saved `.chain.json` validation.
19
+ - Added chain step metadata (`phase`, `label`), named outputs (`as` with `{outputs.name}`), workflow graph snapshots, and strict `outputSchema` structured-output contracts across foreground and async chain execution.
20
+ - Added dynamic chain fanout with `expand`/single-template `parallel`/`collect`, structured named-output sources, bounded item expansion, collected result outputs, async status graph persistence, and saved `.chain.json` support.
21
+
22
+ ### Fixed
23
+ - Fixed dynamic fanout acceptance blockers around real `structured_output` tool validation, malformed dynamic-like chain rejection, async dynamic failure status/details, dynamic child intercom target indexing, and saved `.chain.json` management diagnostics.
24
+ - Fixed acceptance-gate semantics so reviewed status requires an independent reviewer result, required criteria must be reported as satisfied, only fenced `acceptance-report` blocks satisfy attestation, malformed reports preserve parse errors, `{ level: "none", reason }` disables inferred gates, and zero-child dynamic aggregates no longer fabricate evidence.
25
+
26
+ ## [0.25.0] - 2026-05-21
27
+
5
28
  ### Added
29
+ - Allow child agents whose resolved builtin tools explicitly include `subagent` to run child-safe nested fanout, with parent-visible nested status trees and nested `status`/`interrupt`/`resume` by id.
6
30
 
7
31
  ### Fixed
32
+ - Preserve compact nested child summaries in grouped result/intercom payloads and async completion metadata before ordinary result files are processed and deleted.
33
+ - Keep async result files retryable when nested registry enrichment temporarily fails, instead of marking them seen before a successful delivery pass.
34
+ - Require an explicit id for child-safe nested `status` when no local foreground run is active, preventing fanout children from listing unrelated top-level async runs.
35
+ - Keep fanout child control inbox polling alive across transient filesystem errors, and retain control requests for retry when control-result writes fail.
36
+ - Share nested path/env sanitization between child launch arguments and nested event projection.
8
37
 
9
38
  ## [0.24.4] - 2026-05-20
10
39
 
package/README.md CHANGED
@@ -149,7 +149,7 @@ Foreground runs stream progress in the conversation while they run.
149
149
 
150
150
  Background runs keep working after control returns to you. Inspect active runs with `subagent({ action: "status" })`, or a specific run with `subagent({ action: "status", id: "..." })`.
151
151
 
152
- They also show a compact async widget and send completion notifications. Parallel background runs show per-agent progress instead of fake chain steps. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones.
152
+ They also show a compact async widget and send completion notifications. Parallel background runs show per-agent progress instead of fake chain steps. Chains with parallel groups keep their grouped shape in progress and results, so failed or paused agents stay visible next to completed ones. When a child is explicitly allowed to fan out with `tools: subagent`, its nested runs appear under that parent child in the main status tree instead of being hidden inside the child process.
153
153
 
154
154
  You can also ask naturally:
155
155
 
@@ -181,7 +181,7 @@ Use the optional prompt shortcuts below when you want the pattern to be repeatab
181
181
 
182
182
  Packaged `planner`, `worker`, and `oracle` default to forked context when a launch omits `context`; pass `context: "fresh"` when you intentionally want a fresh child run.
183
183
 
184
- Child-safety boundaries are enforced at runtime. Spawned child sessions do not register the `subagent` tool, do not receive the bundled `pi-subagents` skill, and receive explicit boundary instructions that they are not the parent orchestrator and must not propose or run subagents. Forked child context filtering also removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results.
184
+ Child-safety boundaries are enforced at runtime. Spawned child sessions do not receive the bundled `pi-subagents` skill, and forked child context filtering removes parent-only subagent artifacts (including old hidden orchestration-instruction messages, slash/status/control messages, and prior parent `subagent` tool-call/tool-result history) while preserving ordinary prose and unrelated tool calls/results. By default, children do not register the `subagent` tool and receive boundary instructions that they are not the parent orchestrator and must not propose or run subagents. The explicit exception is an agent whose resolved builtin `tools` includes `subagent`; that child gets a child-safe `subagent` tool for the fanout work the parent assigned, still bounded by `maxSubagentDepth`.
185
185
 
186
186
  ## Optional shortcuts
187
187
 
@@ -223,7 +223,7 @@ The child can use one dedicated coordination tool:
223
223
 
224
224
  - `contact_supervisor`: the child contacts the parent/supervisor session that delegated the task. Use `reason: "need_decision"` for blocking decisions or clarification, and `reason: "progress_update"` for short non-blocking updates when a discovery changes the plan. Do not ask for clarification when the only conflict is review-only/no-edit versus progress-writing or artifact-writing instructions; no-edit wins.
225
225
 
226
- Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets and full child summaries.
226
+ Child-side routine completion handoffs are still not expected. With the intercom bridge active, parent-side `pi-subagents` sends grouped completion results through `pi-intercom`: one grouped message per foreground parent `subagent` run and one per completed async result file. Acknowledged foreground delivery returns a compact receipt with artifact/session paths; if unacknowledged, the normal full output is preserved. Grouped messages include child intercom targets, full child summaries, and compact nested child summaries under the parent child that launched them.
227
227
 
228
228
  If a child appears stalled, needs-attention notices can show up in the parent session with useful next actions, such as checking `subagent({ action: "status" })`, interrupting the run, or nudging the child.
229
229
 
@@ -246,7 +246,7 @@ Skip this section until you want exact syntax.
246
246
  | `/run <agent> [task]` | Run one agent; omit the task for self-contained agents |
247
247
  | `/chain agent1 "task1" -> agent2 "task2"` | Run agents in sequence |
248
248
  | `/parallel agent1 "task1" -> agent2 "task2"` | Run agents in parallel |
249
- | `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` workflow |
249
+ | `/run-chain <chainName> -- <task>` | Launch a saved `.chain.md` or `.chain.json` workflow |
250
250
  | `/subagents-doctor` | Show read-only setup diagnostics |
251
251
 
252
252
  Commands validate agent names locally, support tab completion, and send results back into the conversation.
@@ -472,8 +472,9 @@ Examples:
472
472
  - `tools` omitted and `extensions` omitted: normal builtins and normal extensions.
473
473
  - `tools: mcp:chrome-devtools`: normal builtins plus direct Chrome DevTools MCP tools.
474
474
  - `tools: read, bash, mcp:chrome-devtools`: only `read` and `bash` as builtins, plus direct Chrome DevTools MCP tools.
475
+ - `tools: subagent, read`: a child-safe `subagent` tool is available inside that child so it can run explicitly assigned nested fanout.
475
476
 
476
- Direct MCP tools require [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter). Subagents only receive direct MCP tools when `mcp:` entries are listed in their frontmatter; global `directTools: true` in `mcp.json` is not enough by itself. The generic `mcp` proxy tool can still be used for discovery when available. The adapter caches tool metadata at startup, so after connecting a new MCP server for the first time, restart Pi before relying on direct tools.
477
+ Direct MCP tools require [pi-mcp-adapter](https://github.com/nicobailon/pi-mcp-adapter). Subagents only receive direct MCP tools when `mcp:` entries are listed in their frontmatter; global `directTools: true` in `mcp.json` is not enough by itself. The generic `mcp` proxy tool can still be used for discovery when available. The adapter caches tool metadata at startup, so after connecting a new MCP server for the first time, restart Pi before relying on direct tools. An `mcp:` entry named `subagent` does not authorize nested fanout; only the builtin `subagent` tool name does.
477
478
 
478
479
  `extensions` controls child extension loading:
479
480
 
@@ -491,14 +492,14 @@ When `extensions` is present, it takes precedence over extension paths implied b
491
492
 
492
493
  ## Chain files
493
494
 
494
- Chains are reusable `.chain.md` workflows stored separately from agent files.
495
+ Chains are reusable workflows stored separately from agent files. Use `.chain.md` for simple sequential saved chains. Use `.chain.json` when a chain needs dynamic fanout.
495
496
 
496
497
  | Scope | Path |
497
498
  |-------|------|
498
- | User | `~/.pi/agent/chains/**/*.chain.md` |
499
- | Project | `.pi/chains/**/*.chain.md` |
499
+ | User | `~/.pi/agent/chains/**/*.chain.md`, `~/.pi/agent/chains/**/*.chain.json` |
500
+ | Project | `.pi/chains/**/*.chain.md`, `.pi/chains/**/*.chain.json` |
500
501
 
501
- Nested subdirectories are discovered recursively. If user and project scopes define the same parsed runtime chain name, the project chain wins. Chains support the same optional `package` frontmatter as agents; `name: review-flow` plus `package: code-analysis` runs as `code-analysis.review-flow`.
502
+ Nested subdirectories are discovered recursively. If both `.chain.md` and `.chain.json` define the same parsed runtime chain name in the same scope, `.chain.json` wins. If user and project scopes define the same parsed runtime chain name, the project chain wins. Chains support the same optional `package` frontmatter as agents; `name: review-flow` plus `package: code-analysis` runs as `code-analysis.review-flow`.
502
503
 
503
504
  Example:
504
505
 
@@ -509,23 +510,67 @@ description: Gather context then plan implementation
509
510
  ---
510
511
 
511
512
  ## scout
513
+ phase: Context
514
+ label: Map auth flow
515
+ as: context
512
516
  output: context.md
513
517
 
514
518
  Analyze the codebase for {task}
515
519
 
516
520
  ## planner
521
+ phase: Planning
522
+ label: Implementation plan
517
523
  reads: context.md
518
524
  model: anthropic/claude-sonnet-4-5:high
519
525
  progress: true
520
526
 
521
- Create an implementation plan based on {previous}
527
+ Create an implementation plan based on {outputs.context}
522
528
  ```
523
529
 
524
- Each `## agent-name` section is a step. Config lines such as `output`, `outputMode`, `reads`, `model`, `skills`, and `progress` go immediately after the header. A blank line separates config from task text.
530
+ Each `.chain.md` `## agent-name` section is a step. Config lines such as `phase`, `label`, `as`, `outputSchema`, `output`, `outputMode`, `reads`, `model`, `skills`, and `progress` go immediately after the header. A blank line separates config from task text. In saved `.chain.md` files, `outputSchema` is a path to a JSON Schema file; direct tool calls and `.chain.json` files can pass the schema object inline.
525
531
 
526
532
  For `output`, `reads`, `skills`, and `progress`, chain behavior is three-state: omitted inherits from the agent, a value overrides, and `false` disables.
527
533
 
528
- Create chains by writing `.chain.md` files directly or with the `subagent({ action: "create", config: ... })` management action. Run them with natural language or:
534
+ Use `phase` to group related work in status output, `label` for a readable step name, and `as` to store a successful step or parallel task result for later `{outputs.name}` references. Duplicate `as` names, invalid identifiers, and unknown output references fail before child execution.
535
+
536
+ Dynamic fanout is available only through direct `subagent({ chain: [...] })` JSON or saved `.chain.json` files. It expands an array from a prior structured named output, runs one child template per item, and stores the ordered collection under `collect.as`. The source must be structured output; prose is never parsed. `expand.maxItems` is required, over-limit arrays fail, nested fanout and arbitrary expressions are not supported, and `.chain.md` has no dynamic syntax in this release.
537
+
538
+ ```json
539
+ {
540
+ "name": "dynamic-review",
541
+ "description": "Find review targets, fan out reviewers, then synthesize.",
542
+ "chain": [
543
+ {
544
+ "agent": "scout",
545
+ "task": "Return {\"items\":[{\"path\":\"...\",\"reason\":\"...\"}]} via structured_output.",
546
+ "as": "targets",
547
+ "outputSchema": { "type": "object" }
548
+ },
549
+ {
550
+ "expand": {
551
+ "from": { "output": "targets", "path": "/items" },
552
+ "item": "target",
553
+ "key": "/path",
554
+ "maxItems": 12
555
+ },
556
+ "parallel": {
557
+ "agent": "reviewer",
558
+ "label": "Review {target.path}",
559
+ "task": "Review {target.path}. Reason: {target.reason}",
560
+ "outputSchema": { "type": "object" }
561
+ },
562
+ "collect": { "as": "reviews" },
563
+ "concurrency": 4
564
+ },
565
+ {
566
+ "agent": "worker",
567
+ "task": "Synthesize fixes from {outputs.reviews}"
568
+ }
569
+ ]
570
+ }
571
+ ```
572
+
573
+ Create simple `.chain.md` chains by writing files directly or with the `subagent({ action: "create", config: ... })` management action. Create dynamic `.chain.json` chains by writing the JSON file directly. Run saved chains with natural language or:
529
574
 
530
575
  ```text
531
576
  /run-chain scout-planner -- refactor authentication
@@ -540,6 +585,7 @@ Task templates support:
540
585
  | `{task}` | Original task from the first step. |
541
586
  | `{previous}` | Output from the prior step, or aggregated output from a parallel step. |
542
587
  | `{chain_dir}` | Path to the chain artifact directory. |
588
+ | `{outputs.name}` | Text value from a prior step or completed parallel task with `as: "name"`. |
543
589
 
544
590
  Parallel outputs are aggregated with clear separators before being passed to the next step:
545
591
 
@@ -593,7 +639,7 @@ What the bundled skill covers:
593
639
  - **Delegation patterns**: when to launch which agent, whether to use single, parallel, chain, or async mode, and whether to use fresh or forked context
594
640
  - **Prompt workflow recipes**: how to apply the packaged techniques directly with `subagent(...)` when the user describes the workflow in natural language instead of invoking a slash command. This includes parallel review, review-loop, parallel research, parallel context-build, parallel handoff-plan, gather-context-and-clarify, and parallel cleanup
595
641
  - **Role-agent prompting guidance**: compact contract prompts instead of long scripts, what to include in role-specific meta prompts, and retrieval budgets for researchers
596
- - **Safety boundaries**: child agents must not run subagents, must not invent intercom targets, and must escalate unapproved decisions
642
+ - **Safety boundaries**: child agents must not run subagents unless their resolved builtin tools explicitly include `subagent`, must not invent intercom targets, and must escalate unapproved decisions
597
643
  - **Intercom conventions**: when to ask vs send, and how parent-side result delivery works with `pi-intercom`
598
644
  - **Control and diagnostics**: attention signals, soft interrupts, status, and the `doctor` action
599
645
 
@@ -633,14 +679,49 @@ These are the parameters the LLM passes when it calls the `subagent` tool. Most
633
679
 
634
680
  // Chain with fan-out/fan-in
635
681
  { chain: [
636
- { agent: "scout", task: "Gather context" },
682
+ { agent: "scout", task: "Gather context", phase: "Context", label: "Map code", as: "context" },
637
683
  { parallel: [
638
- { agent: "worker", task: "Implement feature A from {previous}" },
639
- { agent: "worker", task: "Implement feature B from {previous}" }
684
+ { agent: "worker", task: "Implement feature A from {outputs.context}", label: "Feature A", as: "featureA" },
685
+ { agent: "worker", task: "Implement feature B from {outputs.context}", label: "Feature B", as: "featureB" }
640
686
  ], concurrency: 2, failFast: true },
641
- { agent: "reviewer", task: "Review all changes from {previous}" }
687
+ { agent: "reviewer", task: "Review {outputs.featureA} and {outputs.featureB}" }
642
688
  ]}
643
689
 
690
+ // Dynamic fanout from structured output
691
+ { chain: [
692
+ {
693
+ agent: "scout",
694
+ task: "Return review targets as structured_output: { items: [{ path, reason }] }",
695
+ as: "targets",
696
+ outputSchema: { type: "object" }
697
+ },
698
+ {
699
+ expand: { from: { output: "targets", path: "/items" }, item: "target", key: "/path", maxItems: 12 },
700
+ parallel: { agent: "reviewer", task: "Review {target.path}. Reason: {target.reason}", outputSchema: { type: "object" } },
701
+ collect: { as: "reviews" },
702
+ concurrency: 4
703
+ },
704
+ { agent: "worker", task: "Synthesize fixes from {outputs.reviews}" }
705
+ ] }
706
+
707
+ // Strict structured output for reliable handoff data
708
+ { chain: [
709
+ {
710
+ agent: "scout",
711
+ task: "Return the key files and risks for {task}",
712
+ as: "scan",
713
+ outputSchema: {
714
+ type: "object",
715
+ required: ["files", "risks"],
716
+ properties: {
717
+ files: { type: "array", items: { type: "string" } },
718
+ risks: { type: "array", items: { type: "string" } }
719
+ }
720
+ }
721
+ },
722
+ { agent: "planner", task: "Plan from this scan: {outputs.scan}" }
723
+ ] }
724
+
644
725
  // Worktree isolation
645
726
  { tasks: [
646
727
  { agent: "worker", task: "Implement auth" },
@@ -710,10 +791,10 @@ Agent definitions are not loaded into context by default. Management actions let
710
791
  | `outputMode` | `"inline" \| "file-only"` | `inline` | Return saved output inline or as a concise saved-file reference. `file-only` requires an `output` path. |
711
792
  | `skill` | `string \| string[] \| false` | agent default | Override skills or disable all. |
712
793
  | `model` | string | agent default | Override model. |
713
- | `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. |
794
+ | `tasks` | array | - | Top-level parallel tasks. Supports `agent`, `task`, `cwd`, `count`, `output`, `outputMode`, `reads`, `progress`, `skill`, `model`, and `acceptance`. |
714
795
  | `concurrency` | number | config or `4` | Top-level parallel concurrency. |
715
796
  | `worktree` | boolean | false | Create isolated git worktrees for parallel tasks. |
716
- | `chain` | array | - | Sequential and parallel chain steps. |
797
+ | `chain` | array | - | Sequential, static parallel, and dynamic fanout chain steps. Sequential steps and parallel child tasks support `phase`, `label`, `as`, `outputSchema`, and `acceptance` in addition to the usual execution fields. Dynamic fanout uses `expand`, one child `parallel` template, and `collect`; group-level acceptance is not supported because there is no child session to finalize. |
717
798
  | `context` | `fresh \| fork` | agent default or `fresh` | `fork` creates real branched sessions from the parent leaf. Packaged `planner`, `worker`, and `oracle` default to `fork`. |
718
799
  | `chainDir` | string | temp chain dir | Persistent directory for chain artifacts. |
719
800
  | `clarify` | boolean | true for chains | Show TUI preview/edit flow. |
@@ -725,25 +806,31 @@ Agent definitions are not loaded into context by default. Management actions let
725
806
  | `includeProgress` | boolean | false | Include full progress in result. |
726
807
  | `share` | boolean | false | Upload session export to GitHub Gist. |
727
808
  | `sessionDir` | string | derived | Override session log directory. |
809
+ | `acceptance` | object | omitted | Explicit acceptance contract. When present, the child gets a structured contract, then the runtime continues the same session for a bounded self-review/repair loop before evaluating acceptance. |
728
810
 
729
811
  `context: "fork"` fails fast when the parent session is not persisted, the current leaf is missing, or the branched child session cannot be created. It never silently downgrades to `fresh`. In multi-agent runs, if any requested agent has `defaultContext: fork` and the launch omits `context`, the whole invocation uses forked context; pass `context: "fresh"` when you intentionally want a fresh run.
730
812
 
731
813
  Use `outputMode: "file-only"` when a saved output may be large and the parent only needs a pointer. The returned text is a compact reference like `Output saved to: /abs/report.md (48.2 KB, 2847 lines). Read this file if needed.` Failed runs and save errors still return normal inline output for debugging. In chains, later `{previous}` steps receive the same compact reference when the prior step used file-only mode.
732
814
 
733
- Sequential and parallel chain tasks accept `agent`, `task`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`.
815
+ Sequential and parallel chain tasks accept `agent`, `task`, `phase`, `label`, `as`, `outputSchema`, `cwd`, `output`, `outputMode`, `reads`, `progress`, `skill`, and `model`. Parallel tasks also accept `count`. Parallel step groups accept `parallel`, `concurrency`, `failFast`, and `worktree`. If `outputSchema` is present, the child must call `structured_output` with schema-valid JSON; prose-only completion or invalid JSON fails the step. Validated structured values are preserved on the step result, and `as` also exposes a compact text representation through `{outputs.name}`.
734
816
 
735
817
  Status and control actions:
736
818
 
737
819
  ```ts
738
820
  subagent({ action: "status" })
739
821
  subagent({ action: "status", id: "<run-id>" })
822
+ subagent({ action: "status", id: "<nested-run-id>" })
740
823
  subagent({ action: "interrupt", id: "<run-id>" })
824
+ subagent({ action: "interrupt", id: "<nested-run-id>" })
741
825
  subagent({ action: "resume", id: "<run-id>", message: "follow-up question" })
742
826
  subagent({ action: "resume", id: "<run-id>", index: 1, message: "follow-up for child 2" })
827
+ subagent({ action: "resume", id: "<nested-run-id>", message: "follow-up for a nested child" })
743
828
  subagent({ action: "doctor" })
744
829
  ```
745
830
 
746
- `resume` sends the follow-up directly when an async child is still reachable over intercom. After completion, it revives the child by starting a new async child from the stored child session file. Multi-child async runs and remembered foreground single, parallel, or chain runs can be revived by passing `index` to choose the child. Revive starts a new child process from the old session context; it does not restart the same OS process, and it requires the chosen child to have a persisted `.jsonl` session file.
831
+ `status` resolves exact foreground ids, top-level async ids, and nested run ids before falling back to prefix matching. Nested status shows the root/parent path, nested children, session/artifact paths when known, and nested control commands. Inside child-safe fanout mode, bare `status` requires an id when no local foreground run is active, so children cannot enumerate unrelated top-level async runs. Bare `interrupt` still targets only the visible top-level run; interrupting a nested run requires its explicit nested id.
832
+
833
+ `resume` sends the follow-up directly when an async child is still reachable over intercom. After completion, it revives the child by starting a new async child from the stored child session file. Multi-child async runs and remembered foreground single, parallel, or chain runs can be revived by passing `index` to choose the child. Nested runs can be resumed by nested id when their live route or persisted session metadata is available. Revive starts a new child process from the old session context; it does not restart the same OS process, and it requires the chosen child to have a persisted `.jsonl` session file.
747
834
 
748
835
  ## Worktree isolation
749
836
 
@@ -822,7 +909,7 @@ Session directory precedence is: `params.sessionDir`, then `config.defaultSessio
822
909
  { "maxSubagentDepth": 1 }
823
910
  ```
824
911
 
825
- Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent’s child runs, but cannot relax an inherited stricter limit.
912
+ Controls nested delegation when no inherited `PI_SUBAGENT_MAX_DEPTH` is already in effect. Per-agent `maxSubagentDepth` can tighten the limit for that agent’s child runs, but cannot relax an inherited stricter limit. This applies even to children that explicitly declare `tools: subagent`; at the cap, execution fanout is blocked instead of silently hiding nested work.
826
913
 
827
914
  ### `intercomBridge`
828
915
 
@@ -898,15 +985,46 @@ Async runs write:
898
985
  subagent-log-<id>.md
899
986
  ```
900
987
 
901
- `status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
988
+ `status.json` powers the widget and `subagent({ action: "status" })` output. `events.jsonl` contains wrapper events plus child Pi JSON events annotated with run and step metadata. Nested fanout status is stored as compact sidecar event/registry metadata and merged into parent status views and result/intercom payloads; full recursive status snapshots are not embedded in parent result files. `output-<n>.log` is a live human-readable tail. Fallback information is persisted so background runs are debuggable after completion.
989
+
990
+ ## Acceptance Gates
991
+
992
+ `acceptance` is an explicit contract. Omit it for lightweight runs. Set it on single runs, top-level parallel task items, sequential chain steps, static parallel task items, and dynamic fanout child templates when the child must prove the work meets concrete criteria. Do not set it on static parallel groups or dynamic fanout aggregate groups; those groups do not own a same-session child turn.
993
+
994
+ If you are coming from Codex Goals, `acceptance` is the subagent equivalent for one delegated run. When a user says `/goal`, “goal”, “active goal”, “continue until evidence says done”, or “verify against a goal”, translate that into an acceptance contract: `criteria` are the target, `evidence` and `verify` are proof, `stopRules` are constraints, and `maxFinalizationTurns` is the bounded loop budget.
995
+
996
+ ```ts
997
+ {
998
+ agent: "worker",
999
+ task: "Implement the fix",
1000
+ acceptance: {
1001
+ criteria: ["Patch the bug without widening scope"],
1002
+ evidence: ["changed-files", "tests-added", "commands-run", "residual-risks", "no-staged-files"],
1003
+ verify: [{ id: "focused", command: "npm test", timeoutMs: 120000 }],
1004
+ maxFinalizationTurns: 3
1005
+ }
1006
+ }
1007
+ ```
1008
+
1009
+ When `acceptance` is present, the initial child prompt includes a standardized acceptance section and asks for a fenced `acceptance-report` JSON block. After the child’s initial completion, the runtime continues the same persisted child session with an acceptance finalization prompt. The child can repair omissions in that same session, then must return the final `acceptance-report`. Missing or malformed finalization reports reject the run when the loop limit is reached.
1010
+
1011
+ Public acceptance config is evidence-driven. There is no public `level` field and no `acceptance: "checked"` shorthand. Runtime provenance is derived from what actually happened:
1012
+
1013
+ - `attested`: the child returned a structured acceptance report.
1014
+ - `checked`: runtime structural checks passed, such as required criteria, required evidence, and no staged files.
1015
+ - `verified`: configured runtime verification commands passed. Child-reported command success does not count.
1016
+ - `reviewed`: an independent reviewer result is present.
1017
+ - `rejected`: attestation, structural checks, verification, review, or finalization failed.
1018
+
1019
+ Self-review finalization never counts as `reviewed`, and it never counts as `verified` unless configured runtime verification commands actually pass. The visible child output remains the initial answer; finalization reports and residual risks are stored in the acceptance ledger and async/status details.
902
1020
 
903
1021
  ## Live progress
904
1022
 
905
- Foreground runs show compact live progress for single, chain, and parallel modes: current tool, recent output, token counts, duration, activity freshness, and current-tool duration.
1023
+ Foreground runs show compact live progress for single, chain, and parallel modes: current tool, recent output, token counts, duration, activity freshness, current-tool duration, and chain graph metadata when available.
906
1024
 
907
1025
  Press `Ctrl+O` to expand the full streaming view with complete output per step.
908
1026
 
909
- Sequential chains show a flow line like `done scout → running planner`. Chains with parallel steps show per-step cards instead.
1027
+ Sequential chains show a flow line like `done scout → running planner`. Chains with parallel steps show per-step cards instead. Chain status uses `label` and `phase` metadata when present, while falling back to agent names for older chains.
910
1028
 
911
1029
  ## Session sharing
912
1030
 
@@ -920,9 +1038,9 @@ This is disabled by default. Session data may contain source code, paths, enviro
920
1038
 
921
1039
  ## Recursion guard
922
1040
 
923
- Subagents can call `subagent`, which can get expensive and hard to observe. A depth guard prevents unbounded nesting.
1041
+ Subagents can call `subagent` only when their resolved builtin tools explicitly include `subagent`. That is meant for delegated fanout agents, not ordinary worker/reviewer children. A depth guard prevents unbounded nesting.
924
1042
 
925
- By default, nesting is limited to two levels: main session → subagent → sub-subagent. Deeper calls are blocked with guidance to complete the current task directly.
1043
+ By default, nesting is limited to two levels: main session → subagent → sub-subagent. Deeper calls are blocked with guidance to complete the current task directly. Nested runs appear in the parent status widget and `status` output as a tree, and `status`, `interrupt`, and `resume` can target a nested run by its id.
926
1044
 
927
1045
  Configure the limit with:
928
1046
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-subagents",
3
- "version": "0.24.4",
3
+ "version": "0.27.0",
4
4
  "description": "Pi extension for delegating tasks to subagents with chains, parallel execution, and TUI clarification",
5
5
  "author": "Nico Bailon",
6
6
  "license": "MIT",
@@ -4,12 +4,14 @@ description: Parallel context builders for planning handoff
4
4
 
5
5
  Launch fresh-context `context-builder` subagents in parallel to build grounded handoff context for planning or implementation.
6
6
 
7
- Use the `subagent` tool in chain mode with a single parallel step, not top-level parallel tasks, so relative output files live under the temporary chain directory. Use `context: "fresh"` unless I explicitly ask for forked context. Give every parallel task a distinct `output` path, for example:
7
+ Use the `subagent` tool in chain mode with a single parallel step, not top-level parallel tasks, so relative output files live under the temporary chain directory. Use `context: "fresh"` unless I explicitly ask for forked context. Give every parallel task a distinct `output` path, `label`, and `as` name, for example:
8
8
 
9
9
  - `context-build/request-and-scope.md`
10
10
  - `context-build/codebase-and-patterns.md`
11
11
  - `context-build/validation-and-risks.md`
12
12
 
13
+ Use one phase such as `phase: "Context build"` for the parallel tasks so async status is readable. A later synthesis step can reference specific outputs with `{outputs.requestScope}`, `{outputs.codebasePatterns}`, and `{outputs.validationRisks}` instead of relying only on `{previous}`.
14
+
13
15
  Do not write these context artifacts into the repository unless I explicitly ask for persistent files.
14
16
 
15
17
  Treat the slash command arguments as the primary request, target, or focus:
@@ -19,12 +19,14 @@ Use the `subagent` tool in chain mode:
19
19
 
20
20
  2. Second step: a synthesis `context-builder` that reads the parallel findings and writes the final handoff plan and meta-prompt.
21
21
 
22
- Use distinct output paths under the chain directory. Example outputs:
22
+ Use distinct output paths, `label` values, and `as` names under the chain directory. Example outputs:
23
23
  - `handoff/external-reference.md`
24
24
  - `handoff/local-context.md`
25
25
  - `handoff/implementation-strategy.md`
26
26
  - `handoff/final-handoff-plan.md`
27
27
 
28
+ Use phases such as `Research`, `Local context`, and `Synthesis` so async status is readable. Prefer `{outputs.externalReference}`, `{outputs.localContext}`, and `{outputs.implementationStrategy}` in the synthesis task when those specific inputs are available; keep `{previous}` only when the whole parallel fan-in summary is the desired input.
29
+
28
30
  Do not write these artifacts into the repository unless I explicitly ask for persistent files.
29
31
 
30
32
  Role guidance:
@@ -4,7 +4,7 @@ description: Review/fix loop until clean
4
4
 
5
5
  Run a parent-orchestrated review loop for the requested work.
6
6
 
7
- Use the `subagent` tool. Keep the parent session as the loop controller and final decision-maker. Child subagents must receive concrete role-specific tasks; they must not run subagents or manage the loop themselves.
7
+ Use the `subagent` tool. Keep the parent session as the loop controller and final decision-maker. Child subagents must receive concrete role-specific tasks; they must not run subagents or manage the loop themselves unless the parent intentionally selected an explicit fanout agent whose builtin `tools` includes `subagent` for that assigned fanout.
8
8
 
9
9
  Default to a maximum of 3 review rounds unless I specify a different cap. Count a review round each time fresh-context reviewers inspect the current diff after a worker pass. Stop early when reviewers find no blockers or fixes worth doing now.
10
10