@henryqw/pi-subagent 15.1.1 → 15.1.3

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/README.md CHANGED
@@ -80,6 +80,19 @@ See the [orchestration guide](./docs/orchestration.md) for full delegation, tran
80
80
 
81
81
  The bundled [`pi-subagent-delegated-development`](./skills/pi-subagent-delegated-development/SKILL.md) Skill guides Main's planning and orchestration. It adds no runtime code, config, or Role installation.
82
82
 
83
+ Implementers remove only task-created temporary, generated, or ignored artifacts. Required deliverables and unrelated files stay intact. They never use `git clean` or blanket deletion, and unclear paths block.
84
+
85
+ For known regressions with a runner that supports test-name filtering, use a test-name filter. Keep broad package or workspace checks to one caller-owned final validation after relevant units integrate. Flow itself does not run that check.
86
+
87
+ Before delegating:
88
+
89
+ - Find concrete outcomes that can ship on their own.
90
+ - Split only those outcomes. Give each one owner and a focused check.
91
+ - Run independent work in parallel.
92
+ - Prefer parallel delegation when at least two outcomes are independent.
93
+ - For naturally multi-part work, roughly three to five useful units can help.
94
+ - This is a guide, not a quota. Never create units just to reach it.
95
+
83
96
  Its ordinary review loop is optional. Use it only when the caller or repository policy explicitly requires judgment review.
84
97
 
85
98
  - Call `delegate_task` with `role: "reviewer"` to select the effective `reviewer` Role.
@@ -92,7 +105,9 @@ Flow is separate. It owns exact review evidence, exact `PASS` approval, validati
92
105
 
93
106
  ## Flow
94
107
 
95
- Flow requires a clean Main worktree on an attached branch with a committed `HEAD`. Use it only for independent Git changes that can merge in any order. Do not split units that overlap files, APIs, schemas, generated output, package metadata, lockfiles, or invariants.
108
+ Flow requires a clean Main worktree on an attached branch with a committed `HEAD`. Use it only for independent Git changes that can merge in any order.
109
+
110
+ Keep work together or run it in order when a split divides an invariant or adds coordination. Do not split units with overlapping mutable ownership. Do not split units that overlap files, APIs, schemas, generated output, package metadata, lockfiles, or invariants.
96
111
 
97
112
  One Implementer launch must plausibly finish before the configured maximum runtime. Cohesion is not enough when work has several preservable, separately verifiable milestones. Split oversized dependent work into serial one-unit Flows after each milestone integrates. Units in one Flow stay independent and commuting.
98
113
 
@@ -110,12 +110,12 @@ Flow has no dependency graph, saved state, automatic retry, aggregate review, or
110
110
 
111
111
  ## Per-delegation resources and isolation
112
112
 
113
- For `delegate_task`, every single entry, parallel sibling, and chain step independently:
113
+ `delegate_task` first preflights every requested Role name, so an initially unknown Role starts no sibling. Then, after receiving an executor permit, every single entry, parallel sibling, and chain step independently:
114
114
 
115
- 1. loads its selected Role;
116
- 2. resolves its route and named Skills from the latest effective Pi context after receiving an executor permit;
115
+ 1. reloads its effective Role by requested name;
116
+ 2. resolves its route and named Skills from the latest effective Pi context;
117
117
  3. creates its Role launch policy; and
118
- 4. when the Role requests `isolation: worktree`, creates a worktree identified by the tool call, mode, and input index.
118
+ 4. when the reloaded Role requests `isolation: worktree`, creates a worktree identified by the tool call, mode, and input index.
119
119
 
120
120
  Separate deterministic identities produce separate worktree paths and branches. Parallel siblings cannot collide, and a chain does not base one step's worktree on the preceding step's branch. `{previous}` passes text only. There is no implicit shared worktree or hidden workflow state.
121
121
 
@@ -16,7 +16,7 @@ isolation: worktree
16
16
 
17
17
  Implement the bounded outcome, not a preassigned file list. Work in the assigned cwd. Read applicable repository instructions and domain context first; inspect the relevant flow, callers, and tests before editing. Preserve unrelated work. Fix the root cause with the smallest complete diff, reusing existing patterns and dependencies. Do not add speculative work. Stop when the outcome is complete or blocked.
18
18
 
19
- For ordinary delegation, run focused validation needed to establish correctness. For Flow, the declared validation gate is authoritative: run only narrow development checks while implementing and do not duplicate that final gate.
19
+ For ordinary delegation, run focused validation needed to establish correctness. For Flow, the declared validation gate is authoritative: run only narrow development checks while implementing and do not duplicate that final gate. Before reporting ordinary or Flow completion, remove only task-created non-deliverable temporary, generated, or ignored artifacts. Preserve required deliverables, unrelated files, pre-existing files, and user data. Never use `git clean` or blanket deletion. If a path's ownership or necessity is uncertain, report its exact path as a blocker.
20
20
 
