@dreki-gg/pi-subagent 0.6.0 → 0.8.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 (40) hide show
  1. package/.fallowrc.json +6 -0
  2. package/CHANGELOG.md +37 -0
  3. package/README.md +82 -70
  4. package/docs/orchestration-principles.md +132 -0
  5. package/docs/plans/01_structured-handoffs-and-synthesis.plan.md +376 -0
  6. package/docs/plans/02_clean-context-review-loop.plan.md +240 -0
  7. package/docs/plans/03_parallel-recon-single-writer-docs.plan.md +199 -0
  8. package/docs/plans/04_manager-workflow.plan.md +248 -0
  9. package/docs/plans/05_advisor-routing.plan.md +244 -0
  10. package/extensions/subagent/agent-result-utils.ts +12 -0
  11. package/extensions/subagent/agent-runner-types.ts +23 -0
  12. package/extensions/subagent/agent-runner.ts +90 -0
  13. package/extensions/subagent/agents.ts +31 -77
  14. package/extensions/subagent/handoffs.ts +273 -0
  15. package/extensions/subagent/index.ts +359 -581
  16. package/extensions/subagent/run-agent-args.ts +90 -0
  17. package/extensions/subagent/{delegate-executor.ts → spawn-utils.ts} +64 -87
  18. package/extensions/subagent/synthesis.ts +1 -51
  19. package/package.json +7 -10
  20. package/prompts/advisor.md +37 -0
  21. package/prompts/bug-prover.md +42 -0
  22. package/{agents → prompts}/docs-scout.md +2 -2
  23. package/prompts/manager.md +52 -0
  24. package/{agents → prompts}/planner.md +16 -1
  25. package/prompts/reviewer.md +93 -0
  26. package/{agents → prompts}/scout.md +5 -1
  27. package/prompts/validator.md +42 -0
  28. package/prompts/worker.md +61 -0
  29. package/skills/spawn-subagents/SKILL.md +80 -8
  30. package/skills/write-an-agent/SKILL.md +5 -5
  31. package/agents/reviewer.md +0 -37
  32. package/agents/worker.md +0 -26
  33. package/extensions/subagent/delegate-args.ts +0 -145
  34. package/extensions/subagent/delegate-types.ts +0 -62
  35. package/extensions/subagent/delegate-ui.ts +0 -132
  36. package/extensions/subagent/workflows.ts +0 -150
  37. package/prompts/implement-and-review.md +0 -10
  38. package/prompts/implement.md +0 -10
  39. package/prompts/scout-and-plan.md +0 -9
  40. /package/{agents → prompts}/ux-designer.md +0 -0
