gsd-opencode 1.22.1 → 1.33.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/agents/gsd-advisor-researcher.md +112 -0
- package/agents/gsd-assumptions-analyzer.md +110 -0
- package/agents/gsd-codebase-mapper.md +0 -2
- package/agents/gsd-debugger.md +117 -2
- package/agents/gsd-doc-verifier.md +207 -0
- package/agents/gsd-doc-writer.md +608 -0
- package/agents/gsd-executor.md +45 -4
- package/agents/gsd-integration-checker.md +0 -2
- package/agents/gsd-nyquist-auditor.md +0 -2
- package/agents/gsd-phase-researcher.md +191 -5
- package/agents/gsd-plan-checker.md +152 -5
- package/agents/gsd-planner.md +131 -157
- package/agents/gsd-project-researcher.md +28 -3
- package/agents/gsd-research-synthesizer.md +0 -2
- package/agents/gsd-roadmapper.md +29 -2
- package/agents/gsd-security-auditor.md +129 -0
- package/agents/gsd-ui-auditor.md +485 -0
- package/agents/gsd-ui-checker.md +305 -0
- package/agents/gsd-ui-researcher.md +368 -0
- package/agents/gsd-user-profiler.md +173 -0
- package/agents/gsd-verifier.md +207 -22
- package/commands/gsd/gsd-add-backlog.md +76 -0
- package/commands/gsd/gsd-analyze-dependencies.md +34 -0
- package/commands/gsd/gsd-audit-uat.md +24 -0
- package/commands/gsd/gsd-autonomous.md +45 -0
- package/commands/gsd/gsd-cleanup.md +5 -0
- package/commands/gsd/gsd-debug.md +29 -21
- package/commands/gsd/gsd-discuss-phase.md +15 -36
- package/commands/gsd/gsd-do.md +30 -0
- package/commands/gsd/gsd-docs-update.md +48 -0
- package/commands/gsd/gsd-execute-phase.md +24 -2
- package/commands/gsd/gsd-fast.md +30 -0
- package/commands/gsd/gsd-forensics.md +56 -0
- package/commands/gsd/gsd-help.md +2 -0
- package/commands/gsd/gsd-join-discord.md +2 -1
- package/commands/gsd/gsd-list-workspaces.md +19 -0
- package/commands/gsd/gsd-manager.md +40 -0
- package/commands/gsd/gsd-milestone-summary.md +51 -0
- package/commands/gsd/gsd-new-project.md +4 -0
- package/commands/gsd/gsd-new-workspace.md +44 -0
- package/commands/gsd/gsd-next.md +24 -0
- package/commands/gsd/gsd-note.md +34 -0
- package/commands/gsd/gsd-plan-phase.md +8 -1
- package/commands/gsd/gsd-plant-seed.md +28 -0
- package/commands/gsd/gsd-pr-branch.md +25 -0
- package/commands/gsd/gsd-profile-user.md +46 -0
- package/commands/gsd/gsd-quick.md +7 -3
- package/commands/gsd/gsd-reapply-patches.md +178 -45
- package/commands/gsd/gsd-remove-workspace.md +26 -0
- package/commands/gsd/gsd-research-phase.md +7 -12
- package/commands/gsd/gsd-review-backlog.md +62 -0
- package/commands/gsd/gsd-review.md +38 -0
- package/commands/gsd/gsd-secure-phase.md +35 -0
- package/commands/gsd/gsd-session-report.md +19 -0
- package/commands/gsd/gsd-set-profile.md +24 -23
- package/commands/gsd/gsd-ship.md +23 -0
- package/commands/gsd/gsd-stats.md +18 -0
- package/commands/gsd/gsd-thread.md +127 -0
- package/commands/gsd/gsd-ui-phase.md +34 -0
- package/commands/gsd/gsd-ui-review.md +32 -0
- package/commands/gsd/gsd-workstreams.md +71 -0
- package/get-shit-done/bin/gsd-tools.cjs +450 -90
- package/get-shit-done/bin/lib/commands.cjs +489 -24
- package/get-shit-done/bin/lib/config.cjs +329 -48
- package/get-shit-done/bin/lib/core.cjs +1143 -102
- package/get-shit-done/bin/lib/docs.cjs +267 -0
- package/get-shit-done/bin/lib/frontmatter.cjs +125 -43
- package/get-shit-done/bin/lib/init.cjs +918 -106
- package/get-shit-done/bin/lib/milestone.cjs +65 -33
- package/get-shit-done/bin/lib/model-profiles.cjs +70 -0
- package/get-shit-done/bin/lib/phase.cjs +434 -404
- package/get-shit-done/bin/lib/profile-output.cjs +1048 -0
- package/get-shit-done/bin/lib/profile-pipeline.cjs +539 -0
- package/get-shit-done/bin/lib/roadmap.cjs +156 -101
- package/get-shit-done/bin/lib/schema-detect.cjs +238 -0
- package/get-shit-done/bin/lib/security.cjs +384 -0
- package/get-shit-done/bin/lib/state.cjs +711 -79
- package/get-shit-done/bin/lib/template.cjs +2 -2
- package/get-shit-done/bin/lib/uat.cjs +282 -0
- package/get-shit-done/bin/lib/verify.cjs +254 -42
- package/get-shit-done/bin/lib/workstream.cjs +495 -0
- package/get-shit-done/references/agent-contracts.md +79 -0
- package/get-shit-done/references/artifact-types.md +113 -0
- package/get-shit-done/references/checkpoints.md +12 -10
- package/get-shit-done/references/context-budget.md +49 -0
- package/get-shit-done/references/continuation-format.md +15 -15
- package/get-shit-done/references/decimal-phase-calculation.md +2 -3
- package/get-shit-done/references/domain-probes.md +125 -0
- package/get-shit-done/references/gate-prompts.md +100 -0
- package/get-shit-done/references/git-integration.md +47 -0
- package/get-shit-done/references/model-profile-resolution.md +2 -0
- package/get-shit-done/references/model-profiles.md +62 -16
- package/get-shit-done/references/phase-argument-parsing.md +2 -2
- package/get-shit-done/references/planner-gap-closure.md +62 -0
- package/get-shit-done/references/planner-reviews.md +39 -0
- package/get-shit-done/references/planner-revision.md +87 -0
- package/get-shit-done/references/planning-config.md +18 -1
- package/get-shit-done/references/revision-loop.md +97 -0
- package/get-shit-done/references/ui-brand.md +2 -2
- package/get-shit-done/references/universal-anti-patterns.md +58 -0
- package/get-shit-done/references/user-profiling.md +681 -0
- package/get-shit-done/references/workstream-flag.md +111 -0
- package/get-shit-done/templates/SECURITY.md +61 -0
- package/get-shit-done/templates/UAT.md +21 -3
- package/get-shit-done/templates/UI-SPEC.md +100 -0
- package/get-shit-done/templates/VALIDATION.md +3 -3
- package/get-shit-done/templates/claude-md.md +145 -0
- package/get-shit-done/templates/config.json +14 -3
- package/get-shit-done/templates/context.md +61 -6
- package/get-shit-done/templates/debug-subagent-prompt.md +2 -6
- package/get-shit-done/templates/dev-preferences.md +21 -0
- package/get-shit-done/templates/discussion-log.md +63 -0
- package/get-shit-done/templates/phase-prompt.md +46 -5
- package/get-shit-done/templates/planner-subagent-prompt.md +2 -10
- package/get-shit-done/templates/project.md +2 -0
- package/get-shit-done/templates/state.md +2 -2
- package/get-shit-done/templates/user-profile.md +146 -0
- package/get-shit-done/workflows/add-phase.md +4 -4
- package/get-shit-done/workflows/add-tests.md +4 -4
- package/get-shit-done/workflows/add-todo.md +4 -4
- package/get-shit-done/workflows/analyze-dependencies.md +96 -0
- package/get-shit-done/workflows/audit-milestone.md +20 -16
- package/get-shit-done/workflows/audit-uat.md +109 -0
- package/get-shit-done/workflows/autonomous.md +1036 -0
- package/get-shit-done/workflows/check-todos.md +4 -4
- package/get-shit-done/workflows/cleanup.md +4 -4
- package/get-shit-done/workflows/complete-milestone.md +22 -10
- package/get-shit-done/workflows/diagnose-issues.md +21 -7
- package/get-shit-done/workflows/discovery-phase.md +2 -2
- package/get-shit-done/workflows/discuss-phase-assumptions.md +671 -0
- package/get-shit-done/workflows/discuss-phase-power.md +291 -0
- package/get-shit-done/workflows/discuss-phase.md +558 -47
- package/get-shit-done/workflows/do.md +104 -0
- package/get-shit-done/workflows/docs-update.md +1093 -0
- package/get-shit-done/workflows/execute-phase.md +741 -58
- package/get-shit-done/workflows/execute-plan.md +77 -12
- package/get-shit-done/workflows/fast.md +105 -0
- package/get-shit-done/workflows/forensics.md +265 -0
- package/get-shit-done/workflows/health.md +28 -6
- package/get-shit-done/workflows/help.md +127 -7
- package/get-shit-done/workflows/insert-phase.md +4 -4
- package/get-shit-done/workflows/list-phase-assumptions.md +2 -2
- package/get-shit-done/workflows/list-workspaces.md +56 -0
- package/get-shit-done/workflows/manager.md +363 -0
- package/get-shit-done/workflows/map-codebase.md +83 -44
- package/get-shit-done/workflows/milestone-summary.md +223 -0
- package/get-shit-done/workflows/new-milestone.md +133 -25
- package/get-shit-done/workflows/new-project.md +216 -54
- package/get-shit-done/workflows/new-workspace.md +237 -0
- package/get-shit-done/workflows/next.md +97 -0
- package/get-shit-done/workflows/node-repair.md +92 -0
- package/get-shit-done/workflows/note.md +156 -0
- package/get-shit-done/workflows/pause-work.md +132 -15
- package/get-shit-done/workflows/plan-milestone-gaps.md +6 -7
- package/get-shit-done/workflows/plan-phase.md +513 -62
- package/get-shit-done/workflows/plant-seed.md +169 -0
- package/get-shit-done/workflows/pr-branch.md +129 -0
- package/get-shit-done/workflows/profile-user.md +450 -0
- package/get-shit-done/workflows/progress.md +154 -29
- package/get-shit-done/workflows/quick.md +285 -111
- package/get-shit-done/workflows/remove-phase.md +2 -2
- package/get-shit-done/workflows/remove-workspace.md +90 -0
- package/get-shit-done/workflows/research-phase.md +13 -9
- package/get-shit-done/workflows/resume-project.md +37 -18
- package/get-shit-done/workflows/review.md +281 -0
- package/get-shit-done/workflows/secure-phase.md +154 -0
- package/get-shit-done/workflows/session-report.md +146 -0
- package/get-shit-done/workflows/set-profile.md +2 -2
- package/get-shit-done/workflows/settings.md +91 -11
- package/get-shit-done/workflows/ship.md +237 -0
- package/get-shit-done/workflows/stats.md +60 -0
- package/get-shit-done/workflows/transition.md +150 -23
- package/get-shit-done/workflows/ui-phase.md +292 -0
- package/get-shit-done/workflows/ui-review.md +183 -0
- package/get-shit-done/workflows/update.md +262 -30
- package/get-shit-done/workflows/validate-phase.md +14 -17
- package/get-shit-done/workflows/verify-phase.md +143 -11
- package/get-shit-done/workflows/verify-work.md +141 -39
- package/package.json +1 -1
- package/skills/gsd-audit-milestone/SKILL.md +29 -0
- package/skills/gsd-cleanup/SKILL.md +19 -0
- package/skills/gsd-complete-milestone/SKILL.md +131 -0
- package/skills/gsd-discuss-phase/SKILL.md +54 -0
- package/skills/gsd-execute-phase/SKILL.md +49 -0
- package/skills/gsd-plan-phase/SKILL.md +37 -0
- package/skills/gsd-ui-phase/SKILL.md +24 -0
- package/skills/gsd-ui-review/SKILL.md +24 -0
- package/skills/gsd-verify-work/SKILL.md +30 -0
|
@@ -0,0 +1,495 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workstream — CRUD operations for workstream namespacing
|
|
3
|
+
*
|
|
4
|
+
* Workstreams enable parallel milestones by scoping ROADMAP.md, STATE.md,
|
|
5
|
+
* REQUIREMENTS.md, and phases/ into .planning/workstreams/{name}/ directories.
|
|
6
|
+
*
|
|
7
|
+
* When no workstreams/ directory exists, GSD operates in "flat mode" with
|
|
8
|
+
* everything at .planning/ — backward compatible with pre-workstream installs.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
const { output, error, planningPaths, planningRoot, toPosixPath, getMilestoneInfo, generateSlugInternal, setActiveWorkstream, getActiveWorkstream, filterPlanFiles, filterSummaryFiles, readSubdirectories } = require('./core.cjs');
|
|
14
|
+
const { stateExtractField } = require('./state.cjs');
|
|
15
|
+
|
|
16
|
+
// ─── Migration ──────────────────────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Migrate flat .planning/ layout to workstream mode.
|
|
20
|
+
* Moves per-workstream files (ROADMAP.md, STATE.md, REQUIREMENTS.md, phases/)
|
|
21
|
+
* into .planning/workstreams/{name}/. Shared files (PROJECT.md, config.json,
|
|
22
|
+
* milestones/, research/, codebase/, todos/) stay in place.
|
|
23
|
+
*/
|
|
24
|
+
function migrateToWorkstreams(cwd, workstreamName) {
|
|
25
|
+
if (!workstreamName || /[/\\]/.test(workstreamName) || workstreamName === '.' || workstreamName === '..') {
|
|
26
|
+
throw new Error('Invalid workstream name for migration');
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const baseDir = planningRoot(cwd);
|
|
30
|
+
const wsDir = path.join(baseDir, 'workstreams', workstreamName);
|
|
31
|
+
|
|
32
|
+
if (fs.existsSync(path.join(baseDir, 'workstreams'))) {
|
|
33
|
+
throw new Error('Already in workstream mode — .planning/workstreams/ exists');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const toMove = [
|
|
37
|
+
{ name: 'ROADMAP.md', type: 'file' },
|
|
38
|
+
{ name: 'STATE.md', type: 'file' },
|
|
39
|
+
{ name: 'REQUIREMENTS.md', type: 'file' },
|
|
40
|
+
{ name: 'phases', type: 'dir' },
|
|
41
|
+
];
|
|
42
|
+
|
|
43
|
+
fs.mkdirSync(wsDir, { recursive: true });
|
|
44
|
+
|
|
45
|
+
const filesMoved = [];
|
|
46
|
+
try {
|
|
47
|
+
for (const item of toMove) {
|
|
48
|
+
const src = path.join(baseDir, item.name);
|
|
49
|
+
if (fs.existsSync(src)) {
|
|
50
|
+
const dest = path.join(wsDir, item.name);
|
|
51
|
+
fs.renameSync(src, dest);
|
|
52
|
+
filesMoved.push(item.name);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch (err) {
|
|
56
|
+
for (const name of filesMoved) {
|
|
57
|
+
try { fs.renameSync(path.join(wsDir, name), path.join(baseDir, name)); } catch {}
|
|
58
|
+
}
|
|
59
|
+
try { fs.rmSync(wsDir, { recursive: true }); } catch {}
|
|
60
|
+
try { fs.rmdirSync(path.join(baseDir, 'workstreams')); } catch {}
|
|
61
|
+
throw err;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return { migrated: true, workstream: workstreamName, files_moved: filesMoved };
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// ─── CRUD Commands ──────────────────────────────────────────────────────────
|
|
68
|
+
|
|
69
|
+
function cmdWorkstreamCreate(cwd, name, options, raw) {
|
|
70
|
+
if (!name) {
|
|
71
|
+
error('workstream name required. Usage: workstream create <name>');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const slug = name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
75
|
+
if (!slug) {
|
|
76
|
+
error('Invalid workstream name — must contain at least one alphanumeric character');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const baseDir = planningRoot(cwd);
|
|
80
|
+
if (!fs.existsSync(baseDir)) {
|
|
81
|
+
error('.planning/ directory not found — run /gsd-new-project first');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const wsRoot = path.join(baseDir, 'workstreams');
|
|
85
|
+
const wsDir = path.join(wsRoot, slug);
|
|
86
|
+
|
|
87
|
+
if (fs.existsSync(wsDir) && fs.existsSync(path.join(wsDir, 'STATE.md'))) {
|
|
88
|
+
output({ created: false, error: 'already_exists', workstream: slug, path: toPosixPath(path.relative(cwd, wsDir)) }, raw);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const isFlatMode = !fs.existsSync(wsRoot);
|
|
93
|
+
let migration = null;
|
|
94
|
+
if (isFlatMode && options.migrate !== false) {
|
|
95
|
+
const hasExistingWork = fs.existsSync(path.join(baseDir, 'ROADMAP.md')) ||
|
|
96
|
+
fs.existsSync(path.join(baseDir, 'STATE.md')) ||
|
|
97
|
+
fs.existsSync(path.join(baseDir, 'phases'));
|
|
98
|
+
|
|
99
|
+
if (hasExistingWork) {
|
|
100
|
+
const migrateName = options.migrateName || null;
|
|
101
|
+
let existingWsName;
|
|
102
|
+
if (migrateName) {
|
|
103
|
+
existingWsName = migrateName;
|
|
104
|
+
} else {
|
|
105
|
+
try {
|
|
106
|
+
const milestone = getMilestoneInfo(cwd);
|
|
107
|
+
existingWsName = generateSlugInternal(milestone.name) || 'default';
|
|
108
|
+
} catch {
|
|
109
|
+
existingWsName = 'default';
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
migration = migrateToWorkstreams(cwd, existingWsName);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
output({ created: false, error: 'migration_failed', message: e.message }, raw);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
fs.mkdirSync(wsRoot, { recursive: true });
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
fs.mkdirSync(wsDir, { recursive: true });
|
|
125
|
+
fs.mkdirSync(path.join(wsDir, 'phases'), { recursive: true });
|
|
126
|
+
|
|
127
|
+
const today = new Date().toISOString().split('T')[0];
|
|
128
|
+
const stateContent = [
|
|
129
|
+
'---',
|
|
130
|
+
`workstream: ${slug}`,
|
|
131
|
+
`created: ${today}`,
|
|
132
|
+
'---',
|
|
133
|
+
'',
|
|
134
|
+
'# Project State',
|
|
135
|
+
'',
|
|
136
|
+
'## Current Position',
|
|
137
|
+
'**Status:** Not started',
|
|
138
|
+
'**Current Phase:** None',
|
|
139
|
+
`**Last Activity:** ${today}`,
|
|
140
|
+
'**Last Activity Description:** Workstream created',
|
|
141
|
+
'',
|
|
142
|
+
'## Progress',
|
|
143
|
+
'**Phases Complete:** 0',
|
|
144
|
+
'**Current Plan:** N/A',
|
|
145
|
+
'',
|
|
146
|
+
'## Session Continuity',
|
|
147
|
+
'**Stopped At:** N/A',
|
|
148
|
+
'**Resume File:** None',
|
|
149
|
+
'',
|
|
150
|
+
].join('\n');
|
|
151
|
+
|
|
152
|
+
const statePath = path.join(wsDir, 'STATE.md');
|
|
153
|
+
if (!fs.existsSync(statePath)) {
|
|
154
|
+
fs.writeFileSync(statePath, stateContent, 'utf-8');
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
setActiveWorkstream(cwd, slug);
|
|
158
|
+
|
|
159
|
+
const relPath = toPosixPath(path.relative(cwd, wsDir));
|
|
160
|
+
output({
|
|
161
|
+
created: true,
|
|
162
|
+
workstream: slug,
|
|
163
|
+
path: relPath,
|
|
164
|
+
state_path: relPath + '/STATE.md',
|
|
165
|
+
phases_path: relPath + '/phases',
|
|
166
|
+
migration: migration || null,
|
|
167
|
+
active: true,
|
|
168
|
+
}, raw);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function cmdWorkstreamList(cwd, raw) {
|
|
172
|
+
const wsRoot = path.join(planningRoot(cwd), 'workstreams');
|
|
173
|
+
|
|
174
|
+
if (!fs.existsSync(wsRoot)) {
|
|
175
|
+
output({ mode: 'flat', workstreams: [], message: 'No workstreams — operating in flat mode' }, raw);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const entries = fs.readdirSync(wsRoot, { withFileTypes: true });
|
|
180
|
+
const workstreams = [];
|
|
181
|
+
|
|
182
|
+
for (const entry of entries) {
|
|
183
|
+
if (!entry.isDirectory()) continue;
|
|
184
|
+
|
|
185
|
+
const wsDir = path.join(wsRoot, entry.name);
|
|
186
|
+
const phasesDir = path.join(wsDir, 'phases');
|
|
187
|
+
|
|
188
|
+
const phaseDirs = readSubdirectories(phasesDir);
|
|
189
|
+
const phaseCount = phaseDirs.length;
|
|
190
|
+
let completedCount = 0;
|
|
191
|
+
for (const d of phaseDirs) {
|
|
192
|
+
try {
|
|
193
|
+
const phaseFiles = fs.readdirSync(path.join(phasesDir, d));
|
|
194
|
+
const plans = filterPlanFiles(phaseFiles);
|
|
195
|
+
const summaries = filterSummaryFiles(phaseFiles);
|
|
196
|
+
if (plans.length > 0 && summaries.length >= plans.length) completedCount++;
|
|
197
|
+
} catch {}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
let status = 'unknown', currentPhase = null;
|
|
201
|
+
try {
|
|
202
|
+
const stateContent = fs.readFileSync(path.join(wsDir, 'STATE.md'), 'utf-8');
|
|
203
|
+
status = stateExtractField(stateContent, 'Status') || 'unknown';
|
|
204
|
+
currentPhase = stateExtractField(stateContent, 'Current Phase');
|
|
205
|
+
} catch {}
|
|
206
|
+
|
|
207
|
+
workstreams.push({
|
|
208
|
+
name: entry.name,
|
|
209
|
+
path: toPosixPath(path.relative(cwd, wsDir)),
|
|
210
|
+
has_roadmap: fs.existsSync(path.join(wsDir, 'ROADMAP.md')),
|
|
211
|
+
has_state: fs.existsSync(path.join(wsDir, 'STATE.md')),
|
|
212
|
+
status,
|
|
213
|
+
current_phase: currentPhase,
|
|
214
|
+
phase_count: phaseCount,
|
|
215
|
+
completed_phases: completedCount,
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
output({ mode: 'workstream', workstreams, count: workstreams.length }, raw);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function cmdWorkstreamStatus(cwd, name, raw) {
|
|
223
|
+
if (!name) error('workstream name required. Usage: workstream status <name>');
|
|
224
|
+
if (/[/\\]/.test(name) || name === '.' || name === '..') error('Invalid workstream name');
|
|
225
|
+
|
|
226
|
+
const wsDir = path.join(planningRoot(cwd), 'workstreams', name);
|
|
227
|
+
if (!fs.existsSync(wsDir)) {
|
|
228
|
+
output({ found: false, workstream: name }, raw);
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
const p = planningPaths(cwd, name);
|
|
233
|
+
const relPath = toPosixPath(path.relative(cwd, wsDir));
|
|
234
|
+
|
|
235
|
+
const files = {
|
|
236
|
+
roadmap: fs.existsSync(p.roadmap),
|
|
237
|
+
state: fs.existsSync(p.state),
|
|
238
|
+
requirements: fs.existsSync(p.requirements),
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
const phases = [];
|
|
242
|
+
for (const dir of readSubdirectories(p.phases).sort()) {
|
|
243
|
+
try {
|
|
244
|
+
const phaseFiles = fs.readdirSync(path.join(p.phases, dir));
|
|
245
|
+
const plans = filterPlanFiles(phaseFiles);
|
|
246
|
+
const summaries = filterSummaryFiles(phaseFiles);
|
|
247
|
+
phases.push({
|
|
248
|
+
directory: dir,
|
|
249
|
+
status: summaries.length >= plans.length && plans.length > 0 ? 'complete' :
|
|
250
|
+
plans.length > 0 ? 'in_progress' : 'pending',
|
|
251
|
+
plan_count: plans.length,
|
|
252
|
+
summary_count: summaries.length,
|
|
253
|
+
});
|
|
254
|
+
} catch {}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
let stateInfo = {};
|
|
258
|
+
try {
|
|
259
|
+
const stateContent = fs.readFileSync(p.state, 'utf-8');
|
|
260
|
+
stateInfo = {
|
|
261
|
+
status: stateExtractField(stateContent, 'Status') || 'unknown',
|
|
262
|
+
current_phase: stateExtractField(stateContent, 'Current Phase'),
|
|
263
|
+
last_activity: stateExtractField(stateContent, 'Last Activity'),
|
|
264
|
+
};
|
|
265
|
+
} catch {}
|
|
266
|
+
|
|
267
|
+
output({
|
|
268
|
+
found: true,
|
|
269
|
+
workstream: name,
|
|
270
|
+
path: relPath,
|
|
271
|
+
files,
|
|
272
|
+
phases,
|
|
273
|
+
phase_count: phases.length,
|
|
274
|
+
completed_phases: phases.filter(ph => ph.status === 'complete').length,
|
|
275
|
+
...stateInfo,
|
|
276
|
+
}, raw);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
function cmdWorkstreamComplete(cwd, name, options, raw) {
|
|
280
|
+
if (!name) error('workstream name required. Usage: workstream complete <name>');
|
|
281
|
+
if (/[/\\]/.test(name) || name === '.' || name === '..') error('Invalid workstream name');
|
|
282
|
+
|
|
283
|
+
const root = planningRoot(cwd);
|
|
284
|
+
const wsRoot = path.join(root, 'workstreams');
|
|
285
|
+
const wsDir = path.join(wsRoot, name);
|
|
286
|
+
|
|
287
|
+
if (!fs.existsSync(wsDir)) {
|
|
288
|
+
output({ completed: false, error: 'not_found', workstream: name }, raw);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
const active = getActiveWorkstream(cwd);
|
|
293
|
+
if (active === name) setActiveWorkstream(cwd, null);
|
|
294
|
+
|
|
295
|
+
const archiveDir = path.join(root, 'milestones');
|
|
296
|
+
const today = new Date().toISOString().split('T')[0];
|
|
297
|
+
let archivePath = path.join(archiveDir, `ws-${name}-${today}`);
|
|
298
|
+
let suffix = 1;
|
|
299
|
+
while (fs.existsSync(archivePath)) {
|
|
300
|
+
archivePath = path.join(archiveDir, `ws-${name}-${today}-${suffix++}`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
fs.mkdirSync(archivePath, { recursive: true });
|
|
304
|
+
|
|
305
|
+
const filesMoved = [];
|
|
306
|
+
try {
|
|
307
|
+
const entries = fs.readdirSync(wsDir, { withFileTypes: true });
|
|
308
|
+
for (const entry of entries) {
|
|
309
|
+
fs.renameSync(path.join(wsDir, entry.name), path.join(archivePath, entry.name));
|
|
310
|
+
filesMoved.push(entry.name);
|
|
311
|
+
}
|
|
312
|
+
} catch (err) {
|
|
313
|
+
for (const fname of filesMoved) {
|
|
314
|
+
try { fs.renameSync(path.join(archivePath, fname), path.join(wsDir, fname)); } catch {}
|
|
315
|
+
}
|
|
316
|
+
try { fs.rmSync(archivePath, { recursive: true }); } catch {}
|
|
317
|
+
if (active === name) setActiveWorkstream(cwd, name);
|
|
318
|
+
output({ completed: false, error: 'archive_failed', message: err.message, workstream: name }, raw);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
try { fs.rmdirSync(wsDir); } catch {}
|
|
323
|
+
|
|
324
|
+
let remainingWs = 0;
|
|
325
|
+
try {
|
|
326
|
+
remainingWs = fs.readdirSync(wsRoot, { withFileTypes: true }).filter(e => e.isDirectory()).length;
|
|
327
|
+
if (remainingWs === 0) fs.rmdirSync(wsRoot);
|
|
328
|
+
} catch {}
|
|
329
|
+
|
|
330
|
+
output({
|
|
331
|
+
completed: true,
|
|
332
|
+
workstream: name,
|
|
333
|
+
archived_to: toPosixPath(path.relative(cwd, archivePath)),
|
|
334
|
+
remaining_workstreams: remainingWs,
|
|
335
|
+
reverted_to_flat: remainingWs === 0,
|
|
336
|
+
}, raw);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
// ─── Active Workstream Commands ──────────────────────────────────────────────
|
|
340
|
+
|
|
341
|
+
function cmdWorkstreamSet(cwd, name, raw) {
|
|
342
|
+
if (!name || name === '--clear') {
|
|
343
|
+
if (name !== '--clear') {
|
|
344
|
+
error('Workstream name required. Usage: workstream set <name> (or workstream set --clear to unset)');
|
|
345
|
+
}
|
|
346
|
+
const previous = getActiveWorkstream(cwd);
|
|
347
|
+
setActiveWorkstream(cwd, null);
|
|
348
|
+
output({ active: null, cleared: true, previous: previous || null }, raw);
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
353
|
+
output({ active: null, error: 'invalid_name', message: 'Workstream name must be alphanumeric, hyphens, and underscores only' }, raw);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const wsDir = path.join(planningRoot(cwd), 'workstreams', name);
|
|
358
|
+
if (!fs.existsSync(wsDir)) {
|
|
359
|
+
output({ active: null, error: 'not_found', workstream: name }, raw);
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
setActiveWorkstream(cwd, name);
|
|
364
|
+
output({ active: name, set: true }, raw, name);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function cmdWorkstreamGet(cwd, raw) {
|
|
368
|
+
const active = getActiveWorkstream(cwd);
|
|
369
|
+
const wsRoot = path.join(planningRoot(cwd), 'workstreams');
|
|
370
|
+
output({ active, mode: fs.existsSync(wsRoot) ? 'workstream' : 'flat' }, raw, active || 'none');
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function cmdWorkstreamProgress(cwd, raw) {
|
|
374
|
+
const root = planningRoot(cwd);
|
|
375
|
+
const wsRoot = path.join(root, 'workstreams');
|
|
376
|
+
|
|
377
|
+
if (!fs.existsSync(wsRoot)) {
|
|
378
|
+
output({ mode: 'flat', workstreams: [], message: 'No workstreams — operating in flat mode' }, raw);
|
|
379
|
+
return;
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
const active = getActiveWorkstream(cwd);
|
|
383
|
+
const entries = fs.readdirSync(wsRoot, { withFileTypes: true });
|
|
384
|
+
const workstreams = [];
|
|
385
|
+
|
|
386
|
+
for (const entry of entries) {
|
|
387
|
+
if (!entry.isDirectory()) continue;
|
|
388
|
+
|
|
389
|
+
const wsDir = path.join(wsRoot, entry.name);
|
|
390
|
+
const phasesDir = path.join(wsDir, 'phases');
|
|
391
|
+
|
|
392
|
+
const phaseDirsProgress = readSubdirectories(phasesDir);
|
|
393
|
+
const phaseCount = phaseDirsProgress.length;
|
|
394
|
+
let completedCount = 0, totalPlans = 0, completedPlans = 0;
|
|
395
|
+
for (const d of phaseDirsProgress) {
|
|
396
|
+
try {
|
|
397
|
+
const phaseFiles = fs.readdirSync(path.join(phasesDir, d));
|
|
398
|
+
const plans = filterPlanFiles(phaseFiles);
|
|
399
|
+
const summaries = filterSummaryFiles(phaseFiles);
|
|
400
|
+
totalPlans += plans.length;
|
|
401
|
+
completedPlans += Math.min(summaries.length, plans.length);
|
|
402
|
+
if (plans.length > 0 && summaries.length >= plans.length) completedCount++;
|
|
403
|
+
} catch {}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
let roadmapPhaseCount = phaseCount;
|
|
407
|
+
try {
|
|
408
|
+
const roadmapContent = fs.readFileSync(path.join(wsDir, 'ROADMAP.md'), 'utf-8');
|
|
409
|
+
const phaseMatches = roadmapContent.match(/^###?\s+Phase\s+\d/gm);
|
|
410
|
+
if (phaseMatches) roadmapPhaseCount = phaseMatches.length;
|
|
411
|
+
} catch {}
|
|
412
|
+
|
|
413
|
+
let status = 'unknown', currentPhase = null;
|
|
414
|
+
try {
|
|
415
|
+
const stateContent = fs.readFileSync(path.join(wsDir, 'STATE.md'), 'utf-8');
|
|
416
|
+
status = stateExtractField(stateContent, 'Status') || 'unknown';
|
|
417
|
+
currentPhase = stateExtractField(stateContent, 'Current Phase');
|
|
418
|
+
} catch {}
|
|
419
|
+
|
|
420
|
+
workstreams.push({
|
|
421
|
+
name: entry.name,
|
|
422
|
+
active: entry.name === active,
|
|
423
|
+
status,
|
|
424
|
+
current_phase: currentPhase,
|
|
425
|
+
phases: `${completedCount}/${roadmapPhaseCount}`,
|
|
426
|
+
plans: `${completedPlans}/${totalPlans}`,
|
|
427
|
+
progress_percent: roadmapPhaseCount > 0 ? Math.round((completedCount / roadmapPhaseCount) * 100) : 0,
|
|
428
|
+
});
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
output({ mode: 'workstream', active, workstreams, count: workstreams.length }, raw);
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
// ─── Collision Detection ────────────────────────────────────────────────────
|
|
435
|
+
|
|
436
|
+
/**
|
|
437
|
+
* Return other workstreams that are NOT complete.
|
|
438
|
+
* Used to detect whether the milestone has active parallel work
|
|
439
|
+
* when a workstream finishes its last phase.
|
|
440
|
+
*/
|
|
441
|
+
function getOtherActiveWorkstreams(cwd, excludeWs) {
|
|
442
|
+
const wsRoot = path.join(planningRoot(cwd), 'workstreams');
|
|
443
|
+
if (!fs.existsSync(wsRoot)) return [];
|
|
444
|
+
|
|
445
|
+
const entries = fs.readdirSync(wsRoot, { withFileTypes: true });
|
|
446
|
+
const others = [];
|
|
447
|
+
|
|
448
|
+
for (const entry of entries) {
|
|
449
|
+
if (!entry.isDirectory() || entry.name === excludeWs) continue;
|
|
450
|
+
|
|
451
|
+
const wsDir = path.join(wsRoot, entry.name);
|
|
452
|
+
const statePath = path.join(wsDir, 'STATE.md');
|
|
453
|
+
|
|
454
|
+
let status = 'unknown', currentPhase = null;
|
|
455
|
+
try {
|
|
456
|
+
const content = fs.readFileSync(statePath, 'utf-8');
|
|
457
|
+
status = stateExtractField(content, 'Status') || 'unknown';
|
|
458
|
+
currentPhase = stateExtractField(content, 'Current Phase');
|
|
459
|
+
} catch {}
|
|
460
|
+
|
|
461
|
+
if (status.toLowerCase().includes('milestone complete') ||
|
|
462
|
+
status.toLowerCase().includes('archived')) {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const phasesDir = path.join(wsDir, 'phases');
|
|
467
|
+
const phaseDirsOther = readSubdirectories(phasesDir);
|
|
468
|
+
const phaseCount = phaseDirsOther.length;
|
|
469
|
+
let completedCount = 0;
|
|
470
|
+
for (const d of phaseDirsOther) {
|
|
471
|
+
try {
|
|
472
|
+
const phaseFiles = fs.readdirSync(path.join(phasesDir, d));
|
|
473
|
+
const plans = filterPlanFiles(phaseFiles);
|
|
474
|
+
const summaries = filterSummaryFiles(phaseFiles);
|
|
475
|
+
if (plans.length > 0 && summaries.length >= plans.length) completedCount++;
|
|
476
|
+
} catch {}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
others.push({ name: entry.name, status, current_phase: currentPhase, phases: `${completedCount}/${phaseCount}` });
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
return others;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
module.exports = {
|
|
486
|
+
migrateToWorkstreams,
|
|
487
|
+
cmdWorkstreamCreate,
|
|
488
|
+
cmdWorkstreamList,
|
|
489
|
+
cmdWorkstreamStatus,
|
|
490
|
+
cmdWorkstreamComplete,
|
|
491
|
+
cmdWorkstreamSet,
|
|
492
|
+
cmdWorkstreamGet,
|
|
493
|
+
cmdWorkstreamProgress,
|
|
494
|
+
getOtherActiveWorkstreams,
|
|
495
|
+
};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# Agent Contracts
|
|
2
|
+
|
|
3
|
+
Completion markers and handoff schemas for all GSD agents. Workflows use these markers to detect agent completion and route accordingly.
|
|
4
|
+
|
|
5
|
+
This doc describes what IS, not what should be. Casing inconsistencies are documented as they appear in agent source files.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Agent Registry
|
|
10
|
+
|
|
11
|
+
| Agent | Role | Completion Markers |
|
|
12
|
+
|-------|------|--------------------|
|
|
13
|
+
| gsd-planner | Plan creation | `## PLANNING COMPLETE` |
|
|
14
|
+
| gsd-executor | Plan execution | `## PLAN COMPLETE`, `## CHECKPOINT REACHED` |
|
|
15
|
+
| gsd-phase-researcher | Phase-scoped research | `## RESEARCH COMPLETE`, `## RESEARCH BLOCKED` |
|
|
16
|
+
| gsd-project-researcher | Project-wide research | `## RESEARCH COMPLETE`, `## RESEARCH BLOCKED` |
|
|
17
|
+
| gsd-plan-checker | Plan validation | `## VERIFICATION PASSED`, `## ISSUES FOUND` |
|
|
18
|
+
| gsd-research-synthesizer | Multi-research synthesis | `## SYNTHESIS COMPLETE`, `## SYNTHESIS BLOCKED` |
|
|
19
|
+
| gsd-debugger | Debug investigation | `## DEBUG COMPLETE`, `## ROOT CAUSE FOUND`, `## CHECKPOINT REACHED` |
|
|
20
|
+
| gsd-roadmapper | Roadmap creation/revision | `## ROADMAP CREATED`, `## ROADMAP REVISED`, `## ROADMAP BLOCKED` |
|
|
21
|
+
| gsd-ui-auditor | UI review | `## UI REVIEW COMPLETE` |
|
|
22
|
+
| gsd-ui-checker | UI validation | `## ISSUES FOUND` |
|
|
23
|
+
| gsd-ui-researcher | UI spec creation | `## UI-SPEC COMPLETE`, `## UI-SPEC BLOCKED` |
|
|
24
|
+
| gsd-verifier | Post-execution verification | `## Verification Complete` (title case) |
|
|
25
|
+
| gsd-integration-checker | Cross-phase integration check | `## Integration Check Complete` (title case) |
|
|
26
|
+
| gsd-nyquist-auditor | Sampling audit | `## PARTIAL`, `## ESCALATE` (non-standard) |
|
|
27
|
+
| gsd-security-auditor | Security audit | `## OPEN_THREATS`, `## ESCALATE` (non-standard) |
|
|
28
|
+
| gsd-codebase-mapper | Codebase analysis | No marker (writes docs directly) |
|
|
29
|
+
| gsd-assumptions-analyzer | Assumption extraction | No marker (returns `## Assumptions` sections) |
|
|
30
|
+
| gsd-doc-verifier | Doc validation | No marker (writes JSON to `.planning/tmp/`) |
|
|
31
|
+
| gsd-doc-writer | Doc generation | No marker (writes docs directly) |
|
|
32
|
+
| gsd-advisor-researcher | Advisory research | No marker (utility agent) |
|
|
33
|
+
| gsd-user-profiler | User profiling | No marker (returns JSON in analysis tags) |
|
|
34
|
+
| gsd-intel-updater | Codebase intelligence analysis | `## INTEL UPDATE COMPLETE`, `## INTEL UPDATE FAILED` |
|
|
35
|
+
|
|
36
|
+
## Marker Rules
|
|
37
|
+
|
|
38
|
+
1. **ALL-CAPS markers** (e.g., `## PLANNING COMPLETE`) are the standard convention
|
|
39
|
+
2. **Title-case markers** (e.g., `## Verification Complete`) exist in gsd-verifier and gsd-integration-checker -- these are intentional as-is, not bugs
|
|
40
|
+
3. **Non-standard markers** (e.g., `## PARTIAL`, `## ESCALATE`) in audit agents indicate partial results requiring orchestrator judgment
|
|
41
|
+
4. **Agents without markers** either write artifacts directly to disk or return structured data (JSON/sections) that the caller parses
|
|
42
|
+
5. Markers must appear as H2 headings (`## `) at the start of a line in the agent's final output
|
|
43
|
+
|
|
44
|
+
## Key Handoff Contracts
|
|
45
|
+
|
|
46
|
+
### Planner -> Executor (via PLAN.md)
|
|
47
|
+
|
|
48
|
+
| Field | Required | Description |
|
|
49
|
+
|-------|----------|-------------|
|
|
50
|
+
| Frontmatter | Yes | phase, plan, type, wave, depends_on, files_modified, autonomous, requirements |
|
|
51
|
+
| `<objective>` | Yes | What the plan achieves |
|
|
52
|
+
| `<tasks>` | Yes | Ordered task list with type, files, action, verify, acceptance_criteria |
|
|
53
|
+
| `<verification>` | Yes | Overall verification steps |
|
|
54
|
+
| `<success_criteria>` | Yes | Measurable completion criteria |
|
|
55
|
+
|
|
56
|
+
### Executor -> Verifier (via SUMMARY.md)
|
|
57
|
+
|
|
58
|
+
| Field | Required | Description |
|
|
59
|
+
|-------|----------|-------------|
|
|
60
|
+
| Frontmatter | Yes | phase, plan, subsystem, tags, key-files, metrics |
|
|
61
|
+
| Commits table | Yes | Per-task commit hashes and descriptions |
|
|
62
|
+
| Deviations section | Yes | Auto-fixed issues or "None" |
|
|
63
|
+
| Self-Check | Yes | PASSED or FAILED with details |
|
|
64
|
+
|
|
65
|
+
## Workflow Regex Patterns
|
|
66
|
+
|
|
67
|
+
Workflows match these markers to detect agent completion:
|
|
68
|
+
|
|
69
|
+
**plan-phase.md matches:**
|
|
70
|
+
- `## RESEARCH COMPLETE` / `## RESEARCH BLOCKED` (researcher output)
|
|
71
|
+
- `## PLANNING COMPLETE` (planner output)
|
|
72
|
+
- `## CHECKPOINT REACHED` (planner/executor pause)
|
|
73
|
+
- `## VERIFICATION PASSED` / `## ISSUES FOUND` (plan-checker output)
|
|
74
|
+
|
|
75
|
+
**execute-phase.md matches:**
|
|
76
|
+
- `## PHASE COMPLETE` (all plans in phase done)
|
|
77
|
+
- `## Self-Check: FAILED` (summary self-check)
|
|
78
|
+
|
|
79
|
+
> **NOTE:** `## PLAN COMPLETE` is the gsd-executor's completion marker but execute-phase.md does not regex-match it. Instead, it detects executor completion via spot-checks (SUMMARY.md existence, git commit state). This is intentional behavior, not a mismatch.
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
# GSD Artifact Types
|
|
2
|
+
|
|
3
|
+
This reference documents all artifact types in the GSD planning taxonomy. Each type has a defined
|
|
4
|
+
shape, lifecycle, location, and consumption mechanism. A well-formatted artifact that no workflow
|
|
5
|
+
reads is inert — the consumption mechanism is what gives an artifact meaning.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Core Artifacts
|
|
10
|
+
|
|
11
|
+
### ROADMAP.md
|
|
12
|
+
- **Shape**: Milestone + phase listing with goals and canonical refs
|
|
13
|
+
- **Lifecycle**: Created → Updated per milestone → Archived
|
|
14
|
+
- **Location**: `.planning/ROADMAP.md`
|
|
15
|
+
- **Consumed by**: `plan-phase`, `discuss-phase`, `execute-phase`, `progress`, `state` commands
|
|
16
|
+
|
|
17
|
+
### STATE.md
|
|
18
|
+
- **Shape**: Current position tracker (phase, plan, progress, decisions)
|
|
19
|
+
- **Lifecycle**: Continuously updated throughout the project
|
|
20
|
+
- **Location**: `.planning/STATE.md`
|
|
21
|
+
- **Consumed by**: All orchestration workflows; `resume-project`, `progress`, `next` commands
|
|
22
|
+
|
|
23
|
+
### REQUIREMENTS.md
|
|
24
|
+
- **Shape**: Numbered acceptance criteria with traceability table
|
|
25
|
+
- **Lifecycle**: Created at project start → Updated as requirements are satisfied
|
|
26
|
+
- **Location**: `.planning/REQUIREMENTS.md`
|
|
27
|
+
- **Consumed by**: `discuss-phase`, `plan-phase`, CONTEXT.md generation; executor marks complete
|
|
28
|
+
|
|
29
|
+
### CONTEXT.md (per-phase)
|
|
30
|
+
- **Shape**: 6-section format: domain, decisions, canonical_refs, code_context, specifics, deferred
|
|
31
|
+
- **Lifecycle**: Created before planning → Used during planning and execution → Superseded by next phase
|
|
32
|
+
- **Location**: `.planning/phases/XX-name/XX-CONTEXT.md`
|
|
33
|
+
- **Consumed by**: `plan-phase` (reads decisions), `execute-phase` (reads code_context and canonical_refs)
|
|
34
|
+
|
|
35
|
+
### PLAN.md (per-plan)
|
|
36
|
+
- **Shape**: Frontmatter + objective + tasks with types + success criteria + output spec
|
|
37
|
+
- **Lifecycle**: Created by planner → Executed → SUMMARY.md produced
|
|
38
|
+
- **Location**: `.planning/phases/XX-name/XX-YY-PLAN.md`
|
|
39
|
+
- **Consumed by**: `execute-phase` executor; task commits reference plan IDs
|
|
40
|
+
|
|
41
|
+
### SUMMARY.md (per-plan)
|
|
42
|
+
- **Shape**: Frontmatter with dependency graph + narrative + deviations + self-check
|
|
43
|
+
- **Lifecycle**: Created at plan completion → read by subsequent plans in same phase
|
|
44
|
+
- **Location**: `.planning/phases/XX-name/XX-YY-SUMMARY.md`
|
|
45
|
+
- **Consumed by**: Orchestrator (progress), planner (context for future plans), `milestone-summary`
|
|
46
|
+
|
|
47
|
+
### HANDOFF.json / .continue-here.md
|
|
48
|
+
- **Shape**: Structured pause state (JSON machine-readable + Markdown human-readable)
|
|
49
|
+
- **Lifecycle**: Created on pause → Consumed on resume → Replaced by next pause
|
|
50
|
+
- **Location**: `.planning/HANDOFF.json` + `.planning/phases/XX-name/.continue-here.md` (or spike/deliberation path)
|
|
51
|
+
- **Consumed by**: `resume-project` workflow
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Extended Artifacts
|
|
56
|
+
|
|
57
|
+
### DISCUSSION-LOG.md (per-phase)
|
|
58
|
+
- **Shape**: Audit trail of assumptions and corrections from discuss-phase
|
|
59
|
+
- **Lifecycle**: Created at discussion time → read-only audit record
|
|
60
|
+
- **Location**: `.planning/phases/XX-name/XX-DISCUSSION-LOG.md`
|
|
61
|
+
- **Consumed by**: Human review; not read by automated workflows
|
|
62
|
+
|
|
63
|
+
### USER-PROFILE.md
|
|
64
|
+
- **Shape**: Calibration tier and preferences profile
|
|
65
|
+
- **Lifecycle**: Created by `profile-user` → Updated as preferences are observed
|
|
66
|
+
- **Location**: `$HOME/.config/opencode/get-shit-done/USER-PROFILE.md`
|
|
67
|
+
- **Consumed by**: `discuss-phase-assumptions` (calibration tier), `plan-phase`
|
|
68
|
+
|
|
69
|
+
### SPIKE.md / DESIGN.md (per-spike)
|
|
70
|
+
- **Shape**: Research question + methodology + findings + recommendation
|
|
71
|
+
- **Lifecycle**: Created → Investigated → Decided → Archived
|
|
72
|
+
- **Location**: `.planning/spikes/SPIKE-NNN/`
|
|
73
|
+
- **Consumed by**: Planner when spike is referenced; `pause-work` for spike context handoff
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Standing Reference Artifacts
|
|
78
|
+
|
|
79
|
+
### METHODOLOGY.md
|
|
80
|
+
|
|
81
|
+
- **Shape**: Standing reference — reusable interpretive frameworks (lenses) that apply across phases
|
|
82
|
+
- **Lifecycle**: Created → Active → Superseded (when a lens is replaced by a better one)
|
|
83
|
+
- **Location**: `.planning/METHODOLOGY.md` (project-scoped, not phase-scoped)
|
|
84
|
+
- **Contents**: Named lenses, each documenting:
|
|
85
|
+
- What it diagnoses (the class of problem it detects)
|
|
86
|
+
- What it recommends (the class of response it prescribes)
|
|
87
|
+
- When to apply (triggering conditions)
|
|
88
|
+
- Example: Bayesian updating, STRIDE threat modeling, Cost-of-delay prioritization
|
|
89
|
+
- **Consumed by**:
|
|
90
|
+
- `discuss-phase-assumptions` — reads METHODOLOGY.md (if it exists) and applies active lenses
|
|
91
|
+
to the current assumption analysis before surfacing findings to the user
|
|
92
|
+
- `plan-phase` — reads METHODOLOGY.md to inform methodology selection for each plan
|
|
93
|
+
- `pause-work` — includes METHODOLOGY.md in the Required Reading section of `.continue-here.md`
|
|
94
|
+
so resuming agents inherit the project's analytical orientation
|
|
95
|
+
|
|
96
|
+
**Why consumption matters:** A METHODOLOGY.md that no workflow reads is inert. The lenses only
|
|
97
|
+
take effect when an agent loads them into its reasoning context before analysis. This is why
|
|
98
|
+
both the discuss-phase-assumptions and pause-work workflows explicitly reference this file.
|
|
99
|
+
|
|
100
|
+
**Example lens entry:**
|
|
101
|
+
|
|
102
|
+
```markdown
|
|
103
|
+
## Bayesian Updating
|
|
104
|
+
|
|
105
|
+
**Diagnoses:** Decisions made with stale priors — assumptions formed early that evidence has since
|
|
106
|
+
contradicted, but which remain embedded in the plan.
|
|
107
|
+
|
|
108
|
+
**Recommends:** Before confirming an assumption, ask: "What evidence would make me change this?"
|
|
109
|
+
If no evidence could change it, it's a belief, not an assumption. Flag for user review.
|
|
110
|
+
|
|
111
|
+
**Apply when:** Any assumption carries Confident label but was formed before recent architectural
|
|
112
|
+
changes, library upgrades, or scope corrections.
|
|
113
|
+
```
|