21
21
  Do not access credentials, use the network, generate artifacts, or broaden scope unless the task explicitly requires it. Never invoke external LLM APIs, SDKs, agent harnesses, or model CLIs.
22
22
 
@@ -550,7 +550,7 @@ export function registerDelegateFlow(pi: ExtensionAPI, runtime: DelegateFlowRunt
550
550
  const tip = oid(tipResult.stdout, "Unit HEAD");
551
551
  const branchTip = oid(await requireGit(["rev-parse", "--verify", `refs/heads/${unit.worktree.branch}^{commit}`], unit.worktree.cwd, signal), "Unit branch tip");
552
552
  if (tip !== branchTip) return { block: `Unit ${JSON.stringify(unit.request.id)} branch no longer names its checked-out HEAD.` };
553
- const status = await requireGit(["status", "--porcelain=v1", "--untracked-files=all"], unit.worktree.cwd, signal);
553
+ const status = await requireGit(["status", "--porcelain=v1", "--untracked-files=all", "--ignore-submodules=none"], unit.worktree.cwd, signal);
554
554
  if (status) return { block: `Unit Worktree is dirty:\n${capOutput(status)}` };
555
555
  const flags = await inspectIndexFlags(unit.worktree.cwd, git, signal);
556
556
  if (flags.failure) throw new Error(`Unit index inspection failed: ${flags.failure}`);
@@ -770,7 +770,7 @@ export function registerDelegateFlow(pi: ExtensionAPI, runtime: DelegateFlowRunt
770
770
  description: "Run 1–8 independent Implementers in isolated Unit Worktrees, validate and serially fast-forward each tip, with exact review only for units that declare a judgment criterion.",
771
771
  promptSnippet: "Run a deterministic parallel-implementation, serial-verification Flow",
772
772
  promptGuidelines: [
773
- "Use delegate_flow only for cohesive units expected to commute: split independent outcomes into units, sequence dependent work outside delegate_flow, and never divide one invariant across multiple units. Combine work that overlaps files, APIs, schemas, generated output, package metadata, lockfiles, or invariants.",
773
+ "Use delegate_flow only for cohesive units expected to commute: make independent commuting outcomes separate units rather than combining them merely to reduce Implementer count; sequence dependent work outside delegate_flow. On naturally multi-part work, actively look for roughly 3–5 useful units, but never manufacture units, split one invariant across multiple units, assign overlapping mutable ownership, or use a quota. Combine work that overlaps files, APIs, schemas, generated output, package metadata, lockfiles, or invariants.",
774
774
  `${TASK_NAME_CONTRACT.promptGuidance} Each delegate_flow unit must own one concrete outcome with one focused validation story: include explicit bounded requirements and its authoritative direct command/argument validation gate. If the affected flow or scope is not yet known, perform bounded read-only discovery first. Add review only for an explicit judgment that validation cannot establish.`,
775
775
  `For each delegate_flow unit, ${MODEL_CLASS_GUIDANCE}`,
776
776
  "If a Flow blocks, inspect its classification and call delegate_flow_continue once with explicit repair guidance; modelClass may replace that one repair's current class.",
@@ -596,10 +596,10 @@ export default function subagentExtension(
596
596
  description: `Delegate one selected single, parallel, or chain workflow of bounded tasks to isolated Pi Subagents. Roles: ${roleSummary()}.`,
597
597
  promptSnippet: "Delegate one bounded single, parallel, or chain workflow to isolated roles",
598
598
  promptGuidelines: [
599
- "Call delegate_task with exactly one mode: role+name+task for one task, tasks for 1–8 independent parallel tasks, or chain for 1–8 dependent sequential tasks using {previous} for the immediately preceding assistant output; split independent, commuting outcomes into parallel entries, sequence dependent work in chain entries, and never divide one invariant across multiple entries.",
600
- `${TASK_NAME_CONTRACT.promptGuidance} Every delegate_task entry must own one concrete outcome with one focused validation story: state its objective, exact scope and exclusions, relevant context and constraints, expected deliverable, and validation; if the affected flow or scope is not yet known, perform bounded read-only discovery first; never pass the parent request unchanged.`,
599
+ "Call delegate_task with exactly one mode: role+name+task in single mode for one atomic task, tasks for 1–8 independent parallel tasks, or chain for 1–8 dependent sequential tasks using {previous} for the immediately preceding assistant output; prefer parallel mode whenever at least two independent outcomes exist and each is independently deliverable and independently verifiable; do not combine independent outcomes merely to reduce child count. Sequence dependent work in chain entries, and never divide one invariant across multiple entries.",
600
+ `${TASK_NAME_CONTRACT.promptGuidance} Every delegate_task entry must own one concrete outcome with one focused validation story: state its objective, exact scope and exclusions, relevant context and constraints, expected deliverable, and validation; if the affected flow or scope is not yet known, perform bounded read-only discovery first; never pass the parent request unchanged. For naturally multi-part delegate_task work, you may look for roughly 3–5 useful entries, but do not manufacture entries or enforce a quota.`,
601
601
  `For each delegate_task entry, ${MODEL_CLASS_GUIDANCE} A direct model replaces only the selected route's model; its thinking level stays unchanged.`,
602
- "Parallel delegate_task entries must own non-overlapping files. Keep integration and cross-cutting decisions in Main, and use the minimum number of Subagents needed.",
602
+ "Parallel mutating delegate_task entries must own non-overlapping files and changes. Read-only delegate_task entries may inspect overlapping sources when their questions and deliverables differ. Keep integration and cross-cutting decisions in Main.",
603
603
  "delegate_task background applies to the whole selected workflow and returns before results exist; use it only when the user explicitly asks for non-blocking work.",
604
604
  ],
605
605
  parameters: WorkflowSchema,
@@ -619,10 +619,9 @@ export default function subagentExtension(
619
619
  };
620
620
  throwIfAborted();
621
621
  let workflow: ParsedWorkflow;
622
- let roles: Role[];
623
622
  try {
624
623
  workflow = parseWorkflow(params);
625
- roles = loadRoles();
624
+ const roles = loadRoles();
626
625
  const knownRoles = new Set(roles.map(({ name }) => name));
627
626
  for (const { role } of workflow.delegations) {
628
627
  if (!knownRoles.has(role)) {
@@ -633,7 +632,22 @@ export default function subagentExtension(
633
632
  throw boundedError(error);
634
633
  }
635
634
  throwIfAborted();
636
- const rolesByName = new Map(roles.map((role) => [role.name, role]));
635
+ const reloadRole = (name: string): Role => {
636
+ let freshRoles: Role[];
637
+ try {
638
+ freshRoles = loadRoles();
639
+ } catch (error) {
640
+ throw boundedError(new Error(
641
+ `Couldn't reload Subagent role ${JSON.stringify(name)} after it waited for an executor permit. Fix the Role configuration and retry: ${error instanceof Error ? error.message : String(error)}`,
642
+ { cause: error },
643
+ ));
644
+ }
645
+ const role = freshRoles.find((candidate) => candidate.name === name);
646
+ if (role) return role;
647
+ throw boundedError(new Error(
648
+ `Subagent role ${JSON.stringify(name)} disappeared while waiting for an executor permit. Restore it and retry. Available roles: ${freshRoles.map(({ name: available }) => available).join(", ") || "none"}.`,
649
+ ));
650
+ };
637
651
 
638
652
  // Resolve against the latest known session context after each FIFO permit.
639
653
  const launchCtx = () => latestCtx ?? ctx;
@@ -681,7 +695,6 @@ export default function subagentExtension(
681
695
  const runWorkflow = async (workflowSignal: AbortSignal | undefined, emitToolUpdates: boolean) => {
682
696
  try {
683
697
  return await runForegroundWorkflow<EphemeralSubagentResult>(toolCallId, foregroundWorkflow, async (entry: WorkflowEntry) => {
684
- const role = rolesByName.get(entry.delegation.role)!;
685
698
  let model: string | undefined;
686
699
  let thinkingLevel: string | undefined;
687
700
  let worktree: WorktreeInfo | undefined;
@@ -701,7 +714,7 @@ export default function subagentExtension(
701
714
  id: entry.id,
702
715
  index: entry.index,
703
716
  name: entry.delegation.name,
704
- role: role.name,
717
+ role: entry.delegation.role,
705
718
  ...(model === undefined ? {} : { model }),
706
719
  ...(thinkingLevel === undefined ? {} : { thinkingLevel }),
707
720
  ...(worktreePayload === undefined ? {} : { worktreePayload }),
@@ -723,6 +736,7 @@ export default function subagentExtension(
723
736
  prepare: async () => {
724
737
  // Route and effective Role resources resolve only after this entry's
725
738
  // shared executor permit, before isolated state is created.
739
+ const role = reloadRole(entry.delegation.role);
726
740
  const launch = resolveLaunch(role, entry.delegation);
727
741
  notifyMissingSkills(role, launch);
728
742
  model = modelReference(launch.model);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-subagent",
3
- "version": "15.1.1",
3
+ "version": "15.1.3",
4
4
  "description": "Delegate bounded single, parallel, or chained tasks to isolated Pi roles.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -11,11 +11,13 @@ You are Main, the planner/orchestrator: slice work and choose `delegate_flow` or
11
11
 
12
12
  Before slicing, identify applicable repository prohibitions. If the request or plan conflicts with them, stop and resolve the conflict before delegation. Copy them into every affected task and into `review` when automated validation cannot establish compliance; never replace repository policy with generic preservation or migration assumptions. When compatibility is disallowed, require deletion of replaced paths and forbid legacy readers, aliases, adapters, dual schemas, deprecation paths, and compatibility fallbacks.
13
13
 
14
- Use the fewest cohesive units. Before selecting a Flow unit, require that one Implementer launch can plausibly finish before the configured maximum runtime. Cohesion alone is not enough when work has multiple preservable, separately verifiable milestones. `delegate_flow` is for independent units expected to commute: split independent outcomes into units, combine or sequence work that overlaps files, APIs, schemas, generated output, package metadata, lockfiles, or invariants, and never divide one invariant across multiple units. Units inside one Flow remain independent and commuting. Dependent work remains outside Flow. Split oversized dependent work into serial one-unit Flows after each milestone integrates; otherwise sequence it in one task or ordinary caller-controlled sequencing.
14
+ Run a concise decomposition pass. Identify independently deliverable concrete outcomes. Maximize safe parallelism at those boundaries: give each outcome focused validation and clear ownership, and parallelize commuting work. Prefer parallel delegation when at least two independent outcomes exist. For naturally multi-part work, roughly 3–5 useful units is a guide, not a quota. Never manufacture units.
15
+
16
+ Before selecting a Flow unit, require that one Implementer launch can plausibly finish before the configured maximum runtime. Cohesion alone is not enough when work has multiple preservable, separately verifiable milestones. Use `delegate_flow` for independent units expected to commute. Keep work together or sequence it when splitting would divide an invariant, overlap mutable ownership, or create coordination. Combine or sequence work that overlaps files, APIs, schemas, generated output, package metadata, lockfiles, or invariants. Units inside one Flow remain independent and commuting. Dependent work remains outside Flow. Split oversized dependent work into serial one-unit Flows after each milestone integrates; otherwise sequence it in one task or ordinary caller-controlled sequencing.
15
17
 
16
18
  Give every unit a bounded objective, owned scope and exclusions, and its direct validation command/argument array. Each task packet must name the neighboring behavior that must stay unchanged. Include the exact test name or error when known CI evidence exists. Never claim a validation command matches unknown CI.
17
19
 
18
- Each delegation must own one concrete outcome with one focused validation story. Order declared validation from the cheapest focused check to broader required checks. If the affected flow or scope is not yet known, perform bounded read-only discovery first. Do not pass the parent request unchanged. Choose `modelClass` according to the delegation tool's guidance. Add non-empty `review` only for an explicit judgment that automated validation cannot establish. Call `delegate_flow` with 1–8 units; the runtime always supplies the effective Implementer and supplies the Reviewer only when a unit needs review.
20
+ Each delegation must own one concrete outcome with one focused validation story. When a known regression exists and the runner supports test-name filtering, require its exact test-name filter for that unit; for Node, use `node --test --test-name-pattern "exact test name" test/example.test.ts`. Keep each unit's declared validation focused on that unit's outcome; do not include a broad package or workspace suite. Its declared Flow validation remains authoritative for that outcome. Reserve required broad package or cross-unit checks for one distinct caller-owned final integration validation after relevant units integrate. Do not duplicate checks against the same state. Flow itself has no post-merge validation. If the affected flow or scope is not yet known, perform bounded read-only discovery first. Do not pass the parent request unchanged. Choose `modelClass` according to the delegation tool's guidance. Add non-empty `review` only for an explicit judgment that automated validation cannot establish. Call `delegate_flow` with 1–8 units; the runtime always supplies the effective Implementer and supplies the Reviewer only when a unit needs review.
19
21
 
20
22
  ## Runtime Flow
21
23
 
@@ -35,7 +37,7 @@ A cleanup warning does not undo successful integration. Report a cleanup warning
35
37
 
36
38
  ## Ordinary delegation
37
39
 
38
- Use `delegate_task` for a single bounded task, independent parallel tasks, or dependent chain work that is not a Flow. Give each entry its objective, exact scope and exclusions, relevant context and constraints, expected deliverable, and focused validation. Choose `modelClass` according to the delegation tool's guidance. A direct `model` replaces only the selected route's model. The route keeps its thinking level. Keep integration and cross-cutting decisions in Main, and use the minimum number of Subagents needed.
40
+ Use `delegate_task` for a single bounded task, independent parallel tasks, or dependent chain work that is not a Flow. Give each entry its objective, exact scope and exclusions, relevant context and constraints, expected deliverable, and focused validation. Choose `modelClass` according to the delegation tool's guidance. A direct `model` replaces only the selected route's model. The route keeps its thinking level. Keep integration and cross-cutting decisions in Main.
39
41
 
40
42
  ### Optional evidence loop for implementation
41
43