@dreki-gg/pi-subagent 0.3.1 → 0.5.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.
- package/CHANGELOG.md +20 -1
- package/README.md +39 -5
- package/extensions/subagent/agents.ts +90 -3
- package/extensions/subagent/delegate-args.ts +84 -0
- package/extensions/subagent/delegate-executor.ts +31 -10
- package/extensions/subagent/index.ts +105 -26
- package/package.json +4 -1
- package/skills/spawn-subagents/SKILL.md +58 -0
- package/skills/write-an-agent/SKILL.md +67 -0
- package/skills/subagent-workflows/SKILL.md +0 -52
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @dreki-gg/pi-subagent
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`4f2f148`](https://github.com/dreki-gg/pi-extensions/commit/4f2f148488e32ff43f97216a5c221fd9d1716a11) Thanks [@jalbarrang](https://github.com/jalbarrang)! - added agents to the registry so my fork is able to discover subagent files
|
|
8
|
+
|
|
9
|
+
## 0.4.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- [`52d744e`](https://github.com/dreki-gg/pi-extensions/commit/52d744e34f593a7bd6b907d67d5e245ef63b6079) Thanks [@jalbarrang](https://github.com/jalbarrang)! - Improve bundled agent resolution and `/delegate` workflow control in `@dreki-gg/pi-subagent`.
|
|
14
|
+
|
|
15
|
+
- Add explicit agent source tracking for bundled, user, and project agents.
|
|
16
|
+
- Resolve agents with layered precedence: bundled → user → project.
|
|
17
|
+
- Add `agentScope` support to delegated execution so workflows can opt into user, project, or both agent layers.
|
|
18
|
+
- Add `/delegate` argument parsing for `--scope`, `--workflow`, and `--yes-project-agents`.
|
|
19
|
+
- Add a confirmation step before running project-local agents from `/delegate` or the `subagent` tool when UI is available.
|
|
20
|
+
- Replace the old `subagent-workflows` skill with `spawn-subagents`, which steers the assistant toward conversational `subagent` usage and keeps `/delegate` as an explicit gated workflow option.
|
|
21
|
+
|
|
3
22
|
## 0.3.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -20,7 +39,7 @@
|
|
|
20
39
|
- `/delegate` command — synthesize conversation into a task, pick a workflow, execute with scouts/planner/worker/reviewer
|
|
21
40
|
- `/delegate-agents` command — list, customize, or reset bundled agents
|
|
22
41
|
- 6 bundled agents: scout, docs-scout, planner, worker, reviewer, ux-designer
|
|
23
|
-
- `
|
|
42
|
+
- `spawn-subagents` skill for conversational subagent orchestration
|
|
24
43
|
- 3 prompt templates: implement, scout-and-plan, implement-and-review
|
|
25
44
|
|
|
26
45
|
### Bundled agent discovery
|
package/README.md
CHANGED
|
@@ -18,9 +18,21 @@ The `subagent` tool supports three modes:
|
|
|
18
18
|
| Parallel | `{ tasks: [...] }` — multiple agents concurrently |
|
|
19
19
|
| Chain | `{ chain: [...] }` — sequential with `{previous}` placeholder |
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Recommended Usage
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
In day-to-day use, the main agent should usually call the `subagent` tool from normal conversation.
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
- "spawn a scout for the auth code"
|
|
27
|
+
- "run scout and docs-scout in parallel"
|
|
28
|
+
- "have planner make a plan, then worker implement it"
|
|
29
|
+
- "send this to reviewer"
|
|
30
|
+
|
|
31
|
+
`/delegate` is optional. It exists for rigid gated workflows, plan approval, and explicit workflow control.
|
|
32
|
+
|
|
33
|
+
## Optional Delegate Command
|
|
34
|
+
|
|
35
|
+
After a design/grill session, or when you explicitly want a guided workflow:
|
|
24
36
|
|
|
25
37
|
```
|
|
26
38
|
/delegate
|
|
@@ -32,6 +44,18 @@ Or with an explicit task:
|
|
|
32
44
|
/delegate implement the auth flow we designed
|
|
33
45
|
```
|
|
34
46
|
|
|
47
|
+
Use project-local repo agents:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
/delegate --scope project implement the subagent refactor
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Pin a workflow and skip the project-agent confirmation prompt:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
/delegate --scope project --workflow implement --yes-project-agents improve delegate execution
|
|
57
|
+
```
|
|
58
|
+
|
|
35
59
|
### How it works
|
|
36
60
|
|
|
37
61
|
1. **Synthesize** — extracts goal, decisions, constraints, architecture, intent from conversation
|
|
@@ -41,6 +65,14 @@ Or with an explicit task:
|
|
|
41
65
|
5. **Plan gate** — shows planner output for approval before worker runs
|
|
42
66
|
6. **Summary** — full phase-by-phase report with usage totals
|
|
43
67
|
|
|
68
|
+
### Delegate Flags
|
|
69
|
+
|
|
70
|
+
| Flag | Meaning |
|
|
71
|
+
|------|---------|
|
|
72
|
+
| `--scope user|project|both` | Which agent layers to use. Default: `user` |
|
|
73
|
+
| `--workflow <id>` | Skip the picker and force a workflow |
|
|
74
|
+
| `--yes-project-agents` | Disable the confirmation prompt for project-local agents |
|
|
75
|
+
|
|
44
76
|
### Workflows
|
|
45
77
|
|
|
46
78
|
| Workflow | Phases |
|
|
@@ -54,7 +86,7 @@ Or with an explicit task:
|
|
|
54
86
|
|
|
55
87
|
## Agent Definitions
|
|
56
88
|
|
|
57
|
-
Create agent files in `~/.pi/agent/agents/` as markdown with YAML frontmatter:
|
|
89
|
+
Create agent files in `~/.pi/agent/agents/` or `.pi/agents/` as markdown with YAML frontmatter:
|
|
58
90
|
|
|
59
91
|
```markdown
|
|
60
92
|
---
|
|
@@ -78,7 +110,9 @@ The package ships with these agents out of the box:
|
|
|
78
110
|
- `reviewer` — code review
|
|
79
111
|
- `ux-designer` — frontend UI design
|
|
80
112
|
|
|
81
|
-
|
|
113
|
+
Resolution order is: bundled → user (`~/.pi/agent/agents/`) → project (`.pi/agents/`). Project agents override user and bundled agents by name.
|
|
114
|
+
|
|
115
|
+
> Note: pi packages do not currently expose a first-class `agents` manifest. If you mirror package agents into `~/.pi/agent/agents/`, treat those files as managed package artifacts rather than hand-authored overrides.
|
|
82
116
|
|
|
83
117
|
### Managing Agents
|
|
84
118
|
|
|
@@ -92,7 +126,7 @@ User agents in `~/.pi/agent/agents/` override bundled agents by name.
|
|
|
92
126
|
## Bundled Resources
|
|
93
127
|
|
|
94
128
|
### Skill
|
|
95
|
-
- `
|
|
129
|
+
- `spawn-subagents` — guides the model on when/how to spawn specialized subagents conversationally
|
|
96
130
|
|
|
97
131
|
### Prompt Templates
|
|
98
132
|
- `/implement` — scout → planner → worker
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Agent discovery and configuration
|
|
3
|
+
*
|
|
4
|
+
* Supports two discovery strategies:
|
|
5
|
+
* 1. Package-resolved: Uses pi's ResolvedPaths.agents from the package manager
|
|
6
|
+
* when available (pi forks with first-class agents resource support).
|
|
7
|
+
* Package agents are resolved, filtered, and toggleable via pi config.
|
|
8
|
+
* 2. Legacy: Manual filesystem discovery from bundled, user, and project dirs.
|
|
9
|
+
* Used as fallback when ResolvedPaths.agents is not available.
|
|
3
10
|
*/
|
|
4
11
|
|
|
5
12
|
import * as fs from 'node:fs';
|
|
6
13
|
import * as path from 'node:path';
|
|
7
14
|
import { getAgentDir, parseFrontmatter } from '@mariozechner/pi-coding-agent';
|
|
15
|
+
import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
|
|
8
16
|
|
|
9
17
|
export type AgentScope = 'user' | 'project' | 'both';
|
|
18
|
+
export type AgentSource = 'bundled' | 'user' | 'project' | 'package';
|
|
10
19
|
|
|
11
20
|
export interface AgentConfig {
|
|
12
21
|
name: string;
|
|
@@ -15,7 +24,7 @@ export interface AgentConfig {
|
|
|
15
24
|
model?: string;
|
|
16
25
|
thinking?: string;
|
|
17
26
|
systemPrompt: string;
|
|
18
|
-
source:
|
|
27
|
+
source: AgentSource;
|
|
19
28
|
filePath: string;
|
|
20
29
|
}
|
|
21
30
|
|
|
@@ -27,7 +36,7 @@ export interface AgentDiscoveryResult {
|
|
|
27
36
|
/** Bundled agents ship with the package (../../agents relative to extensions/subagent/) */
|
|
28
37
|
const bundledAgentsDir = path.resolve(import.meta.dirname, '..', '..', 'agents');
|
|
29
38
|
|
|
30
|
-
function loadAgentsFromDir(dir: string, source:
|
|
39
|
+
function loadAgentsFromDir(dir: string, source: AgentSource): AgentConfig[] {
|
|
31
40
|
const agents: AgentConfig[] = [];
|
|
32
41
|
|
|
33
42
|
if (!fs.existsSync(dir)) {
|
|
@@ -99,12 +108,62 @@ function findNearestProjectAgentsDir(cwd: string): string | null {
|
|
|
99
108
|
}
|
|
100
109
|
}
|
|
101
110
|
|
|
111
|
+
/**
|
|
112
|
+
* Load agents from package-manager resolved paths (enabled only).
|
|
113
|
+
* This is called with pre-resolved paths from an async context.
|
|
114
|
+
*/
|
|
115
|
+
export function loadAgentsFromResolvedPaths(resolvedPaths: ResolvedPaths): AgentConfig[] {
|
|
116
|
+
// Check if the agents field exists (compatibility with upstream pi)
|
|
117
|
+
const agentResources = (resolvedPaths as unknown as Record<string, unknown>).agents;
|
|
118
|
+
if (!agentResources || !Array.isArray(agentResources)) {
|
|
119
|
+
return [];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const agents: AgentConfig[] = [];
|
|
123
|
+
for (const resource of agentResources) {
|
|
124
|
+
if (!resource.enabled) continue;
|
|
125
|
+
const agent = loadAgentFromFile(resource.path, 'package');
|
|
126
|
+
if (agent) agents.push(agent);
|
|
127
|
+
}
|
|
128
|
+
return agents;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function loadAgentFromFile(filePath: string, source: AgentSource): AgentConfig | null {
|
|
132
|
+
let content: string;
|
|
133
|
+
try {
|
|
134
|
+
content = fs.readFileSync(filePath, 'utf-8');
|
|
135
|
+
} catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const { frontmatter, body } = parseFrontmatter<Record<string, string>>(content);
|
|
140
|
+
if (!frontmatter.name || !frontmatter.description) {
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const tools = frontmatter.tools
|
|
145
|
+
?.split(',')
|
|
146
|
+
.map((t: string) => t.trim())
|
|
147
|
+
.filter(Boolean);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
name: frontmatter.name,
|
|
151
|
+
description: frontmatter.description,
|
|
152
|
+
tools: tools && tools.length > 0 ? tools : undefined,
|
|
153
|
+
model: frontmatter.model,
|
|
154
|
+
thinking: frontmatter.thinking,
|
|
155
|
+
systemPrompt: body,
|
|
156
|
+
source,
|
|
157
|
+
filePath,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
102
161
|
export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryResult {
|
|
103
162
|
const userDir = path.join(getAgentDir(), 'agents');
|
|
104
163
|
const projectAgentsDir = findNearestProjectAgentsDir(cwd);
|
|
105
164
|
|
|
106
165
|
// Bundled agents from the package itself (lowest priority)
|
|
107
|
-
const bundledAgents = loadAgentsFromDir(bundledAgentsDir, '
|
|
166
|
+
const bundledAgents = loadAgentsFromDir(bundledAgentsDir, 'bundled');
|
|
108
167
|
|
|
109
168
|
const userAgents = scope === 'project' ? [] : loadAgentsFromDir(userDir, 'user');
|
|
110
169
|
const projectAgents =
|
|
@@ -127,6 +186,34 @@ export function discoverAgents(cwd: string, scope: AgentScope): AgentDiscoveryRe
|
|
|
127
186
|
return { agents: Array.from(agentMap.values()), projectAgentsDir };
|
|
128
187
|
}
|
|
129
188
|
|
|
189
|
+
/**
|
|
190
|
+
* Discover agents with package-resolved paths merged in.
|
|
191
|
+
* Package-resolved agents (from pi.agents in installed packages) are loaded
|
|
192
|
+
* at lowest priority, then overridden by bundled, user, and project agents.
|
|
193
|
+
*
|
|
194
|
+
* Falls back to discoverAgents() when resolvedPaths is not provided or
|
|
195
|
+
* does not contain the agents field (upstream pi compatibility).
|
|
196
|
+
*/
|
|
197
|
+
export function discoverAgentsWithPackages(
|
|
198
|
+
cwd: string,
|
|
199
|
+
scope: AgentScope,
|
|
200
|
+
resolvedPaths?: ResolvedPaths,
|
|
201
|
+
): AgentDiscoveryResult {
|
|
202
|
+
const base = discoverAgents(cwd, scope);
|
|
203
|
+
|
|
204
|
+
if (!resolvedPaths) return base;
|
|
205
|
+
|
|
206
|
+
const packageAgents = loadAgentsFromResolvedPaths(resolvedPaths);
|
|
207
|
+
if (packageAgents.length === 0) return base;
|
|
208
|
+
|
|
209
|
+
// Package agents are lowest priority: existing agents override by name
|
|
210
|
+
const agentMap = new Map<string, AgentConfig>();
|
|
211
|
+
for (const agent of packageAgents) agentMap.set(agent.name, agent);
|
|
212
|
+
for (const agent of base.agents) agentMap.set(agent.name, agent);
|
|
213
|
+
|
|
214
|
+
return { agents: Array.from(agentMap.values()), projectAgentsDir: base.projectAgentsDir };
|
|
215
|
+
}
|
|
216
|
+
|
|
130
217
|
export { bundledAgentsDir };
|
|
131
218
|
|
|
132
219
|
export function formatAgentList(
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { AgentScope } from './agents';
|
|
2
|
+
import type { WorkflowId } from './delegate-types';
|
|
3
|
+
|
|
4
|
+
export interface DelegateCommandOptions {
|
|
5
|
+
agentScope: AgentScope;
|
|
6
|
+
workflowId?: WorkflowId;
|
|
7
|
+
confirmProjectAgents: boolean;
|
|
8
|
+
explicitTask?: string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const WORKFLOW_IDS = new Set<WorkflowId>([
|
|
12
|
+
'scout-only',
|
|
13
|
+
'scout-and-plan',
|
|
14
|
+
'implement',
|
|
15
|
+
'implement-and-review',
|
|
16
|
+
'quick-fix',
|
|
17
|
+
'review',
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
function tokenize(input: string): string[] {
|
|
21
|
+
return input.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, '')) ?? [];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function formatDelegateUsage(): string {
|
|
25
|
+
return [
|
|
26
|
+
'Usage: /delegate [--scope user|project|both] [--workflow <id>] [--yes-project-agents] [task]',
|
|
27
|
+
'',
|
|
28
|
+
'Workflows: scout-only, scout-and-plan, implement, implement-and-review, quick-fix, review',
|
|
29
|
+
].join('\n');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function parseDelegateArgs(rawArgs?: string):
|
|
33
|
+
| { ok: true; options: DelegateCommandOptions }
|
|
34
|
+
| { ok: false; error: string } {
|
|
35
|
+
const tokens = tokenize(rawArgs?.trim() ?? '');
|
|
36
|
+
const taskTokens: string[] = [];
|
|
37
|
+
|
|
38
|
+
let agentScope: AgentScope = 'user';
|
|
39
|
+
let workflowId: WorkflowId | undefined;
|
|
40
|
+
let confirmProjectAgents = true;
|
|
41
|
+
|
|
42
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
43
|
+
const token = tokens[i];
|
|
44
|
+
|
|
45
|
+
if (token === '--scope') {
|
|
46
|
+
const value = tokens[++i];
|
|
47
|
+
if (!value || !['user', 'project', 'both'].includes(value)) {
|
|
48
|
+
return { ok: false, error: `Invalid --scope value.\n\n${formatDelegateUsage()}` };
|
|
49
|
+
}
|
|
50
|
+
agentScope = value as AgentScope;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (token === '--workflow') {
|
|
55
|
+
const value = tokens[++i] as WorkflowId | undefined;
|
|
56
|
+
if (!value || !WORKFLOW_IDS.has(value)) {
|
|
57
|
+
return { ok: false, error: `Invalid --workflow value.\n\n${formatDelegateUsage()}` };
|
|
58
|
+
}
|
|
59
|
+
workflowId = value;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (token === '--yes-project-agents') {
|
|
64
|
+
confirmProjectAgents = false;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (token.startsWith('--')) {
|
|
69
|
+
return { ok: false, error: `Unknown option: ${token}\n\n${formatDelegateUsage()}` };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
taskTokens.push(token);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
ok: true,
|
|
77
|
+
options: {
|
|
78
|
+
agentScope,
|
|
79
|
+
workflowId,
|
|
80
|
+
confirmProjectAgents,
|
|
81
|
+
explicitTask: taskTokens.join(' ').trim() || undefined,
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
}
|
|
@@ -3,8 +3,9 @@ import * as fs from 'node:fs';
|
|
|
3
3
|
import * as os from 'node:os';
|
|
4
4
|
import * as path from 'node:path';
|
|
5
5
|
import { withFileMutationQueue } from '@mariozechner/pi-coding-agent';
|
|
6
|
+
import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
|
|
6
7
|
import type { Message } from '@mariozechner/pi-ai';
|
|
7
|
-
import {
|
|
8
|
+
import { discoverAgentsWithPackages, type AgentScope } from './agents';
|
|
8
9
|
import type { AgentResult, UsageStats } from './delegate-types';
|
|
9
10
|
|
|
10
11
|
function emptyUsage(): UsageStats {
|
|
@@ -39,14 +40,22 @@ async function writePromptToTempFile(
|
|
|
39
40
|
|
|
40
41
|
export type OnPhaseUpdate = (phaseName: string, agentName: string, result: AgentResult) => void;
|
|
41
42
|
|
|
43
|
+
export interface RunAgentOptions {
|
|
44
|
+
agentScope?: AgentScope;
|
|
45
|
+
cwd?: string;
|
|
46
|
+
onUpdate?: OnPhaseUpdate;
|
|
47
|
+
phaseName?: string;
|
|
48
|
+
signal?: AbortSignal;
|
|
49
|
+
resolvedPaths?: ResolvedPaths;
|
|
50
|
+
}
|
|
51
|
+
|
|
42
52
|
export async function runAgent(
|
|
43
53
|
cwd: string,
|
|
44
54
|
agentName: string,
|
|
45
55
|
task: string,
|
|
46
|
-
|
|
47
|
-
phaseName?: string,
|
|
56
|
+
options: RunAgentOptions = {},
|
|
48
57
|
): Promise<AgentResult> {
|
|
49
|
-
const { agents } =
|
|
58
|
+
const { agents } = discoverAgentsWithPackages(cwd, options.agentScope ?? 'user', options.resolvedPaths);
|
|
50
59
|
const agent = agents.find((a) => a.name === agentName);
|
|
51
60
|
|
|
52
61
|
if (!agent) {
|
|
@@ -92,7 +101,7 @@ export async function runAgent(
|
|
|
92
101
|
const exitCode = await new Promise<number>((resolve) => {
|
|
93
102
|
const invocation = getPiInvocation(args);
|
|
94
103
|
const proc = spawn(invocation.command, invocation.args, {
|
|
95
|
-
cwd,
|
|
104
|
+
cwd: options.cwd ?? cwd,
|
|
96
105
|
shell: false,
|
|
97
106
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
98
107
|
});
|
|
@@ -128,12 +137,14 @@ export async function runAgent(
|
|
|
128
137
|
if (msg.errorMessage) result.errorMessage = msg.errorMessage;
|
|
129
138
|
}
|
|
130
139
|
|
|
131
|
-
if (onUpdate)
|
|
140
|
+
if (options.onUpdate)
|
|
141
|
+
options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
|
|
132
142
|
}
|
|
133
143
|
|
|
134
144
|
if (event.type === 'tool_result_end' && event.message) {
|
|
135
145
|
result.messages.push(event.message as Message);
|
|
136
|
-
if (onUpdate)
|
|
146
|
+
if (options.onUpdate)
|
|
147
|
+
options.onUpdate(options.phaseName ?? 'unknown', agentName, { ...result });
|
|
137
148
|
}
|
|
138
149
|
};
|
|
139
150
|
|
|
@@ -154,6 +165,17 @@ export async function runAgent(
|
|
|
154
165
|
});
|
|
155
166
|
|
|
156
167
|
proc.on('error', () => resolve(1));
|
|
168
|
+
|
|
169
|
+
if (options.signal) {
|
|
170
|
+
const killProc = () => {
|
|
171
|
+
proc.kill('SIGTERM');
|
|
172
|
+
setTimeout(() => {
|
|
173
|
+
if (!proc.killed) proc.kill('SIGKILL');
|
|
174
|
+
}, 5000);
|
|
175
|
+
};
|
|
176
|
+
if (options.signal.aborted) killProc();
|
|
177
|
+
else options.signal.addEventListener('abort', killProc, { once: true });
|
|
178
|
+
}
|
|
157
179
|
});
|
|
158
180
|
|
|
159
181
|
result.exitCode = exitCode;
|
|
@@ -178,8 +200,7 @@ export async function runParallel(
|
|
|
178
200
|
cwd: string,
|
|
179
201
|
agentNames: string[],
|
|
180
202
|
task: string,
|
|
181
|
-
|
|
182
|
-
phaseName?: string,
|
|
203
|
+
options: RunAgentOptions = {},
|
|
183
204
|
): Promise<AgentResult[]> {
|
|
184
205
|
const MAX_CONCURRENCY = 4;
|
|
185
206
|
const results: AgentResult[] = new Array(agentNames.length);
|
|
@@ -191,7 +212,7 @@ export async function runParallel(
|
|
|
191
212
|
while (true) {
|
|
192
213
|
const current = nextIndex++;
|
|
193
214
|
if (current >= agentNames.length) return;
|
|
194
|
-
results[current] = await runAgent(cwd, agentNames[current], task,
|
|
215
|
+
results[current] = await runAgent(cwd, agentNames[current], task, options);
|
|
195
216
|
}
|
|
196
217
|
});
|
|
197
218
|
|
|
@@ -25,13 +25,24 @@ import { StringEnum } from '@mariozechner/pi-ai';
|
|
|
25
25
|
import {
|
|
26
26
|
type ExtensionAPI,
|
|
27
27
|
type ExtensionCommandContext,
|
|
28
|
+
DefaultPackageManager,
|
|
28
29
|
getAgentDir,
|
|
29
30
|
getMarkdownTheme,
|
|
31
|
+
SettingsManager,
|
|
30
32
|
withFileMutationQueue,
|
|
31
33
|
} from '@mariozechner/pi-coding-agent';
|
|
34
|
+
import type { ResolvedPaths } from '@mariozechner/pi-coding-agent';
|
|
32
35
|
import { Container, Markdown, Spacer, Text } from '@mariozechner/pi-tui';
|
|
33
36
|
import { Type } from '@sinclair/typebox';
|
|
34
|
-
import {
|
|
37
|
+
import {
|
|
38
|
+
type AgentConfig,
|
|
39
|
+
type AgentScope,
|
|
40
|
+
type AgentSource,
|
|
41
|
+
bundledAgentsDir,
|
|
42
|
+
discoverAgents,
|
|
43
|
+
discoverAgentsWithPackages,
|
|
44
|
+
} from './agents.js';
|
|
45
|
+
import { formatDelegateUsage, parseDelegateArgs } from './delegate-args.js';
|
|
35
46
|
import { runAgent, runParallel } from './delegate-executor.js';
|
|
36
47
|
import { buildSynthesisPrompt, extractRecentConversation } from './synthesis.js';
|
|
37
48
|
import type {
|
|
@@ -50,6 +61,7 @@ import {
|
|
|
50
61
|
getFinalText,
|
|
51
62
|
pickWorkflow,
|
|
52
63
|
} from './delegate-ui.js';
|
|
64
|
+
import { getWorkflow, suggestWorkflow } from './workflows.js';
|
|
53
65
|
|
|
54
66
|
const MAX_PARALLEL_TASKS = 8;
|
|
55
67
|
const MAX_CONCURRENCY = 4;
|
|
@@ -172,7 +184,7 @@ interface UsageStats {
|
|
|
172
184
|
|
|
173
185
|
interface SingleResult {
|
|
174
186
|
agent: string;
|
|
175
|
-
agentSource:
|
|
187
|
+
agentSource: AgentSource | 'unknown';
|
|
176
188
|
task: string;
|
|
177
189
|
exitCode: number;
|
|
178
190
|
messages: Message[];
|
|
@@ -499,6 +511,26 @@ const SubagentParams = Type.Object({
|
|
|
499
511
|
),
|
|
500
512
|
});
|
|
501
513
|
|
|
514
|
+
/**
|
|
515
|
+
* Try to resolve package paths including the agents resource.
|
|
516
|
+
* Returns null if the pi version does not support ResolvedPaths.agents.
|
|
517
|
+
*/
|
|
518
|
+
async function tryResolvePackagePaths(cwd: string): Promise<ResolvedPaths | undefined> {
|
|
519
|
+
try {
|
|
520
|
+
const agentDir = getAgentDir();
|
|
521
|
+
const settingsManager = SettingsManager.create(cwd, agentDir);
|
|
522
|
+
const packageManager = new DefaultPackageManager({ cwd, agentDir, settingsManager });
|
|
523
|
+
const resolved = await packageManager.resolve();
|
|
524
|
+
// Check if this pi version has agents support
|
|
525
|
+
if ('agents' in resolved && Array.isArray((resolved as Record<string, unknown>).agents)) {
|
|
526
|
+
return resolved;
|
|
527
|
+
}
|
|
528
|
+
} catch {
|
|
529
|
+
// Incompatible pi version or missing API
|
|
530
|
+
}
|
|
531
|
+
return undefined;
|
|
532
|
+
}
|
|
533
|
+
|
|
502
534
|
export default function (pi: ExtensionAPI) {
|
|
503
535
|
pi.registerTool({
|
|
504
536
|
name: 'subagent',
|
|
@@ -513,7 +545,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
513
545
|
|
|
514
546
|
async execute(_toolCallId, params, signal, onUpdate, ctx) {
|
|
515
547
|
const agentScope: AgentScope = params.agentScope ?? 'user';
|
|
516
|
-
const
|
|
548
|
+
const resolvedPaths = await tryResolvePackagePaths(ctx.cwd);
|
|
549
|
+
const discovery = discoverAgentsWithPackages(ctx.cwd, agentScope, resolvedPaths);
|
|
517
550
|
const agents = discovery.agents;
|
|
518
551
|
const confirmProjectAgents = params.confirmProjectAgents ?? true;
|
|
519
552
|
|
|
@@ -1133,6 +1166,8 @@ export default function (pi: ExtensionAPI) {
|
|
|
1133
1166
|
synthesis: string,
|
|
1134
1167
|
previousOutput: string,
|
|
1135
1168
|
ctx: ExtensionCommandContext,
|
|
1169
|
+
agentScope: AgentScope,
|
|
1170
|
+
resolvedPaths?: ResolvedPaths,
|
|
1136
1171
|
): Promise<{ results: AgentResult[]; output: string; aborted: boolean }> {
|
|
1137
1172
|
const task = phase.taskTemplate
|
|
1138
1173
|
.replace(/\{synthesis\}/g, synthesis)
|
|
@@ -1145,17 +1180,20 @@ export default function (pi: ExtensionAPI) {
|
|
|
1145
1180
|
|
|
1146
1181
|
let results: AgentResult[];
|
|
1147
1182
|
if (phase.kind === 'parallel') {
|
|
1148
|
-
results = await runParallel(
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
task,
|
|
1152
|
-
(_phaseName, _agentName, _result) => {
|
|
1183
|
+
results = await runParallel(cwd, phase.agents, task, {
|
|
1184
|
+
agentScope,
|
|
1185
|
+
onUpdate: (_phaseName, _agentName, _result) => {
|
|
1153
1186
|
// Streaming updates happen per-message
|
|
1154
1187
|
},
|
|
1155
|
-
phase.name,
|
|
1156
|
-
|
|
1188
|
+
phaseName: phase.name,
|
|
1189
|
+
resolvedPaths,
|
|
1190
|
+
});
|
|
1157
1191
|
} else {
|
|
1158
|
-
const result = await runAgent(cwd, phase.agents[0], task,
|
|
1192
|
+
const result = await runAgent(cwd, phase.agents[0], task, {
|
|
1193
|
+
agentScope,
|
|
1194
|
+
phaseName: phase.name,
|
|
1195
|
+
resolvedPaths,
|
|
1196
|
+
});
|
|
1159
1197
|
results = [result];
|
|
1160
1198
|
}
|
|
1161
1199
|
|
|
@@ -1173,7 +1211,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1173
1211
|
const output = combineParallelOutputs(results);
|
|
1174
1212
|
ctx.ui.notify(formatPhaseHeader(phase.name, 'done'), 'info');
|
|
1175
1213
|
|
|
1176
|
-
if (phase.requiresConfirmation) {
|
|
1214
|
+
if (phase.requiresConfirmation && ctx.hasUI) {
|
|
1177
1215
|
const planText = output;
|
|
1178
1216
|
const proceed = await confirmPlan(ctx, planText);
|
|
1179
1217
|
if (!proceed) {
|
|
@@ -1291,24 +1329,29 @@ export default function (pi: ExtensionAPI) {
|
|
|
1291
1329
|
});
|
|
1292
1330
|
|
|
1293
1331
|
pi.registerCommand('delegate', {
|
|
1294
|
-
description:
|
|
1332
|
+
description:
|
|
1333
|
+
'Orchestrate subagent workflows — supports --scope, --workflow, and project-local agents',
|
|
1295
1334
|
handler: async (args, ctx) => {
|
|
1296
|
-
const
|
|
1335
|
+
const parsed = parseDelegateArgs(args);
|
|
1336
|
+
if (!parsed.ok) {
|
|
1337
|
+
ctx.ui.notify(parsed.error, 'warning');
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
const { explicitTask, agentScope, workflowId, confirmProjectAgents } = parsed.options;
|
|
1342
|
+
const resolvedPaths = await tryResolvePackagePaths(ctx.cwd);
|
|
1297
1343
|
|
|
1298
1344
|
// Step 1: Synthesize
|
|
1299
1345
|
const conversation = extractRecentConversation(ctx);
|
|
1300
1346
|
if (!conversation.trim() && !explicitTask) {
|
|
1301
|
-
ctx.ui.notify(
|
|
1302
|
-
'No conversation context and no task specified. Usage: /delegate [task]',
|
|
1303
|
-
'warning',
|
|
1304
|
-
);
|
|
1347
|
+
ctx.ui.notify(`No conversation context and no task specified.\n\n${formatDelegateUsage()}`, 'warning');
|
|
1305
1348
|
return;
|
|
1306
1349
|
}
|
|
1307
1350
|
|
|
1308
1351
|
const prompt = buildSynthesisPrompt(conversation, explicitTask);
|
|
1309
1352
|
ctx.ui.notify('⏳ Synthesizing task from conversation...', 'info');
|
|
1310
1353
|
|
|
1311
|
-
const synthResult = await runAgent(ctx.cwd, 'planner', prompt);
|
|
1354
|
+
const synthResult = await runAgent(ctx.cwd, 'planner', prompt, { agentScope, resolvedPaths });
|
|
1312
1355
|
const synthesis = getFinalText(synthResult);
|
|
1313
1356
|
|
|
1314
1357
|
if (!synthesis.trim()) {
|
|
@@ -1317,19 +1360,46 @@ export default function (pi: ExtensionAPI) {
|
|
|
1317
1360
|
}
|
|
1318
1361
|
|
|
1319
1362
|
// Step 2: Confirm synthesis
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1363
|
+
if (ctx.hasUI) {
|
|
1364
|
+
const synthOk = await confirmSynthesis(ctx, synthesis);
|
|
1365
|
+
if (!synthOk) {
|
|
1366
|
+
ctx.ui.notify('Delegate cancelled.', 'info');
|
|
1367
|
+
return;
|
|
1368
|
+
}
|
|
1324
1369
|
}
|
|
1325
1370
|
|
|
1326
1371
|
// Step 3: Pick workflow
|
|
1327
|
-
const workflow =
|
|
1372
|
+
const workflow = workflowId
|
|
1373
|
+
? getWorkflow(workflowId)
|
|
1374
|
+
: ctx.hasUI
|
|
1375
|
+
? await pickWorkflow(ctx, synthesis)
|
|
1376
|
+
: getWorkflow(suggestWorkflow(synthesis));
|
|
1328
1377
|
if (!workflow) {
|
|
1329
1378
|
ctx.ui.notify('Delegate cancelled — no workflow selected.', 'info');
|
|
1330
1379
|
return;
|
|
1331
1380
|
}
|
|
1332
1381
|
|
|
1382
|
+
if ((agentScope === 'project' || agentScope === 'both') && confirmProjectAgents && ctx.hasUI) {
|
|
1383
|
+
const discovery = discoverAgentsWithPackages(ctx.cwd, agentScope, resolvedPaths);
|
|
1384
|
+
const requestedProjectAgents = workflow.phases
|
|
1385
|
+
.flatMap((phase) => phase.agents)
|
|
1386
|
+
.map((name) => discovery.agents.find((agent) => agent.name === name))
|
|
1387
|
+
.filter((agent): agent is AgentConfig => agent?.source === 'project');
|
|
1388
|
+
|
|
1389
|
+
if (requestedProjectAgents.length > 0) {
|
|
1390
|
+
const names = Array.from(new Set(requestedProjectAgents.map((agent) => agent.name))).join(', ');
|
|
1391
|
+
const dir = discovery.projectAgentsDir ?? '(unknown)';
|
|
1392
|
+
const ok = await ctx.ui.confirm(
|
|
1393
|
+
'Run project-local agents?',
|
|
1394
|
+
`Agents: ${names}\nSource: ${dir}\n\nProject agents are repo-controlled. Only continue for trusted repositories.`,
|
|
1395
|
+
);
|
|
1396
|
+
if (!ok) {
|
|
1397
|
+
ctx.ui.notify('Delegate cancelled — project-local agents not approved.', 'info');
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1333
1403
|
// Step 4: Execute phases
|
|
1334
1404
|
const state: DelegateState = {
|
|
1335
1405
|
synthesis,
|
|
@@ -1340,10 +1410,18 @@ export default function (pi: ExtensionAPI) {
|
|
|
1340
1410
|
|
|
1341
1411
|
let previousOutput = '';
|
|
1342
1412
|
|
|
1343
|
-
ctx.ui.notify(`Starting workflow: ${workflow.label}`, 'info');
|
|
1413
|
+
ctx.ui.notify(`Starting workflow: ${workflow.label} [${agentScope}]`, 'info');
|
|
1344
1414
|
|
|
1345
1415
|
for (const phaseDef of workflow.phases) {
|
|
1346
|
-
const phaseResult = await executePhase(
|
|
1416
|
+
const phaseResult = await executePhase(
|
|
1417
|
+
ctx.cwd,
|
|
1418
|
+
phaseDef,
|
|
1419
|
+
synthesis,
|
|
1420
|
+
previousOutput,
|
|
1421
|
+
ctx,
|
|
1422
|
+
agentScope,
|
|
1423
|
+
resolvedPaths,
|
|
1424
|
+
);
|
|
1347
1425
|
|
|
1348
1426
|
const phase: PhaseResult = {
|
|
1349
1427
|
name: phaseDef.name,
|
|
@@ -1375,6 +1453,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1375
1453
|
display: true,
|
|
1376
1454
|
details: {
|
|
1377
1455
|
workflow: workflow.id,
|
|
1456
|
+
agentScope,
|
|
1378
1457
|
phaseCount: state.phases.length,
|
|
1379
1458
|
totalUsage: state.totalUsage,
|
|
1380
1459
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dreki-gg/pi-subagent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Subagent tool and delegate orchestration for pi — isolated agents, parallel scouts, planning gates, and workflow presets",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package"
|
|
@@ -28,6 +28,9 @@
|
|
|
28
28
|
],
|
|
29
29
|
"prompts": [
|
|
30
30
|
"./prompts"
|
|
31
|
+
],
|
|
32
|
+
"agents": [
|
|
33
|
+
"./agents"
|
|
31
34
|
]
|
|
32
35
|
},
|
|
33
36
|
"devDependencies": {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: spawn-subagents
|
|
3
|
+
description: Use conversational subagent orchestration with the `subagent` tool. Trigger when the user says spawn, spin up, fan out, parallelize, send to reviewer, use scout/planner/worker, or wants specialized agents to investigate, plan, implement, or review.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Use this skill when the user wants agents spawned conversationally.
|
|
7
|
+
|
|
8
|
+
Default behavior:
|
|
9
|
+
- Prefer the `subagent` tool directly.
|
|
10
|
+
- Do **not** default to `/delegate`.
|
|
11
|
+
- Use `/delegate` only when the user explicitly wants a gated workflow, workflow picker, or plan approval step.
|
|
12
|
+
|
|
13
|
+
Strong triggers:
|
|
14
|
+
- "spawn a scout"
|
|
15
|
+
- "fan this out"
|
|
16
|
+
- "run reviewer on this"
|
|
17
|
+
- "have planner make a plan first"
|
|
18
|
+
- "send docs-scout to check the docs"
|
|
19
|
+
- "parallelize discovery"
|
|
20
|
+
|
|
21
|
+
Patterns:
|
|
22
|
+
|
|
23
|
+
## 1. Single specialist
|
|
24
|
+
Use one agent when the task is narrow.
|
|
25
|
+
- `scout` for repo reconnaissance
|
|
26
|
+
- `docs-scout` for docs lookup
|
|
27
|
+
- `planner` for a concrete plan
|
|
28
|
+
- `worker` for implementation
|
|
29
|
+
- `reviewer` for quality/security review
|
|
30
|
+
|
|
31
|
+
## 2. Parallel recon
|
|
32
|
+
Use parallel mode for noisy discovery.
|
|
33
|
+
- Run `scout` + `docs-scout` in parallel when both code and docs matter.
|
|
34
|
+
- Keep parallel tasks non-overlapping.
|
|
35
|
+
- Return a compact synthesis to the main thread.
|
|
36
|
+
|
|
37
|
+
## 3. Plan then implement
|
|
38
|
+
Use chain mode when the user wants safe sequencing.
|
|
39
|
+
1. `scout` and optionally `docs-scout`
|
|
40
|
+
2. `planner`
|
|
41
|
+
3. `worker`
|
|
42
|
+
4. optional `reviewer`
|
|
43
|
+
|
|
44
|
+
## 4. Review loop
|
|
45
|
+
Use after implementation or when the user asks for a second opinion.
|
|
46
|
+
1. `reviewer`
|
|
47
|
+
2. main agent applies fixes directly or sends focused follow-up to `worker`
|
|
48
|
+
|
|
49
|
+
Execution rules:
|
|
50
|
+
- Parallelize reconnaissance, not conflicting edits.
|
|
51
|
+
- Prefer one `worker` unless file ownership is clearly partitioned.
|
|
52
|
+
- Use `docs-scout` when external library/framework details matter.
|
|
53
|
+
- Pass previous outputs verbatim or as a tight structured summary.
|
|
54
|
+
|
|
55
|
+
When reporting back:
|
|
56
|
+
- say which subagents ran
|
|
57
|
+
- summarize what each contributed
|
|
58
|
+
- keep the main thread focused on conclusions, not raw logs
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: write-an-agent
|
|
3
|
+
description: Writes or refines concise pi subagent definitions for this repo, keeping each agent under 100 lines with a sharp role, tool policy, and output contract. Use when creating, rewriting, or tightening agent prompts in `.pi/agents/` or `packages/subagent/agents/`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Write an Agent
|
|
7
|
+
|
|
8
|
+
Goal: produce a high-signal agent file in fewer than 100 lines.
|
|
9
|
+
|
|
10
|
+
## Use this for
|
|
11
|
+
- new repo-local agents in `.pi/agents/`
|
|
12
|
+
- bundled package agents in `packages/subagent/agents/`
|
|
13
|
+
- tightening bloated prompts into a crisp reusable worker
|
|
14
|
+
|
|
15
|
+
## Design rules
|
|
16
|
+
1. One job only. If the agent does two unrelated things, split it.
|
|
17
|
+
2. One tool policy. Give the minimum tools needed.
|
|
18
|
+
3. One output contract. Tell the next agent exactly what comes back.
|
|
19
|
+
4. Keep the whole file under 100 lines.
|
|
20
|
+
5. If the prompt needs more than 100 lines, write a skill instead.
|
|
21
|
+
|
|
22
|
+
## File shape
|
|
23
|
+
```md
|
|
24
|
+
---
|
|
25
|
+
name: agent-name
|
|
26
|
+
description: What it does. Use when ...
|
|
27
|
+
tools: read, grep, find, ls
|
|
28
|
+
model: openai/gpt-5.4-mini
|
|
29
|
+
thinking: medium
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
You are the <agent-name>.
|
|
33
|
+
|
|
34
|
+
Mission:
|
|
35
|
+
- outcome
|
|
36
|
+
|
|
37
|
+
Rules:
|
|
38
|
+
1. boundary
|
|
39
|
+
2. boundary
|
|
40
|
+
|
|
41
|
+
Output:
|
|
42
|
+
## Section
|
|
43
|
+
- exact shape
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## Authoring workflow
|
|
47
|
+
1. Name the role.
|
|
48
|
+
2. Write one-sentence description with trigger language: "Use when ...".
|
|
49
|
+
3. Pick the smallest tool list.
|
|
50
|
+
4. Pick a cheap model for scouts, stronger model for planner/reviewer/worker.
|
|
51
|
+
5. Write 3-6 rules max.
|
|
52
|
+
6. Define output sections for handoff.
|
|
53
|
+
7. Count lines. Trim anything decorative.
|
|
54
|
+
|
|
55
|
+
## Repo conventions
|
|
56
|
+
- Repo-local overrides belong in `.pi/agents/`.
|
|
57
|
+
- Bundled reusable agents belong in `packages/subagent/agents/`.
|
|
58
|
+
- For this repo, default roles are `scout`, `docs-scout`, `planner`, `worker`, `reviewer`.
|
|
59
|
+
- Prefer local pi docs before external docs when writing `docs-scout`.
|
|
60
|
+
- Mention validation commands in planner/worker/reviewer when package behavior changes.
|
|
61
|
+
|
|
62
|
+
## Review checklist
|
|
63
|
+
- Is the role narrower than a general engineer?
|
|
64
|
+
- Would another agent know exactly when to use it?
|
|
65
|
+
- Are the tools minimal?
|
|
66
|
+
- Is the handoff structured?
|
|
67
|
+
- Is the file under 100 lines?
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: subagent-workflows
|
|
3
|
-
description: Use explicit subagent workflows for planning or implementation after a grill/design session. Runs parallel scouts, then planner, then optional worker/reviewer.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
Use this skill when the user wants to execute a plan with subagents, parallelize discovery intelligently, or asks to hand work off after a design/grill session.
|
|
7
|
-
|
|
8
|
-
Principles:
|
|
9
|
-
- Use the `subagent` tool explicitly; do not improvise ad hoc parallelism.
|
|
10
|
-
- Parallelize reconnaissance, not conflicting edits.
|
|
11
|
-
- Prefer one planner synthesis step after parallel scouts.
|
|
12
|
-
- Prefer one worker unless file ownership can be partitioned safely.
|
|
13
|
-
- Use `docs-scout` whenever library/framework docs matter.
|
|
14
|
-
|
|
15
|
-
Recommended workflows:
|
|
16
|
-
|
|
17
|
-
## 1. Scout and plan
|
|
18
|
-
Use when the user wants a concrete implementation plan before coding.
|
|
19
|
-
|
|
20
|
-
Run `subagent` in parallel mode with two tasks:
|
|
21
|
-
- `scout` for codebase reconnaissance
|
|
22
|
-
- `docs-scout` for library/framework docs if docs are relevant
|
|
23
|
-
|
|
24
|
-
Then run `subagent` in chain or single mode with `planner`, feeding it the scout outputs.
|
|
25
|
-
|
|
26
|
-
## 2. Implement from a grilled plan
|
|
27
|
-
Use when the design is already clarified and the user wants execution.
|
|
28
|
-
|
|
29
|
-
Recommended sequence:
|
|
30
|
-
1. Parallel scouts (`scout` + optionally `docs-scout`)
|
|
31
|
-
2. `planner` synthesis
|
|
32
|
-
3. `worker` implementation
|
|
33
|
-
4. Optional `reviewer`
|
|
34
|
-
|
|
35
|
-
## 3. Review-oriented loop
|
|
36
|
-
Use when the user wants implementation with a final quality pass.
|
|
37
|
-
|
|
38
|
-
Recommended sequence:
|
|
39
|
-
1. `worker`
|
|
40
|
-
2. `reviewer`
|
|
41
|
-
3. Main agent decides whether to apply fixes directly or run another `worker`
|
|
42
|
-
|
|
43
|
-
Execution guidance:
|
|
44
|
-
- Keep parallel scouts focused on different concerns.
|
|
45
|
-
- Do not run multiple workers against the same file set unless boundaries are explicit.
|
|
46
|
-
- If docs are required, use `docs-scout` instead of relying on memory.
|
|
47
|
-
- When handing off between subagents, pass the previous output verbatim or clearly summarized.
|
|
48
|
-
|
|
49
|
-
When reporting back to the user:
|
|
50
|
-
- Say which subagents ran
|
|
51
|
-
- Summarize what each contributed
|
|
52
|
-
- Present the synthesized plan or implementation result clearly
|