@@ -0,0 +1,90 @@
1
+ import type { AgentScope } from './agents';
2
+
3
+ export interface RunAgentCommandOptions {
4
+ agentScope: AgentScope;
5
+ confirmProjectAgents: boolean;
6
+ model?: string;
7
+ thinking?: string;
8
+ agentName?: string;
9
+ explicitTask?: string;
10
+ }
11
+
12
+ function tokenize(input: string): string[] {
13
+ return input.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, '')) ?? [];
14
+ }
15
+
16
+ export function formatRunAgentUsage(): string {
17
+ return 'Usage: /run-agent [--scope user|project|both] [--model <id>] [--thinking <level>] [--yes-project-agents] <agent> [task]';
18
+ }
19
+
20
+ export function parseRunAgentArgs(rawArgs?: string):
21
+ | { ok: true; options: RunAgentCommandOptions }
22
+ | { ok: false; error: string } {
23
+ const tokens = tokenize(rawArgs?.trim() ?? '');
24
+ const taskTokens: string[] = [];
25
+
26
+ let agentScope: AgentScope = 'user';
27
+ let confirmProjectAgents = true;
28
+ let model: string | undefined;
29
+ let thinking: string | undefined;
30
+ let agentName: string | undefined;
31
+
32
+ for (let i = 0; i < tokens.length; i++) {
33
+ const token = tokens[i];
34
+
35
+ if (token === '--scope') {
36
+ const value = tokens[++i];
37
+ if (!value || !['user', 'project', 'both'].includes(value)) {
38
+ return { ok: false, error: `Invalid --scope value.\n\n${formatRunAgentUsage()}` };
39
+ }
40
+ agentScope = value as AgentScope;
41
+ continue;
42
+ }
43
+
44
+ if (token === '--model') {
45
+ const value = tokens[++i];
46
+ if (!value) {
47
+ return { ok: false, error: `Missing --model value.\n\n${formatRunAgentUsage()}` };
48
+ }
49
+ model = value;
50
+ continue;
51
+ }
52
+
53
+ if (token === '--thinking' || token === '--reasoning-level') {
54
+ const value = tokens[++i];
55
+ if (!value) {
56
+ return { ok: false, error: `Missing ${token} value.\n\n${formatRunAgentUsage()}` };
57
+ }
58
+ thinking = value;
59
+ continue;
60
+ }
61
+
62
+ if (token === '--yes-project-agents') {
63
+ confirmProjectAgents = false;
64
+ continue;
65
+ }
66
+
67
+ if (token.startsWith('--')) {
68
+ return { ok: false, error: `Unknown option: ${token}\n\n${formatRunAgentUsage()}` };
69
+ }
70
+
71
+ if (!agentName) {
72
+ agentName = token;
73
+ continue;
74
+ }
75
+
76
+ taskTokens.push(token);
77
+ }
78
+
79
+ return {
80
+ ok: true,
81
+ options: {
82
+ agentScope,
83
+ confirmProjectAgents,
84
+ model,
85
+ thinking,
86
+ agentName,
87
+ explicitTask: taskTokens.join(' ').trim() || undefined,
88
+ },
89
+ };
90
+ }
@@ -1,26 +1,37 @@
1
+ /**
2
+ * Shared utilities for spawning pi subagent processes.
3
+ * Used by both the `subagent` tool (index.ts) and the `/run-agent` command (agent-runner.ts).
4
+ */
5
+
1
6
  import { spawn } from 'node:child_process';
2
7
  import * as fs from 'node:fs';
3
8
  import * as os from 'node:os';
4
9
  import * as path from 'node:path';
5
- import { withFileMutationQueue } from '@mariozechner/pi-coding-agent';
6
- import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
7
- import type { Message } from '@mariozechner/pi-ai';
8
- import { discoverAgentsWithPackages, type AgentScope } from './agents';
9
- import type { AgentResult, UsageStats } from './delegate-types';
10
+ import { withFileMutationQueue } from '@earendil-works/pi-coding-agent';
11
+ import type { Message } from '@earendil-works/pi-ai';
12
+ import type { UsageStats } from './agent-runner-types.js';
10
13
 
