@haoyiyin/workflow 0.2.2 → 0.2.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/package.json +9 -8
- package/src/agents/contracts.ts +559 -0
- package/src/agents/dispatcher-enhanced.ts +350 -0
- package/src/agents/dispatcher.ts +680 -0
- package/src/agents/index.ts +48 -0
- package/src/agents/resilience.ts +255 -0
- package/src/agents/token-budget.ts +83 -0
- package/src/agents/types.ts +73 -0
- package/src/guard/main-agent.ts +245 -0
- package/src/hooks/builtin/index.ts +8 -0
- package/src/hooks/builtin/on-error.ts +23 -0
- package/src/hooks/builtin/post-execute.ts +40 -0
- package/src/hooks/builtin/post-plan.ts +23 -0
- package/src/hooks/builtin/pre-execute.ts +30 -0
- package/src/hooks/builtin/pre-plan.ts +26 -0
- package/src/hooks/index.ts +7 -0
- package/src/hooks/loader.ts +98 -0
- package/src/hooks/manager.ts +99 -0
- package/src/hooks/types-enhanced.ts +38 -0
- package/src/hooks/types.ts +35 -0
- package/src/index.ts +127 -0
- package/src/persistence/index.ts +17 -0
- package/src/persistence/plan-md.ts +141 -0
- package/src/persistence/state-md.ts +167 -0
- package/src/persistence/types.ts +89 -0
- package/src/router/classifier.ts +610 -0
- package/src/router/guard.ts +483 -0
- package/src/router/index.ts +22 -0
- package/src/router/router.ts +108 -0
- package/src/router/types.ts +127 -0
- package/src/skills/agents-md/SKILL.md +45 -0
- package/src/skills/agents-md/index.ts +33 -0
- package/src/skills/execute-plan/SKILL.md +60 -0
- package/src/skills/execute-plan/index.ts +970 -0
- package/src/skills/index.ts +13 -0
- package/src/skills/quick-task/SKILL.md +54 -0
- package/src/skills/quick-task/index.ts +346 -0
- package/src/skills/registry.ts +59 -0
- package/src/skills/review-diff/SKILL.md +53 -0
- package/src/skills/review-diff/index.ts +394 -0
- package/src/skills/skill.ts +59 -0
- package/src/skills/systematic-debugging/SKILL.md +56 -0
- package/src/skills/systematic-debugging/index.ts +404 -0
- package/src/skills/tdd/SKILL.md +52 -0
- package/src/skills/tdd/index.ts +409 -0
- package/src/skills/to-plan/SKILL.md +56 -0
- package/src/skills/to-plan/index-enhanced.ts +551 -0
- package/src/skills/to-plan/index.ts +586 -0
- package/src/skills/types.ts +47 -0
- package/src/state/cleanup.ts +118 -0
- package/src/state/index.ts +8 -0
- package/src/state/manager.ts +96 -0
- package/src/state/persistence.ts +77 -0
- package/src/state/types.ts +30 -0
- package/src/state/validator.ts +78 -0
- package/src/types.ts +102 -0
- package/src/utils/compress.ts +347 -0
- package/src/utils/git.ts +82 -0
- package/src/utils/index.ts +6 -0
- package/src/utils/logger.ts +23 -0
- package/src/utils/paths.ts +55 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TDD Skill - Enforces RED/GREEN/REFACTOR cycle via subagent dispatch
|
|
3
|
+
*
|
|
4
|
+
* Use case: Implement feature with test-first approach
|
|
5
|
+
* Pattern: RED (write failing test) → GREEN (minimal implementation) →
|
|
6
|
+
* REFACTOR (improve while green) → VERIFY (full suite)
|
|
7
|
+
*
|
|
8
|
+
* Spawns implementer subagent with TDD contract at each phase.
|
|
9
|
+
* Enforces the cycle: no implementation before a failing test exists.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { z } from 'zod'
|
|
13
|
+
import { Skill } from '../skill.js'
|
|
14
|
+
import type { SkillContext } from '../types.js'
|
|
15
|
+
import { createDispatcher } from '../../agents/dispatcher.js'
|
|
16
|
+
import { createMainAgentGuard } from '../../guard/main-agent.js'
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Schemas
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
const TDDInputSchema = z.object({
|
|
23
|
+
behavior: z.string().min(1, 'Behavior to implement is required'),
|
|
24
|
+
testFile: z.string().optional(),
|
|
25
|
+
targetFile: z.string().min(1, 'Target implementation file is required'),
|
|
26
|
+
testLevel: z
|
|
27
|
+
.enum(['unit', 'integration', 'e2e', 'contract'])
|
|
28
|
+
.default('unit'),
|
|
29
|
+
model: z.string().optional(),
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
const PhaseResultSchema = z.object({
|
|
33
|
+
phase: z.enum(['red', 'green', 'refactor']),
|
|
34
|
+
status: z.enum(['pass', 'fail', 'skipped']),
|
|
35
|
+
command: z.string(),
|
|
36
|
+
evidence: z.string(),
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
const TDDOutputSchema = z.object({
|
|
40
|
+
status: z.enum(['success', 'failure', 'invalid-red']),
|
|
41
|
+
phases: z.array(PhaseResultSchema),
|
|
42
|
+
broaderVerification: z.object({
|
|
43
|
+
command: z.string(),
|
|
44
|
+
result: z.enum(['PASS', 'FAIL', 'NOT_RUN']),
|
|
45
|
+
}),
|
|
46
|
+
filesModified: z.array(z.string()),
|
|
47
|
+
summary: z.string(),
|
|
48
|
+
tokensUsed: z.number(),
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
type TDDInput = z.infer<typeof TDDInputSchema>
|
|
52
|
+
type TDDOutput = z.infer<typeof TDDOutputSchema>
|
|
53
|
+
type PhaseResult = z.infer<typeof PhaseResultSchema>
|
|
54
|
+
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
// Prompt builders (pure functions)
|
|
57
|
+
// ---------------------------------------------------------------------------
|
|
58
|
+
|
|
59
|
+
function buildRedPrompt(
|
|
60
|
+
behavior: string,
|
|
61
|
+
targetFile: string,
|
|
62
|
+
testFile: string | undefined,
|
|
63
|
+
testLevel: string,
|
|
64
|
+
): string {
|
|
65
|
+
return [
|
|
66
|
+
`## TDD Phase: RED - Write Failing Test`,
|
|
67
|
+
'',
|
|
68
|
+
`**Behavior**: ${behavior}`,
|
|
69
|
+
`**Test Level**: ${testLevel}`,
|
|
70
|
+
`**Target File**: ${targetFile}`,
|
|
71
|
+
testFile ? `**Test File**: ${testFile}` : '',
|
|
72
|
+
'',
|
|
73
|
+
'## Instructions',
|
|
74
|
+
'',
|
|
75
|
+
'1. Read the target file to understand current state',
|
|
76
|
+
'2. Write a minimal, focused test that MUST fail',
|
|
77
|
+
'3. The test should describe the expected behavior precisely',
|
|
78
|
+
'4. Run the test and confirm it FAILS for the RIGHT reason',
|
|
79
|
+
'',
|
|
80
|
+
'## Validation',
|
|
81
|
+
'',
|
|
82
|
+
'- Test must fail because the behavior is NOT yet implemented',
|
|
83
|
+
'- If the test PASSES immediately, the behavior may already exist',
|
|
84
|
+
'- If test fails due to setup/syntax error, fix the test first',
|
|
85
|
+
'',
|
|
86
|
+
'## Anti-Goals',
|
|
87
|
+
'',
|
|
88
|
+
'- Do NOT implement the feature',
|
|
89
|
+
'- Do NOT write more than one test',
|
|
90
|
+
'- Do NOT modify the target file',
|
|
91
|
+
'',
|
|
92
|
+
'## Output',
|
|
93
|
+
'',
|
|
94
|
+
'Report: test file path, test command used, test output (must show FAIL).',
|
|
95
|
+
'If test unexpectedly passes, output: INVALID_RED',
|
|
96
|
+
]
|
|
97
|
+
.filter(Boolean)
|
|
98
|
+
.join('\n')
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function buildGreenPrompt(
|
|
102
|
+
behavior: string,
|
|
103
|
+
targetFile: string,
|
|
104
|
+
testFile: string | undefined,
|
|
105
|
+
redEvidence: string,
|
|
106
|
+
): string {
|
|
107
|
+
return [
|
|
108
|
+
`## TDD Phase: GREEN - Make Test Pass`,
|
|
109
|
+
'',
|
|
110
|
+
`**Behavior**: ${behavior}`,
|
|
111
|
+
`**Target File**: ${targetFile}`,
|
|
112
|
+
testFile ? `**Test File**: ${testFile}` : '',
|
|
113
|
+
'',
|
|
114
|
+
'## RED Phase Evidence',
|
|
115
|
+
redEvidence.slice(0, 500),
|
|
116
|
+
'',
|
|
117
|
+
'## Instructions',
|
|
118
|
+
'',
|
|
119
|
+
'1. Read the failing test to understand what is expected',
|
|
120
|
+
'2. Write the MINIMAL code to make the test pass',
|
|
121
|
+
'3. Code can be hacky, hardcoded, or ugly — refactor comes next',
|
|
122
|
+
'4. Run the test and confirm it PASSES',
|
|
123
|
+
'',
|
|
124
|
+
'## Anti-Goals',
|
|
125
|
+
'',
|
|
126
|
+
'- Do NOT refactor or prettify the code',
|
|
127
|
+
'- Do NOT add features beyond what the test checks',
|
|
128
|
+
'- Do NOT change the test',
|
|
129
|
+
'- Do NOT write additional tests',
|
|
130
|
+
'',
|
|
131
|
+
'## Output',
|
|
132
|
+
'',
|
|
133
|
+
'Report: implementation summary, test command, test output (must show PASS).',
|
|
134
|
+
].join('\n')
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function buildRefactorPrompt(
|
|
138
|
+
targetFile: string,
|
|
139
|
+
): string {
|
|
140
|
+
return [
|
|
141
|
+
`## TDD Phase: REFACTOR - Clean Up`,
|
|
142
|
+
'',
|
|
143
|
+
`**Target File**: ${targetFile}`,
|
|
144
|
+
'',
|
|
145
|
+
'## Instructions',
|
|
146
|
+
'',
|
|
147
|
+
'1. Read the current implementation',
|
|
148
|
+
'2. Improve code quality: remove duplication, better naming, extract helpers',
|
|
149
|
+
'3. Run tests after EACH change to stay green',
|
|
150
|
+
'4. Run the full test suite at the end',
|
|
151
|
+
'',
|
|
152
|
+
'## Allowed',
|
|
153
|
+
'',
|
|
154
|
+
'- Rename variables/functions for clarity',
|
|
155
|
+
'- Extract repeated logic into helper functions',
|
|
156
|
+
'- Add type annotations',
|
|
157
|
+
'- Reorganize code for readability',
|
|
158
|
+
'',
|
|
159
|
+
'## Anti-Goals',
|
|
160
|
+
'',
|
|
161
|
+
'- Do NOT change behavior',
|
|
162
|
+
'- Do NOT add new features',
|
|
163
|
+
'- Do NOT modify test expectations',
|
|
164
|
+
'- Do NOT break any test',
|
|
165
|
+
'',
|
|
166
|
+
'## Output',
|
|
167
|
+
'',
|
|
168
|
+
'Report: what was refactored, test command, test output (must show ALL PASS).',
|
|
169
|
+
].join('\n')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// Skill class
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
|
|
176
|
+
export class TDDSkill extends Skill<TDDInput, TDDOutput> {
|
|
177
|
+
constructor() {
|
|
178
|
+
super({
|
|
179
|
+
name: 'tdd',
|
|
180
|
+
description:
|
|
181
|
+
'Enforce RED/GREEN/REFACTOR TDD cycle with isolated implementer subagents',
|
|
182
|
+
requires: [],
|
|
183
|
+
inputSchema: TDDInputSchema as z.ZodType<TDDInput>,
|
|
184
|
+
outputSchema: TDDOutputSchema,
|
|
185
|
+
})
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
async execute(
|
|
189
|
+
input: TDDInput,
|
|
190
|
+
context: SkillContext,
|
|
191
|
+
): Promise<TDDOutput> {
|
|
192
|
+
const { config, logger } = context
|
|
193
|
+
const dispatcher = createDispatcher(logger)
|
|
194
|
+
const guard = createMainAgentGuard({}, logger)
|
|
195
|
+
|
|
196
|
+
const phases: PhaseResult[] = []
|
|
197
|
+
const filesModified: string[] = []
|
|
198
|
+
let totalTokens = 0
|
|
199
|
+
|
|
200
|
+
guard.activateEmbargo()
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
// ---- Phase 1: RED - Write failing test ----
|
|
204
|
+
logger.info(`[tdd] RED phase: writing failing test for "${input.behavior}"`)
|
|
205
|
+
const redResult = await dispatcher.dispatch(
|
|
206
|
+
{
|
|
207
|
+
role: 'implementer',
|
|
208
|
+
model: input.model || config.defaultModel,
|
|
209
|
+
isolation: 'worktree',
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
permissions: {
|
|
213
|
+
readFiles: true,
|
|
214
|
+
searchCode: false,
|
|
215
|
+
runCommands: true,
|
|
216
|
+
writeFiles: true,
|
|
217
|
+
gitOperations: false,
|
|
218
|
+
},
|
|
219
|
+
prompt: buildRedPrompt(
|
|
220
|
+
input.behavior,
|
|
221
|
+
input.targetFile,
|
|
222
|
+
input.testFile,
|
|
223
|
+
input.testLevel,
|
|
224
|
+
),
|
|
225
|
+
owns: input.testFile ? [input.testFile] : [],
|
|
226
|
+
reads: [input.targetFile],
|
|
227
|
+
},
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
totalTokens += redResult.tokensUsed
|
|
231
|
+
|
|
232
|
+
if (redResult.output.includes('INVALID_RED')) {
|
|
233
|
+
return {
|
|
234
|
+
status: 'invalid-red',
|
|
235
|
+
phases,
|
|
236
|
+
broaderVerification: { command: '', result: 'NOT_RUN' },
|
|
237
|
+
filesModified,
|
|
238
|
+
summary: 'RED phase invalid: behavior may already exist or test is misconfigured',
|
|
239
|
+
tokensUsed: totalTokens,
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (redResult.status !== 'success') {
|
|
244
|
+
phases.push({
|
|
245
|
+
phase: 'red',
|
|
246
|
+
status: 'fail',
|
|
247
|
+
command: '',
|
|
248
|
+
evidence: redResult.errors.join(', '),
|
|
249
|
+
})
|
|
250
|
+
return {
|
|
251
|
+
status: 'failure',
|
|
252
|
+
phases,
|
|
253
|
+
broaderVerification: { command: '', result: 'NOT_RUN' },
|
|
254
|
+
filesModified,
|
|
255
|
+
summary: `RED phase failed: ${redResult.errors.join(', ')}`,
|
|
256
|
+
tokensUsed: totalTokens,
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
phases.push({
|
|
261
|
+
phase: 'red',
|
|
262
|
+
status: 'pass',
|
|
263
|
+
command: '(test runner)',
|
|
264
|
+
evidence: redResult.output.slice(0, 300),
|
|
265
|
+
})
|
|
266
|
+
if (input.testFile) filesModified.push(input.testFile)
|
|
267
|
+
|
|
268
|
+
// ---- Phase 2: GREEN - Make test pass ----
|
|
269
|
+
logger.info('[tdd] GREEN phase: implementing minimal code')
|
|
270
|
+
const greenResult = await dispatcher.dispatch(
|
|
271
|
+
{
|
|
272
|
+
role: 'implementer',
|
|
273
|
+
model: input.model || config.defaultModel,
|
|
274
|
+
isolation: 'worktree',
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
permissions: {
|
|
278
|
+
readFiles: true,
|
|
279
|
+
searchCode: false,
|
|
280
|
+
runCommands: true,
|
|
281
|
+
writeFiles: true,
|
|
282
|
+
gitOperations: false,
|
|
283
|
+
},
|
|
284
|
+
prompt: buildGreenPrompt(
|
|
285
|
+
input.behavior,
|
|
286
|
+
input.targetFile,
|
|
287
|
+
input.testFile,
|
|
288
|
+
redResult.output,
|
|
289
|
+
),
|
|
290
|
+
owns: [input.targetFile],
|
|
291
|
+
reads: [],
|
|
292
|
+
},
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
totalTokens += greenResult.tokensUsed
|
|
296
|
+
|
|
297
|
+
if (greenResult.status !== 'success') {
|
|
298
|
+
phases.push({
|
|
299
|
+
phase: 'green',
|
|
300
|
+
status: 'fail',
|
|
301
|
+
command: '',
|
|
302
|
+
evidence: greenResult.errors.join(', '),
|
|
303
|
+
})
|
|
304
|
+
return {
|
|
305
|
+
status: 'failure',
|
|
306
|
+
phases,
|
|
307
|
+
broaderVerification: { command: '', result: 'NOT_RUN' },
|
|
308
|
+
filesModified,
|
|
309
|
+
summary: `GREEN phase failed: ${greenResult.errors.join(', ')}`,
|
|
310
|
+
tokensUsed: totalTokens,
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
phases.push({
|
|
315
|
+
phase: 'green',
|
|
316
|
+
status: 'pass',
|
|
317
|
+
command: '(test runner)',
|
|
318
|
+
evidence: greenResult.output.slice(0, 300),
|
|
319
|
+
})
|
|
320
|
+
filesModified.push(input.targetFile)
|
|
321
|
+
|
|
322
|
+
// ---- Phase 3: REFACTOR - Clean up while staying green ----
|
|
323
|
+
logger.info('[tdd] REFACTOR phase: improving code quality')
|
|
324
|
+
const refactorResult = await dispatcher.dispatch(
|
|
325
|
+
{
|
|
326
|
+
role: 'implementer',
|
|
327
|
+
model: input.model || config.defaultModel,
|
|
328
|
+
isolation: 'worktree',
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
permissions: {
|
|
332
|
+
readFiles: true,
|
|
333
|
+
searchCode: false,
|
|
334
|
+
runCommands: true,
|
|
335
|
+
writeFiles: true,
|
|
336
|
+
gitOperations: false,
|
|
337
|
+
},
|
|
338
|
+
prompt: buildRefactorPrompt(input.targetFile),
|
|
339
|
+
owns: [input.targetFile],
|
|
340
|
+
reads: [],
|
|
341
|
+
},
|
|
342
|
+
)
|
|
343
|
+
|
|
344
|
+
totalTokens += refactorResult.tokensUsed
|
|
345
|
+
|
|
346
|
+
phases.push({
|
|
347
|
+
phase: 'refactor',
|
|
348
|
+
status: refactorResult.status === 'success' ? 'pass' : 'skipped',
|
|
349
|
+
command: '(test runner)',
|
|
350
|
+
evidence: refactorResult.output.slice(0, 300),
|
|
351
|
+
})
|
|
352
|
+
|
|
353
|
+
// ---- Phase 4: Broader verification ----
|
|
354
|
+
logger.info('[tdd] Running broader verification')
|
|
355
|
+
const verifyResult = await dispatcher.dispatch(
|
|
356
|
+
{
|
|
357
|
+
role: 'verifier',
|
|
358
|
+
model: input.model || config.defaultModel,
|
|
359
|
+
},
|
|
360
|
+
{
|
|
361
|
+
permissions: {
|
|
362
|
+
readFiles: false,
|
|
363
|
+
searchCode: false,
|
|
364
|
+
runCommands: true,
|
|
365
|
+
writeFiles: false,
|
|
366
|
+
gitOperations: false,
|
|
367
|
+
},
|
|
368
|
+
prompt: [
|
|
369
|
+
'Run broader verification for the TDD implementation:',
|
|
370
|
+
'',
|
|
371
|
+
`Behavior: ${input.behavior}`,
|
|
372
|
+
`Target: ${input.targetFile}`,
|
|
373
|
+
'',
|
|
374
|
+
'1. Run the full test suite (not just the new test)',
|
|
375
|
+
'2. Check for regressions',
|
|
376
|
+
'3. Verify the behavior works end-to-end if applicable',
|
|
377
|
+
'',
|
|
378
|
+
'Return: command executed, exit code, summary of results.',
|
|
379
|
+
].join('\n'),
|
|
380
|
+
owns: [],
|
|
381
|
+
reads: [],
|
|
382
|
+
},
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
totalTokens += verifyResult.tokensUsed
|
|
386
|
+
|
|
387
|
+
const redStatus = phases[0]?.status ?? 'fail'
|
|
388
|
+
const greenStatus = phases[1]?.status ?? 'fail'
|
|
389
|
+
const refactorStatus = phases[2]?.status ?? 'skipped'
|
|
390
|
+
|
|
391
|
+
return {
|
|
392
|
+
status: 'success',
|
|
393
|
+
phases,
|
|
394
|
+
broaderVerification: {
|
|
395
|
+
command: '(verification)',
|
|
396
|
+
result: verifyResult.status === 'success' ? 'PASS' : 'FAIL',
|
|
397
|
+
},
|
|
398
|
+
filesModified: [...new Set(filesModified)],
|
|
399
|
+
summary: `TDD complete: RED(${redStatus}) → GREEN(${greenStatus}) → REFACTOR(${refactorStatus}). Used ${totalTokens} tokens.`,
|
|
400
|
+
tokensUsed: totalTokens,
|
|
401
|
+
}
|
|
402
|
+
} finally {
|
|
403
|
+
guard.deactivateEmbargo()
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
export const tddSkill = new TDDSkill()
|
|
409
|
+
export default tddSkill
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: to-plan
|
|
3
|
+
description: Create implementation plans via 5-step subagent dispatch. Classify, explore codebase, synthesize findings, write plan, validate.
|
|
4
|
+
requires: []
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## ⛔ MAIN AGENT CONSTRAINT
|
|
8
|
+
|
|
9
|
+
You are a THIN DISPATCHER. Your ONLY job is to dispatch subagents.
|
|
10
|
+
You MUST NOT: read source files, search code, write/edit files, run tests, run git commands.
|
|
11
|
+
You MAY only: read plan/state files, dispatch subagents via Agent tool, relay results.
|
|
12
|
+
For EVERY user request (including this skill), dispatch a subagent. Never execute yourself.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Use/Exclude Matrix
|
|
17
|
+
|
|
18
|
+
| Use When | Exclude When |
|
|
19
|
+
|---|---|
|
|
20
|
+
| Feature implementation needs planning | Trivial typo/rename (use quick-task) |
|
|
21
|
+
| Bugfix with unknown scope | Already have an approved plan |
|
|
22
|
+
| Refactor spanning multiple files | Single-file change with known solution |
|
|
23
|
+
| Architectural changes | Task fits in <30 chars description |
|
|
24
|
+
|
|
25
|
+
## Workflow
|
|
26
|
+
|
|
27
|
+
Each step below is delegated to a subagent. The main agent only dispatches.
|
|
28
|
+
|
|
29
|
+
1. **Classify** — Dispatch classifier subagent to determine type, complexity, risk, and exploration areas.
|
|
30
|
+
2. **Explore** — Dispatch 1-3 read-only explorer subagents in parallel, each focused on one exploration area.
|
|
31
|
+
3. **Synthesize** — Dispatch planner subagent to cross-reference findings and produce unified task list with execution model.
|
|
32
|
+
4. **Write Plan** — Dispatch writer subagent to write the plan to disk in markdown format.
|
|
33
|
+
5. **Check Plan** — Dispatch reviewer subagent to validate plan completeness, dependency acyclicity, and task sizing.
|
|
34
|
+
|
|
35
|
+
## Output Spec
|
|
36
|
+
|
|
37
|
+
| Field | Type | Description |
|
|
38
|
+
|---|---|---|
|
|
39
|
+
| `planPath` | string | Absolute path to the written plan file |
|
|
40
|
+
| `executionModel` | enum | `single-agent`, `ordered-non-parallel`, `fan-out-fan-in` |
|
|
41
|
+
| `classification.type` | string | `feature`, `bugfix`, `migration`, `cleanup`, `refactor` |
|
|
42
|
+
| `classification.complexity` | enum | `low`, `medium`, `high` |
|
|
43
|
+
| `classification.risk` | enum | `low`, `medium`, `high` |
|
|
44
|
+
| `planCheckerPassed` | boolean | Whether the plan validation passed |
|
|
45
|
+
| `tasks` | TaskDef[] | Parsed tasks with id, title, description, owns, reads, dependencies, verification |
|
|
46
|
+
| `tokensUsed` | number | Total tokens consumed across all subagents |
|
|
47
|
+
|
|
48
|
+
## Error Handling
|
|
49
|
+
|
|
50
|
+
| Error | Action |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Classification subagent fails | Retry once; fall back to defaults (type=feature, complexity=medium) |
|
|
53
|
+
| All explorations fail | Synthesize with empty exploration data |
|
|
54
|
+
| Write subagent fails | Write fallback plan directly from synthesis data |
|
|
55
|
+
| Plan checker returns BLOCKED | Return result with `planCheckerPassed: false`; caller decides retry |
|
|
56
|
+
| Invalid plan path directory | Auto-create directory via `mkdir -p` |
|