5-phase-workflow 2.0.6 → 3.0.0-beta-2
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 +16 -17
- package/bin/install.js +113 -15
- package/docs/workflow-guide.md +25 -26
- package/package.json +1 -1
- package/src/agents/step-executor-agent.md +6 -8
- package/src/agents/step-orchestrator-agent.md +10 -44
- package/src/agents/verification-agent.md +10 -45
- package/src/commands/5/commit.md +14 -83
- package/src/commands/5/configure.md +8 -29
- package/src/commands/5/implement.md +85 -139
- package/src/commands/5/plan.md +129 -109
- package/src/commands/5/reconfigure.md +3 -3
- package/src/commands/5/review.md +53 -37
- package/src/commands/5/split.md +15 -119
- package/src/references/configure-tables.md +0 -5
- package/src/settings.json +0 -10
- package/src/workflows/5-implement.js +328 -0
- package/src/commands/5/discuss-feature.md +0 -189
- package/src/commands/5/unlock.md +0 -23
- package/src/hooks/plan-guard.js +0 -269
- package/src/templates/workflow/STATE.json +0 -43
|
@@ -85,10 +85,6 @@ For each command found: record exact syntax, note variants (e.g., `test:unit`, `
|
|
|
85
85
|
}
|
|
86
86
|
},
|
|
87
87
|
"tools": {
|
|
88
|
-
"coderabbit": {
|
|
89
|
-
"available": false,
|
|
90
|
-
"authenticated": false
|
|
91
|
-
},
|
|
92
88
|
"ide": {
|
|
93
89
|
"available": false,
|
|
94
90
|
"type": null
|
|
@@ -100,7 +96,6 @@ For each command found: record exact syntax, note variants (e.g., `test:unit`, `
|
|
|
100
96
|
"available": false
|
|
101
97
|
}
|
|
102
98
|
},
|
|
103
|
-
"reviewTool": "native",
|
|
104
99
|
"git": {
|
|
105
100
|
"autoCommit": false,
|
|
106
101
|
"commitMessage": {
|
package/src/settings.json
CHANGED
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
export const meta = {
|
|
2
|
+
name: '5-implement',
|
|
3
|
+
description: 'Execute a unified plan: derive steps, run executors in parallel waves, verify. Claude Code only; Codex uses the prose loop.',
|
|
4
|
+
whenToUse: 'Invoked by the /5:implement command when the Workflow tool is available. Reads args from the command, returns the run result for the command to persist to the slim state.json.',
|
|
5
|
+
phases: [
|
|
6
|
+
{ title: 'Orchestrate', detail: 'derive steps + components (agent for non-trivial plans, inline for compact)' },
|
|
7
|
+
{ title: 'Execute', detail: 'one executor agent per component; parallel components fire together per step' },
|
|
8
|
+
{ title: 'Verify', detail: 'inline when all passed + mechanical, else one verification agent' }
|
|
9
|
+
]
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
13
|
+
// Contract note: the executor / orchestrator / verifier prompts below are the
|
|
14
|
+
// inline, schema-validated form of src/agents/*-agent.md. Those .md files remain
|
|
15
|
+
// the canonical human-readable contract; keep these prompts in sync with them.
|
|
16
|
+
//
|
|
17
|
+
// This script has NO filesystem access. It orchestrates agents and RETURNS the
|
|
18
|
+
// final result. The /5:implement command (which has Write) persists the slim
|
|
19
|
+
// state.json and runs auto-commit after this returns.
|
|
20
|
+
//
|
|
21
|
+
// The execution graph (steps/components) is derived fresh on every run and is
|
|
22
|
+
// NOT persisted. Resume works because component names are copied verbatim from
|
|
23
|
+
// the plan's Component Checklist, so re-derivation is stable by name.
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
|
|
26
|
+
const RESULT_SCHEMA = {
|
|
27
|
+
type: 'object',
|
|
28
|
+
additionalProperties: false,
|
|
29
|
+
required: ['status', 'verify'],
|
|
30
|
+
properties: {
|
|
31
|
+
status: { enum: ['success', 'failed'] },
|
|
32
|
+
filesCreated: { type: 'array', items: { type: 'string' } },
|
|
33
|
+
filesModified: { type: 'array', items: { type: 'string' } },
|
|
34
|
+
verify: { enum: ['passed', 'failed', 'skipped'] },
|
|
35
|
+
deviations: { type: 'string', description: 'none or a brief list' },
|
|
36
|
+
error: { type: 'string', description: 'none or an error description' }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const VERIFICATION_SCHEMA = {
|
|
41
|
+
type: 'object',
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
required: ['status', 'completeness', 'infrastructure', 'quality'],
|
|
44
|
+
properties: {
|
|
45
|
+
status: { enum: ['passed', 'partial', 'failed'] },
|
|
46
|
+
completeness: { enum: ['passed', 'partial', 'failed'] },
|
|
47
|
+
infrastructure: { enum: ['passed', 'failed'] },
|
|
48
|
+
acceptanceCriteria: { type: 'string', description: 'satisfied/total, e.g. "3/3"' },
|
|
49
|
+
quality: { enum: ['passed', 'partial', 'failed'] },
|
|
50
|
+
commands: {
|
|
51
|
+
type: 'array',
|
|
52
|
+
items: {
|
|
53
|
+
type: 'object',
|
|
54
|
+
additionalProperties: false,
|
|
55
|
+
required: ['command', 'status'],
|
|
56
|
+
properties: {
|
|
57
|
+
command: { type: 'string' },
|
|
58
|
+
status: { enum: ['passed', 'failed', 'skipped'] },
|
|
59
|
+
summary: { type: 'string' }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
failures: { type: 'array', items: { type: 'string' } }
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const STATE_SCHEMA = {
|
|
68
|
+
type: 'object',
|
|
69
|
+
additionalProperties: false,
|
|
70
|
+
required: ['steps', 'pendingComponents'],
|
|
71
|
+
properties: {
|
|
72
|
+
steps: {
|
|
73
|
+
type: 'array',
|
|
74
|
+
items: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
additionalProperties: false,
|
|
77
|
+
required: ['number', 'name', 'mode', 'components'],
|
|
78
|
+
properties: {
|
|
79
|
+
number: { type: 'integer' },
|
|
80
|
+
name: { type: 'string' },
|
|
81
|
+
mode: { enum: ['parallel', 'sequential'] },
|
|
82
|
+
model: { enum: ['haiku', 'sonnet'] },
|
|
83
|
+
components: { type: 'array', items: { type: 'string' } }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
pendingComponents: {
|
|
88
|
+
type: 'array',
|
|
89
|
+
items: {
|
|
90
|
+
type: 'object',
|
|
91
|
+
additionalProperties: false,
|
|
92
|
+
required: ['name', 'action', 'step', 'mode', 'model', 'file'],
|
|
93
|
+
properties: {
|
|
94
|
+
name: { type: 'string' },
|
|
95
|
+
action: { enum: ['create', 'modify', 'delete', 'rename'] },
|
|
96
|
+
step: { type: 'integer' },
|
|
97
|
+
mode: { enum: ['parallel', 'sequential'] },
|
|
98
|
+
model: { enum: ['haiku', 'sonnet'] },
|
|
99
|
+
file: { type: 'string' },
|
|
100
|
+
sourceFile: { type: ['string', 'null'] },
|
|
101
|
+
description: { type: 'string' },
|
|
102
|
+
dependsOn: { type: 'array', items: { type: 'string' } },
|
|
103
|
+
patternRefs: {
|
|
104
|
+
type: 'array',
|
|
105
|
+
items: {
|
|
106
|
+
type: 'object',
|
|
107
|
+
additionalProperties: false,
|
|
108
|
+
required: ['file'],
|
|
109
|
+
properties: {
|
|
110
|
+
file: { type: 'string' },
|
|
111
|
+
read: { type: 'string' },
|
|
112
|
+
reason: { type: 'string' }
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
verifyCommands: { type: 'array', items: { type: 'string' } },
|
|
117
|
+
notes: { type: 'array', items: { type: 'string' } }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// ── Prompt builders ──────────────────────────────────────────────────────────
|
|
125
|
+
|
|
126
|
+
function orchestratorPrompt(a) {
|
|
127
|
+
return `You are a Step Orchestrator. Read these files and RETURN execution state as structured output. Do NOT write any file.
|
|
128
|
+
|
|
129
|
+
Feature: ${a.feature}
|
|
130
|
+
Plan: ${a.paths.plan}
|
|
131
|
+
Codebase scan: ${a.paths.scan} (read only if present)
|
|
132
|
+
Config: ${a.paths.config} (read only if present)
|
|
133
|
+
|
|
134
|
+
Turn the lean component checklist in the plan into steps + components:
|
|
135
|
+
- COPY EVERY COMPONENT NAME VERBATIM from the plan's Component Checklist. Resume matches components by name across runs, so a renamed or reformatted name makes completed work run twice.
|
|
136
|
+
- Group independent components into one step with mode "parallel"; use "sequential" only when components touch the same file, one imports another, or there is an explicit dependency.
|
|
137
|
+
- Prefer fewer steps. Tests run after the components they validate.
|
|
138
|
+
- model "haiku" by default (mechanical, UI, tests, docs, config, single-file). model "sonnet" only for complex logic, cross-module, security/auth, migrations, or public API.
|
|
139
|
+
- 1-2 high-signal patternRefs per component with line ranges or symbols so executors avoid whole-file reads.
|
|
140
|
+
- verifyCommands: narrowest relevant check first, then project build/test.
|
|
141
|
+
- Exclude [DEFERRED] work. Represent every other component once. dependsOn must reference existing component names.
|
|
142
|
+
|
|
143
|
+
Return an object matching the schema (steps[] and pendingComponents[]).`
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function executorPrompt(c, a, opts) {
|
|
147
|
+
const refs = (c.patternRefs || []).map(r => ` - ${r.file}${r.read ? ` (${r.read})` : ''}${r.reason ? ` — ${r.reason}` : ''}`).join('\n') || ' - none'
|
|
148
|
+
const verify = (c.verifyCommands || []).join(' && ') || 'infer the narrowest relevant test/build command'
|
|
149
|
+
const retry = opts && opts.retry
|
|
150
|
+
? '\nThis is a RETRY of a failed attempt — read the error context carefully and correct the root cause.'
|
|
151
|
+
: ''
|
|
152
|
+
return `You are a Step Executor. Implement EXACTLY this component and nothing more.${retry}
|
|
153
|
+
|
|
154
|
+
Component: ${c.name}
|
|
155
|
+
Action: ${c.action}
|
|
156
|
+
Target file: ${c.file}${c.sourceFile ? `\nSource file (rename from): ${c.sourceFile}` : ''}
|
|
157
|
+
Intent: ${c.description || ''}
|
|
158
|
+
|
|
159
|
+
Read only these pattern references (ranges/symbols), plus the target file for modify/rename:
|
|
160
|
+
${refs}
|
|
161
|
+
|
|
162
|
+
Rules: smallest coherent change; mirror existing naming/exports/layout/tests; follow any local skill or rule; add no new dependency; no abstraction or error handling beyond what the intent requires. Fix mechanical issues you cause (imports, types, lint). STOP and report failed for missing dependencies, unplanned auth/schema/API/contract changes, or unclear product decisions. If verify fails only from pre-existing unrelated issues, report that as a deviation with the exact evidence — do not mark the component failed. Do not make more than three attempts on the same failing issue.
|
|
163
|
+
|
|
164
|
+
Then run: ${verify}
|
|
165
|
+
|
|
166
|
+
Return structured output: status, filesCreated, filesModified, verify, deviations (none or brief), error (none or description). Keep it concise — no logs or diffs unless failed.`
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
function verifyPrompt(a, results, resumeDone) {
|
|
170
|
+
const ran = results.flatMap(s => s.items.map(i =>
|
|
171
|
+
` step ${s.step} ${i.component.name}: ${i.result ? i.result.status : 'no result'} (verify ${i.result ? i.result.verify : '?'})${i.escalated ? ' [escalated to sonnet]' : ''}`))
|
|
172
|
+
const prior = [...(resumeDone || [])]
|
|
173
|
+
.filter(n => !results.some(s => s.items.some(i => i.component.name === n)))
|
|
174
|
+
.map(n => ` ${n}: completed in a prior session`)
|
|
175
|
+
const summary = [...ran, ...prior].join('\n') || ' (no components ran this invocation)'
|
|
176
|
+
const baseline = (a.baseline && a.baseline.length)
|
|
177
|
+
? a.baseline.map(b => ` ${b.command || b.details && b.details.command || '?'}: ${b.status}${b.summary ? ` — ${b.summary}` : ''}`).join('\n')
|
|
178
|
+
: ' (none recorded)'
|
|
179
|
+
return `You are a Verification Agent. Verify only; do not implement fixes.
|
|
180
|
+
|
|
181
|
+
Feature: ${a.feature}
|
|
182
|
+
Plan: ${a.paths.plan}
|
|
183
|
+
Config: ${a.paths.config} (read only if present)
|
|
184
|
+
|
|
185
|
+
Baseline (pre-change) command results — treat any failure listed here as PRE-EXISTING, not caused by this change:
|
|
186
|
+
${baseline}
|
|
187
|
+
|
|
188
|
+
Component results:
|
|
189
|
+
${summary}
|
|
190
|
+
|
|
191
|
+
Checks: completeness (every planned component done, acceptance criteria addressed); files exist for create/modify, rename moved correctly, delete removed; build + test pass (reuse the baseline and component results above when they already prove status — rerun only the commands whose inputs changed, not identical passing ones); correctness (inspect changed files, not just existence); quality (logic-bearing changes have tests when a test framework exists). Prefer changed files over broad scanning.
|
|
192
|
+
|
|
193
|
+
Return structured output: status, completeness, infrastructure, acceptanceCriteria ("satisfied/total"), quality, commands[], failures[].`
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
// Build a single trivial step in JS for compact plans (no orchestrator agent).
|
|
199
|
+
function compactSteps(components) {
|
|
200
|
+
const norm = components.map((c, i) => ({
|
|
201
|
+
name: c.name,
|
|
202
|
+
action: c.action || 'modify',
|
|
203
|
+
step: 1,
|
|
204
|
+
mode: 'parallel',
|
|
205
|
+
model: c.model || 'haiku',
|
|
206
|
+
file: c.file,
|
|
207
|
+
sourceFile: c.sourceFile || null,
|
|
208
|
+
description: c.description || '',
|
|
209
|
+
dependsOn: c.dependsOn || [],
|
|
210
|
+
patternRefs: c.patternRefs || [],
|
|
211
|
+
verifyCommands: c.verifyCommands || [],
|
|
212
|
+
notes: []
|
|
213
|
+
}))
|
|
214
|
+
// If two components write the same file or one depends on another, fall back to sequential.
|
|
215
|
+
const files = norm.map(c => c.file)
|
|
216
|
+
const fileConflict = new Set(files).size !== files.length
|
|
217
|
+
const hasDep = norm.some(c => c.dependsOn && c.dependsOn.length)
|
|
218
|
+
const mode = (fileConflict || hasDep) ? 'sequential' : 'parallel'
|
|
219
|
+
norm.forEach(c => { c.mode = mode })
|
|
220
|
+
const stepModel = norm.some(c => c.model === 'sonnet') ? 'sonnet' : 'haiku'
|
|
221
|
+
return {
|
|
222
|
+
steps: [{ number: 1, name: 'implement', mode, model: stepModel, components: norm.map(c => c.name) }],
|
|
223
|
+
pendingComponents: norm
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
async function runStep(step, components, a) {
|
|
228
|
+
const stepComps = components.filter(c => step.components.includes(c.name))
|
|
229
|
+
if (!stepComps.length) return { step: step.number, name: step.name, mode: step.mode, items: [] }
|
|
230
|
+
|
|
231
|
+
let waveResults
|
|
232
|
+
if (step.mode === 'parallel' && stepComps.length > 1) {
|
|
233
|
+
// Fire every parallel component together — true concurrency, one wave.
|
|
234
|
+
waveResults = await parallel(stepComps.map(c => () =>
|
|
235
|
+
agent(executorPrompt(c, a), { label: `exec:${c.name}`, phase: 'Execute', model: c.model || 'haiku', schema: RESULT_SCHEMA })
|
|
236
|
+
.then(result => ({ component: c, result }))
|
|
237
|
+
.catch(() => ({ component: c, result: null }))))
|
|
238
|
+
} else {
|
|
239
|
+
waveResults = []
|
|
240
|
+
for (const c of stepComps) {
|
|
241
|
+
const result = await agent(executorPrompt(c, a), { label: `exec:${c.name}`, phase: 'Execute', model: c.model || 'haiku', schema: RESULT_SCHEMA })
|
|
242
|
+
.catch(() => null)
|
|
243
|
+
waveResults.push({ component: c, result })
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// Retry failed OR crashed (null) components up to twice, escalating to sonnet.
|
|
248
|
+
// A crashed agent (null result) is retried too — an infra error should not be
|
|
249
|
+
// treated more harshly than a clean structured failure.
|
|
250
|
+
for (const wr of waveResults) {
|
|
251
|
+
let attempt = 1
|
|
252
|
+
while ((wr.result == null || wr.result.status === 'failed') && attempt <= 2) {
|
|
253
|
+
log(`retry ${wr.component.name} (attempt ${attempt + 1}) on sonnet`)
|
|
254
|
+
wr.escalated = true
|
|
255
|
+
const retried = await agent(executorPrompt(wr.component, a, { retry: true }),
|
|
256
|
+
{ label: `retry:${wr.component.name}`, phase: 'Execute', model: 'sonnet', schema: RESULT_SCHEMA }).catch(() => null)
|
|
257
|
+
if (retried) wr.result = retried
|
|
258
|
+
attempt++
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
return { step: step.number, name: step.name, mode: step.mode, items: waveResults }
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// ── Main ─────────────────────────────────────────────────────────────────────
|
|
266
|
+
|
|
267
|
+
const a = args || {}
|
|
268
|
+
const resumeDone = new Set(a.completedComponents || [])
|
|
269
|
+
|
|
270
|
+
phase('Orchestrate')
|
|
271
|
+
if (resumeDone.size) log(`resume: ${resumeDone.size} component(s) already complete, matched by name`)
|
|
272
|
+
let plan
|
|
273
|
+
if (a.isCompact && Array.isArray(a.components) && a.components.length) {
|
|
274
|
+
log(`compact plan: ${a.components.length} component(s), no orchestrator agent`)
|
|
275
|
+
plan = compactSteps(a.components)
|
|
276
|
+
} else {
|
|
277
|
+
plan = await agent(orchestratorPrompt(a), { label: 'orchestrate', phase: 'Orchestrate', schema: STATE_SCHEMA })
|
|
278
|
+
}
|
|
279
|
+
const steps = plan.steps
|
|
280
|
+
const components = plan.pendingComponents
|
|
281
|
+
|
|
282
|
+
phase('Execute')
|
|
283
|
+
const results = []
|
|
284
|
+
for (const step of steps) {
|
|
285
|
+
const remaining = components.filter(c => step.components.includes(c.name) && !resumeDone.has(c.name))
|
|
286
|
+
if (!remaining.length) { log(`step ${step.number} already complete (resume), skipping`); continue }
|
|
287
|
+
const stepResult = await runStep({ ...step, components: remaining.map(c => c.name) }, components, a)
|
|
288
|
+
results.push(stepResult)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
phase('Verify')
|
|
292
|
+
const allItems = results.flatMap(s => s.items)
|
|
293
|
+
const allPassed = allItems.length > 0 && allItems.every(i => i.result && i.result.status === 'success' && i.result.verify !== 'failed')
|
|
294
|
+
// Non-mechanical when a component was planned as sonnet OR needed a sonnet retry to pass —
|
|
295
|
+
// either signals reasoning-level work that warrants the full verification agent.
|
|
296
|
+
const usedSonnet = components.some(c => (c.model || 'haiku') === 'sonnet') || allItems.some(i => i.escalated)
|
|
297
|
+
let verification
|
|
298
|
+
if (allPassed && !usedSonnet) {
|
|
299
|
+
log('all components passed + mechanical (no sonnet, no escalation) — inline verify, no verification agent')
|
|
300
|
+
verification = { status: 'passed', completeness: 'passed', infrastructure: 'passed', acceptanceCriteria: 'n/a', quality: 'passed', commands: [], failures: [], inline: true }
|
|
301
|
+
} else {
|
|
302
|
+
if (!allItems.length) log('no components ran this invocation (resume) — verifying the already-completed feature against the plan')
|
|
303
|
+
verification = await agent(verifyPrompt(a, results, resumeDone), {
|
|
304
|
+
label: 'verify', phase: 'Verify', model: usedSonnet ? 'sonnet' : 'haiku', schema: VERIFICATION_SCHEMA
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// Union prior + newly-succeeded so the command can MERGE (not replace) completed history on resume.
|
|
309
|
+
const newlyCompleted = allItems.filter(i => i.result && i.result.status === 'success').map(i => i.component.name)
|
|
310
|
+
const completedComponents = [...new Set([...resumeDone, ...newlyCompleted])]
|
|
311
|
+
|
|
312
|
+
// Returned to the /5:implement command, which persists the slim state.json and auto-commits.
|
|
313
|
+
// steps + components are returned for reporting and per-step staging only — they are NOT persisted;
|
|
314
|
+
// the next run re-derives them, and resume matches on completedComponents by name.
|
|
315
|
+
return {
|
|
316
|
+
feature: a.feature,
|
|
317
|
+
steps,
|
|
318
|
+
components,
|
|
319
|
+
completedComponents,
|
|
320
|
+
results: results.map(s => ({
|
|
321
|
+
step: s.step,
|
|
322
|
+
name: s.name,
|
|
323
|
+
mode: s.mode,
|
|
324
|
+
items: s.items.map(i => ({ component: i.component.name, file: i.component.file, sourceFile: i.component.sourceFile, escalated: !!i.escalated, result: i.result }))
|
|
325
|
+
})),
|
|
326
|
+
verification,
|
|
327
|
+
status: verification.status === 'passed' ? 'completed' : 'failed'
|
|
328
|
+
}
|
|
@@ -1,189 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: 5:discuss-feature
|
|
3
|
-
description: Discusses and refines an existing unified plan through iterative Q&A. Use after /5:plan when requirements need clarification or changes. Updates the unified plan based on discussion.
|
|
4
|
-
allowed-tools: Read, Write, Glob, Grep, Agent, AskUserQuestion
|
|
5
|
-
user-invocable: true
|
|
6
|
-
context: inherit
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<role>
|
|
10
|
-
You are a Feature Discussion Facilitator. You refine existing unified plans through Q&A.
|
|
11
|
-
You do NOT create new unified plans, create implementation plans, write code, or start implementation.
|
|
12
|
-
You read an existing plan.md, discuss it with the user, and update only the changed sections.
|
|
13
|
-
After updating the plan and informing the user, you are DONE.
|
|
14
|
-
</role>
|
|
15
|
-
|
|
16
|
-
# Discuss Feature Plan (Optional Iteration)
|
|
17
|
-
|
|
18
|
-
## Overview
|
|
19
|
-
|
|
20
|
-
This helper refines the unified `plan.md` created by `/5:plan`.
|
|
21
|
-
|
|
22
|
-
Use it when requirements, scope, acceptance criteria, decisions, or the component checklist need adjustment before `/5:implement`.
|
|
23
|
-
|
|
24
|
-
## ⚠️ CRITICAL SCOPE CONSTRAINT
|
|
25
|
-
|
|
26
|
-
**THIS COMMAND ONLY UPDATES THE UNIFIED PLAN. IT DOES NOT IMPLEMENT.**
|
|
27
|
-
|
|
28
|
-
Your job in this command:
|
|
29
|
-
✅ Read existing unified plan
|
|
30
|
-
✅ Ask what user wants to discuss
|
|
31
|
-
✅ Explore codebase if needed for context
|
|
32
|
-
✅ Ask clarifying questions
|
|
33
|
-
✅ Update unified plan
|
|
34
|
-
✅ Tell user to run /5:implement
|
|
35
|
-
|
|
36
|
-
Your job is NOT:
|
|
37
|
-
❌ Create new unified plans (use /5:plan)
|
|
38
|
-
❌ Start implementation
|
|
39
|
-
❌ Write any code
|
|
40
|
-
❌ Rewrite entire unified plan (only update changed sections)
|
|
41
|
-
|
|
42
|
-
**After updating the unified plan and informing the user, YOUR JOB IS COMPLETE. EXIT IMMEDIATELY.**
|
|
43
|
-
|
|
44
|
-
## Use Cases
|
|
45
|
-
|
|
46
|
-
Use this skill when:
|
|
47
|
-
- Requirements need clarification after initial planning
|
|
48
|
-
- User wants to add/modify/remove requirements
|
|
49
|
-
- Scope needs adjustment
|
|
50
|
-
- Technical constraints discovered during exploration
|
|
51
|
-
- Alternative approaches need evaluation
|
|
52
|
-
- Feature complexity needs reduction
|
|
53
|
-
- Acceptance criteria need refinement
|
|
54
|
-
|
|
55
|
-
## Prerequisites
|
|
56
|
-
|
|
57
|
-
Before invoking this skill, ensure:
|
|
58
|
-
1. Unified plan exists at `.5/features/{feature-name}/plan.md`
|
|
59
|
-
2. You have the feature name or ticket ID ready (e.g., "PROJ-1234-add-feature")
|
|
60
|
-
|
|
61
|
-
## Discussion Process
|
|
62
|
-
|
|
63
|
-
### Step 1: Extract Feature Name
|
|
64
|
-
|
|
65
|
-
If user provides only ticket ID (e.g., "PROJ-1234"), find the plan file:
|
|
66
|
-
- Use Glob: `.5/features/{TICKET-ID}-*/plan.md` (pattern from config)
|
|
67
|
-
- Match the ticket ID
|
|
68
|
-
- If multiple matches, ask user to specify
|
|
69
|
-
- If no match found, inform user and suggest running `/5:plan` first
|
|
70
|
-
|
|
71
|
-
If user provides full feature name (e.g., "PROJ-1234-add-feature"), use directly.
|
|
72
|
-
|
|
73
|
-
### Step 2: Read Plan
|
|
74
|
-
|
|
75
|
-
Read the unified plan from `.5/features/{feature-name}/plan.md`.
|
|
76
|
-
|
|
77
|
-
Extract current state:
|
|
78
|
-
- Ticket ID
|
|
79
|
-
- Overview
|
|
80
|
-
- What Changes
|
|
81
|
-
- Existing Patterns to Follow
|
|
82
|
-
- Constraints
|
|
83
|
-
- Scope
|
|
84
|
-
- Acceptance Criteria
|
|
85
|
-
- Decisions ([DECIDED]/[FLEXIBLE]/[DEFERRED])
|
|
86
|
-
- Module Impact
|
|
87
|
-
- Component Checklist
|
|
88
|
-
- Technical Notes
|
|
89
|
-
- Alternatives Considered
|
|
90
|
-
|
|
91
|
-
### Step 3: Initial Discussion Prompt
|
|
92
|
-
|
|
93
|
-
**FIRST ACTION:** Ask the user what they want to discuss using AskUserQuestion.
|
|
94
|
-
|
|
95
|
-
Prompt to use:
|
|
96
|
-
|
|
97
|
-
"What would you like to discuss or change about this feature?"
|
|
98
|
-
|
|
99
|
-
Provide context options for common scenarios:
|
|
100
|
-
- "Clarify existing requirements"
|
|
101
|
-
- "Add new requirements"
|
|
102
|
-
- "Remove or simplify requirements"
|
|
103
|
-
- "Change scope or approach"
|
|
104
|
-
- "Discuss technical constraints"
|
|
105
|
-
- "Review acceptance criteria"
|
|
106
|
-
- "Other (specify)"
|
|
107
|
-
|
|
108
|
-
Use `multiSelect: false` to get single focus area initially.
|
|
109
|
-
|
|
110
|
-
### Step 4: Contextual Exploration (Optional)
|
|
111
|
-
|
|
112
|
-
Based on the user's focus area, explore the codebase if needed:
|
|
113
|
-
|
|
114
|
-
**Index shortcut:** Before spawning Explore agents or running Glob/Grep, invoke the `use-index` skill to quickly orient in the codebase using the generated index.
|
|
115
|
-
|
|
116
|
-
**For technical constraint discussions:**
|
|
117
|
-
- Search for similar implementations
|
|
118
|
-
- Check existing patterns
|
|
119
|
-
- Identify integration points
|
|
120
|
-
|
|
121
|
-
**For scope changes:**
|
|
122
|
-
- Verify affected modules
|
|
123
|
-
- Check dependencies
|
|
124
|
-
- Identify ripple effects
|
|
125
|
-
|
|
126
|
-
Use Agent tool with subagent_type=Explore for complex exploration.
|
|
127
|
-
|
|
128
|
-
### Step 5: Interactive Q&A
|
|
129
|
-
|
|
130
|
-
Based on the discussion topic, ask targeted follow-up questions using AskUserQuestion.
|
|
131
|
-
|
|
132
|
-
Ask targeted follow-up questions informed by the unified plan and any codebase exploration. Focus on: requirements clarity, scope boundaries, edge cases, technical constraints, and acceptance criteria. Challenge assumptions constructively — suggest simpler alternatives when appropriate.
|
|
133
|
-
|
|
134
|
-
### Step 6: Iterative Refinement
|
|
135
|
-
|
|
136
|
-
After each round of Q&A:
|
|
137
|
-
1. Summarize what you've learned
|
|
138
|
-
2. Ask: "Would you like to discuss anything else about this feature?"
|
|
139
|
-
3. Provide options:
|
|
140
|
-
- "Yes, discuss another aspect"
|
|
141
|
-
- "Yes, continue this topic"
|
|
142
|
-
- "No, update the plan"
|
|
143
|
-
|
|
144
|
-
Allow multiple rounds of discussion until user is satisfied.
|
|
145
|
-
|
|
146
|
-
### Step 7: Update Plan
|
|
147
|
-
|
|
148
|
-
When user indicates they're done discussing, update `.5/features/{feature-name}/plan.md`:
|
|
149
|
-
|
|
150
|
-
**Update these sections based on discussion:**
|
|
151
|
-
|
|
152
|
-
1. **Overview** - If core understanding changed
|
|
153
|
-
2. **What Changes** - Add/modify/remove behavior
|
|
154
|
-
3. **Constraints** - Add new constraints discovered
|
|
155
|
-
4. **Scope** - If boundaries changed
|
|
156
|
-
5. **Acceptance Criteria** - Add/refine verification criteria
|
|
157
|
-
6. **Decisions** - Append new decisions tagged [DECIDED], [FLEXIBLE], or [DEFERRED]
|
|
158
|
-
7. **Component Checklist** - Adjust components only when scope or requirements changed
|
|
159
|
-
8. **Technical Notes / Alternatives Considered** - Document useful context from discussion
|
|
160
|
-
|
|
161
|
-
**Preserve existing content** - Only update sections that changed during discussion.
|
|
162
|
-
|
|
163
|
-
**Track changes** - Add a "Discussion History" section if it doesn't exist:
|
|
164
|
-
|
|
165
|
-
```markdown
|
|
166
|
-
## Discussion History
|
|
167
|
-
|
|
168
|
-
### Session 1: {Date} - {Topic}
|
|
169
|
-
**Changes made:**
|
|
170
|
-
- Added requirement: {X}
|
|
171
|
-
- Clarified: {Y}
|
|
172
|
-
- Removed: {Z}
|
|
173
|
-
|
|
174
|
-
**Rationale:** {Why these changes}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
### Step 8: Inform Developer
|
|
178
|
-
|
|
179
|
-
After updating the plan, tell the developer:
|
|
180
|
-
|
|
181
|
-
1. "Plan updated at `.5/features/{feature-name}/plan.md`"
|
|
182
|
-
2. Summarize key changes:
|
|
183
|
-
- "Added: {X}"
|
|
184
|
-
- "Modified: {Y}"
|
|
185
|
-
- "Removed: {Z}"
|
|
186
|
-
3. Ask: "Would you like to:"
|
|
187
|
-
- "Discuss more (run /5:discuss-feature again)"
|
|
188
|
-
- "Proceed to implementation (run `/clear` followed by `/5:implement {feature-name}`)"
|
|
189
|
-
- "Review the updated plan first"
|
package/src/commands/5/unlock.md
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: 5:unlock
|
|
3
|
-
description: Remove the planning guard lock to allow edits outside the workflow
|
|
4
|
-
allowed-tools: Bash
|
|
5
|
-
user-invocable: true
|
|
6
|
-
context: inherit
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
# Unlock Planning Guard
|
|
10
|
-
|
|
11
|
-
Remove the `.planning-active` marker file that restricts Write/Edit operations during planning phases.
|
|
12
|
-
|
|
13
|
-
## Process
|
|
14
|
-
|
|
15
|
-
Run this bash command to check and remove the marker in one step:
|
|
16
|
-
|
|
17
|
-
```bash
|
|
18
|
-
if [ -f .5/.planning-active ]; then rm .5/.planning-active && echo "REMOVED"; else echo "ABSENT"; fi
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
Based on the output, confirm to the user:
|
|
22
|
-
- If output contains "REMOVED": "Planning guard removed. You can now edit files freely."
|
|
23
|
-
- If output contains "ABSENT": "No planning guard was active. You're already free to edit files."
|