11
- function emptyUsage(): UsageStats {
14
+ export function emptyUsage(): UsageStats {
12
15
  return { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, cost: 0, contextTokens: 0, turns: 0 };
13
16
  }
14
17
 
15
18
  function getPiInvocation(args: string[]): { command: string; args: string[] } {
16
19
  const currentScript = process.argv[1];
17
- if (currentScript && fs.existsSync(currentScript)) {
20
+
21
+ // Bun standalone binaries set argv[1] to a virtual FS path (e.g. /$bunfs/root/pi)
22
+ // that only resolves inside the running Bun process. Skip it — the binary IS the entry point.
23
+ const isBunVirtualPath = currentScript?.startsWith('/$bunfs/');
24
+
25
+ if (currentScript && !isBunVirtualPath && fs.existsSync(currentScript)) {
18
26
  return { command: process.execPath, args: [currentScript, ...args] };
19
27
  }
20
28
 
21
29
  const execName = path.basename(process.execPath).toLowerCase();
22
30
  const isGenericRuntime = /^(node|bun)(\.exe)?$/.test(execName);
23
- if (!isGenericRuntime) return { command: process.execPath, args };
31
+ if (!isGenericRuntime) {
32
+ // Standalone binary (e.g. pi compiled with Bun) — invoke directly
33
+ return { command: process.execPath, args };
34
+ }
24
35
 
25
36
  return { command: 'pi', args };
26
37
  }
@@ -38,74 +49,76 @@ async function writePromptToTempFile(
38
49
  return { dir: tmpDir, filePath };
39
50
  }
40
51
 
41
- export type OnPhaseUpdate = (phaseName: string, agentName: string, result: AgentResult) => void;
52
+ function cleanupTempFiles(
53
+ tmpPromptPath: string | null,
54
+ tmpPromptDir: string | null,
55
+ ): void {
56
+ if (tmpPromptPath) try { fs.unlinkSync(tmpPromptPath); } catch { /* ignore */ }
57
+ if (tmpPromptDir) try { fs.rmdirSync(tmpPromptDir); } catch { /* ignore */ }
58
+ }
42
59
 
43
- export interface RunAgentOptions {
44
- agentScope?: AgentScope;
45
- cwd?: string;
46
- onUpdate?: OnPhaseUpdate;
47
- phaseName?: string;
60
+ export interface SpawnPiAgentOptions {
61
+ cwd: string;
62
+ agentName: string;
63
+ task: string;
64
+ systemPrompt?: string;
65
+ model?: string;
66
+ thinking?: string;
67
+ tools?: string[];
48
68
  signal?: AbortSignal;
49
- resolvedPaths?: ResolvedPaths;
69
+ onMessage?: (msg: Message) => void;
70
+ onToolResult?: (msg: Message) => void;
50
71
  }
51
72
 
52
- export async function runAgent(
53
- cwd: string,
54
- agentName: string,
55
- task: string,
56
- options: RunAgentOptions = {},
57
- ): Promise<AgentResult> {
58
- const { agents } = discoverAgentsWithPackages(cwd, options.agentScope ?? 'user', options.resolvedPaths);
59
- const agent = agents.find((a) => a.name === agentName);
60
-
61
- if (!agent) {
62
- const available = agents.map((a) => a.name).join(', ') || 'none';
63
- return {
64
- agent: agentName,
65
- task,
66
- exitCode: 1,
67
- messages: [],
68
- stderr: `Unknown agent: "${agentName}". Available: ${available}.`,
69
- usage: emptyUsage(),
70
- };
71
- }
73
+ export interface SpawnPiAgentResult {
74
+ exitCode: number;
75
+ messages: Message[];
76
+ stderr: string;
77
+ wasAborted: boolean;
78
+ usage: UsageStats;
79
+ model?: string;
80
+ stopReason?: string;
81
+ errorMessage?: string;
82
+ }
72
83
 
84
+ /**
85
+ * Spawn a pi process for a subagent and collect results.
86
+ * This is the shared core that both the tool and the /run-agent command use.
87
+ */
88
+ export async function spawnPiAgent(options: SpawnPiAgentOptions): Promise<SpawnPiAgentResult> {
73
89
  const args: string[] = ['--mode', 'json', '-p', '--no-session'];
74
- if (agent.model) args.push('--model', agent.model);
75
- if (agent.thinking) args.push('--thinking', agent.thinking);
76
- if (agent.tools && agent.tools.length > 0) args.push('--tools', agent.tools.join(','));
90
+ if (options.model) args.push('--model', options.model);
91
+ if (options.thinking) args.push('--thinking', options.thinking);
92
+ if (options.tools && options.tools.length > 0) args.push('--tools', options.tools.join(','));
77
93
 
78
94
  let tmpPromptDir: string | null = null;
79
95
  let tmpPromptPath: string | null = null;
80
96
 
81
- const result: AgentResult = {
82
- agent: agentName,
83
- task,
97
+ const result: SpawnPiAgentResult = {
84
98
  exitCode: 0,
85
99
  messages: [],
86
100
  stderr: '',
101
+ wasAborted: false,
87
102
  usage: emptyUsage(),
88
- model: agent.model,
89
103
  };
90
104
 
91
105
  try {
92
- if (agent.systemPrompt.trim()) {
93
- const tmp = await writePromptToTempFile(agent.name, agent.systemPrompt);
106
+ if (options.systemPrompt?.trim()) {
107
+ const tmp = await writePromptToTempFile(options.agentName, options.systemPrompt);
94
108
  tmpPromptDir = tmp.dir;
95
109
  tmpPromptPath = tmp.filePath;
96
110
  args.push('--append-system-prompt', tmpPromptPath);
97
111
  }
98
112
 
99
- args.push(`Task: ${task}`);
113
+ args.push(`Task: ${options.task}`);
100
114
 
101
115
  const exitCode = await new Promise<number>((resolve) => {
102
116
  const invocation = getPiInvocation(args);
103
117
  const proc = spawn(invocation.command, invocation.args, {
104
- cwd: options.cwd ?? cwd,
118
+ cwd: options.cwd,
105
119
  shell: false,
106
120
  stdio: ['ignore', 'pipe', 'pipe'],
107
121
  });
108
-
109
122
  let buffer = '';
110
123
 
111
124
  const processLine = (line: string) => {
@@ -137,14 +150,12 @@ export async function runAgent(
137
150
  if (msg.errorMessage) result.errorMessage = msg.errorMessage;
138
151
  }
139
152
 
140
- if (options.onUpdate)
141
- options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
153
+ options.onMessage?.(msg);
142
154
  }
143
155
 
144
156
  if (event.type === 'tool_result_end' && event.message) {
145
157
  result.messages.push(event.message as Message);
146
- if (options.onUpdate)
147
- options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
158
+ options.onToolResult?.(event.message as Message);
148
159
  }
149
160
  };
150
161
 
@@ -168,6 +179,7 @@ export async function runAgent(
168
179
 
169
180
  if (options.signal) {
170
181
  const killProc = () => {
182
+ result.wasAborted = true;
171
183
  proc.kill('SIGTERM');
172
184
  setTimeout(() => {
173
185
  if (!proc.killed) proc.kill('SIGKILL');
@@ -181,41 +193,6 @@ export async function runAgent(
181
193
  result.exitCode = exitCode;
182
194
  return result;
183
195
  } finally {
184
- if (tmpPromptPath)
185
- try {
186
- fs.unlinkSync(tmpPromptPath);
187
- } catch {
188
- /* ignore */
189
- }
190
- if (tmpPromptDir)
191
- try {
192
- fs.rmdirSync(tmpPromptDir);
193
- } catch {
194
- /* ignore */
195
- }
196
+ cleanupTempFiles(tmpPromptPath, tmpPromptDir);
196
197
  }
197
198
  }
198
-
199
- export async function runParallel(
200
- cwd: string,
201
- agentNames: string[],
202
- task: string,
203
- options: RunAgentOptions = {},
204
- ): Promise<AgentResult[]> {
205
- const MAX_CONCURRENCY = 4;
206
- const results: AgentResult[] = new Array(agentNames.length);
207
- let nextIndex = 0;
208
-
209
- const workers = new Array(Math.min(MAX_CONCURRENCY, agentNames.length))
210
- .fill(null)
211
- .map(async () => {
212
- while (true) {
213
- const current = nextIndex++;
214
- if (current >= agentNames.length) return;
215
- results[current] = await runAgent(cwd, agentNames[current], task, options);
216
- }
217
- });
218
-
219
- await Promise.all(workers);
220
- return results;
221
- }
@@ -1,42 +1,7 @@
1
- import type { ExtensionCommandContext } from '@mariozechner/pi-coding-agent';
1
+ import type { ExtensionCommandContext } from '@earendil-works/pi-coding-agent';
2
2
 
3
3
  const MAX_MESSAGES = 40;
4
4
 
5
- const SYNTHESIS_INSTRUCTION = `Synthesize the current conversation into a clear task specification for a team of subagents that will execute it.
6
-
7
- Your synthesis MUST capture:
8
-
9
- 1. **Goal** — What are we building, changing, or investigating?
10
- 2. **Decisions made** — Every locked choice, preference, or constraint the user confirmed.
11
- 3. **Constraints** — What was explicitly rejected and why.
12
- 4. **Architecture** — The agreed structure, file layout, data flow, or integration shape.
13
- 5. **Open questions** — Anything flagged but not resolved yet.
14
- 6. **Intent** — The user's real motivation and the nuance behind the decisions.
15
-
16
- Be specific and actionable. Do NOT summarize vaguely. Include concrete names, paths, tools, APIs, and patterns that were discussed.
17
-
18
- The output should be usable by agents who have NOT seen this conversation.
19
-
20
- Format:
21
-
22
- ## Goal
23
- <one paragraph>
24
-
25
- ## Decisions
26
- <bulleted list of every locked decision>
27
-
28
- ## Constraints
29
- <bulleted list of what was rejected and why>
30
-
31
- ## Architecture
32
- <concrete structure, files, data flow>
33
-
34
- ## Open Questions
35
- <anything unresolved>
36
-
37
- ## Intent
38
- <the user's real motivation>`;
39
-
40
5
  export function extractRecentConversation(ctx: ExtensionCommandContext): string {
41
6
  const entries = ctx.sessionManager.getBranch();
42
7
  const messages: string[] = [];
@@ -61,18 +26,3 @@ export function extractRecentConversation(ctx: ExtensionCommandContext): string
61
26
 
62
27
  return messages.slice(-MAX_MESSAGES).join('\n\n---\n\n');
63
28
  }
64
-
65
- export function buildSynthesisPrompt(conversation: string, explicitTask?: string): string {
66
- const parts = [SYNTHESIS_INSTRUCTION];
67
-
68
- if (explicitTask) {
69
- parts.push(`\nThe user explicitly specified the task as:\n${explicitTask}`);
70
- parts.push(
71
- '\nUse this as the primary goal, but enrich it with relevant context from the conversation.',
72
- );
73
- }
74
-
75
- parts.push(`\n\n## Conversation\n\n${conversation}`);
76
-
77
- return parts.join('\n');
78
- }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dreki-gg/pi-subagent",
3
- "version": "0.6.0",
4
- "description": "Subagent tool and delegate orchestration for pi — isolated agents, parallel scouts, planning gates, and workflow presets",
3
+ "version": "0.8.0",
4
+ "description": "Subagent tool and direct agent runs for pi — isolated agents, parallel scouts, manager workflows, and bundled prompts",
5
5
  "keywords": [
6
6
  "pi-package"
7
7
  ],
@@ -28,9 +28,6 @@
28
28
  ],
29
29
  "prompts": [
30
30
  "./prompts"
31
- ],
32
- "agents": [
33
- "./agents"
34
31
  ]
35
32
  },
36
33
  "devDependencies": {
@@ -40,10 +37,10 @@
40
37
  "typescript": "^6.0.0"
41
38
  },
42
39
  "peerDependencies": {
43
- "@mariozechner/pi-ai": "*",
44
- "@mariozechner/pi-agent-core": "*",
45
- "@mariozechner/pi-coding-agent": "*",
46
- "@mariozechner/pi-tui": "*",
47
- "@sinclair/typebox": "*"
40
+ "@earendil-works/pi-ai": "*",
41
+ "@earendil-works/pi-agent-core": "*",
42
+ "@earendil-works/pi-coding-agent": "*",
43
+ "@earendil-works/pi-tui": "*",
44
+ "typebox": "*"
48
45
  }
49
46
  }
@@ -0,0 +1,37 @@
1
+ ---
2
+ name: advisor
3
+ description: Focused second-opinion consult for tricky planning, implementation, or review decisions
4
+ tools: read, grep, find, ls
5
+ model: openai/gpt-5.4
6
+ thinking: medium
7
+ ---
8
+
9
+ You are an advisor.
10
+
11
+ Mission:
12
+ - Diagnose the hard part of the caller's problem.
13
+ - Recommend the next investigation or decision.
14
+ - Surface concrete risks without taking over the task.
15
+
16
+ Rules:
17
+ 1. Focus on the specific question you were asked, not the whole task from scratch.
18
+ 2. If the answer depends on repo context you have not inspected, say exactly which files, symbols, or commands to inspect next.
19
+ 3. Prefer one clear recommendation over a brainstorming list.
20
+ 4. Do not implement code, rewrite the whole plan, or claim confidence you have not earned from inspected context.
21
+ 5. The caller stays in charge; your job is to sharpen their next move.
22
+
23
+ Output format:
24
+
25
+ ## Assessment
26
+ - What looks tricky, risky, or ambiguous
27
+
28
+ ## What to Inspect Next
29
+ - Concrete files, commands, questions, or experiments
30
+ - If no extra inspection is needed, say `- None.`
31
+
32
+ ## Recommendation
33
+ - Best next action for the caller
34
+
35
+ ## Risks
36
+ - Remaining failure modes, trade-offs, or unknowns
37
+ - If none, say `- None identified from inspected context.`
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: bug-prover
3
+ description: Create the smallest failing repro for a suspected bug. Use when a reviewer or validator needs a minimal test or artifact to prove a claim.
4
+ tools: read, grep, find, ls, bash, edit, write
5
+ model: openai/gpt-5.4
6
+ thinking: medium
7
+ sessionStrategy: fork-at
8
+ ---
9
+
10
+ You are a bug-prover.
11
+
12
+ Mission:
13
+ - Build the smallest reproducible proof for a suspected bug.
14
+ - Prefer an existing test pattern; otherwise create the narrowest isolated repro artifact.
15
+ - Leave behind evidence that another agent can run and inspect.
16
+
17
+ Rules:
18
+ 1. Start from one concrete claim and target behavior.
19
+ 2. Create the minimal repro only; do not fix the bug or refactor unrelated code.
20
+ 3. Prefer a focused failing test in the repo's existing test style.
21
+ 4. If a test is the wrong shape, create the smallest runnable script or fixture instead.
22
+ 5. Keep diffs narrow, reversible, and easy for another agent to inspect.
23
+ 6. If the claim cannot be proven safely, say why instead of forcing a bad repro.
24
+
25
+ Output format:
26
+
27
+ ## Claim
28
+ - The exact bug or behavior being proved
29
+
30
+ ## Proof Artifact
31
+ - `path/to/file` - what was added or changed to prove the claim
32
+ - if none, say `- None.`
33
+
34
+ ## How to Run
35
+ - exact command(s) to reproduce the failure or observation
36
+
37
+ ## Expected Failure or Observation
38
+ - what another agent should see if the claim is real
39
+
40
+ ## Scope Notes
41
+ - what was intentionally not changed
42
+ - cleanup or revert notes if relevant
@@ -8,7 +8,7 @@ thinking: medium
8
8
 
9
9
  You are a documentation scout.
10
10
 
11
- Your job is to quickly gather high-signal implementation documentation and hand it off to another agent.
11
+ Your job is to quickly gather high-signal implementation documentation and hand it off to another agent. Keep the output sections exact so the handoff can be summarized reliably.
12
12
 
13
13
  Rules:
14
14
  1. Prefer Context7 for library/framework/package docs.
@@ -33,4 +33,4 @@ Output format:
33
33
  - Explain how these docs likely apply to the current codebase or plan
34
34
 
35
35
  ## Recommended Next Step
36
- - What the planner or worker should do with this information
36
+ - Mandatory: say exactly what the planner or worker should do with this information next
@@ -0,0 +1,52 @@
1
+ ---
2
+ name: manager
3
+ description: Delegation orchestrator for multi-slice features, migrations, and refactors that need coherent decisions
4
+ model: openai/gpt-5.4
5
+ thinking: high
6
+ sessionStrategy: fork-at
7
+ ---
8
+
9
+ You are a manager.
10
+
11
+ Mission:
12
+ - Break a large task into bounded workstreams.
13
+ - Delegate to specialist child agents via the `subagent` tool when that improves signal.
14
+ - Synthesize results into one coherent next action.
15
+
16
+ Use child agents as specialists, not as peers negotiating in circles.
17
+
18
+ Rules:
19
+ 1. Split by scope, ownership, or decision boundary, not arbitrary agent count.
20
+ 2. Prefer `scout`, `docs-scout`, and `planner` in parallel for discovery or planning.
21
+ 3. Prefer one `worker` for edits unless file ownership is obviously isolated.
22
+ 4. Synthesize child findings before delegating again.
23
+ 5. Escalate unresolved product or architecture decisions back to the main agent or user.
24
+ 6. Do not dump raw child logs; return compact conclusions.
25
+ 7. If one specialist can handle the task directly, say so instead of over-managing.
26
+
27
+ Output format:
28
+
29
+ ## Goal
30
+ - One-sentence statement of the parent task.
31
+
32
+ ## Workstreams
33
+ 1. Workstream name - owner agent, scope, expected output
34
+ 2. ...
35
+
36
+ ## Shared Decisions
37
+ - Constraints, locked decisions, or coordination rules all children must follow.
38
+ - If none, say `- None`.
39
+
40
+ ## Child Reports
41
+ ### <workstream>
42
+ - owner: agent name
43
+ - status: planned | ran | blocked
44
+ - files implicated: `path/to/file` or `None`
45
+ - findings: what was learned or produced
46
+ - blockers/questions: what still needs resolution
47
+
48
+ ## Recommended Next Action
49
+ - State whether to run `worker`, `reviewer`, another bounded child task, or ask the human.
50
+
51
+ ## Notes (if any)
52
+ - Anything the main agent should know.
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  name: planner
3
3
  description: Creates implementation plans from context and requirements
4
- tools: read, grep, find, ls
4
+ tools: read, grep, find, ls, subagent
5
5
  model: openai/gpt-5.4
6
6
  thinking: high
7
7
  ---
@@ -10,6 +10,17 @@ You are a planning specialist. You receive context (from a scout) and requiremen
10
10
 
11
11
  You must NOT make any changes. Only read, analyze, and plan.
12
12
 
13
+ If the task has multiple viable designs, unclear ownership boundaries, or needs sharper decomposition before implementation, you may consult the `advisor` agent with the `subagent` tool.
14
+
15
+ When consulting `advisor`, send only:
16
+ - current role: `planner`
17
+ - the exact design or decomposition question
18
+ - implicated files or packages
19
+ - the smallest relevant task summary
20
+ - what constraints or trade-offs you already see
21
+
22
+ Treat `advisor` as a focused second opinion. You still own the plan.
23
+
13
24
  Input format you'll receive:
14
25
  - Context/findings from a scout agent
15
26
  - Original query or requirements
@@ -19,6 +30,10 @@ Output format:
19
30
  ## Goal
20
31
  One sentence summary of what needs to be done.
21
32
 
33
+ ## Constraints
34
+ - Locked decisions, rejected approaches, assumptions that must stay true.
35
+ - If there are no special constraints, say `- None`.
36
+
22
37
  ## Plan
23
38
  Numbered steps, each small and actionable:
24
39
  1. Step one - specific file/function to modify