gspec 1.6.0 → 1.10.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/README.md +4 -7
- package/bin/gspec.js +275 -8
- package/commands/gspec.analyze.md +2 -4
- package/commands/gspec.architect.md +2 -3
- package/commands/gspec.feature.md +37 -7
- package/commands/gspec.implement.md +14 -19
- package/commands/gspec.migrate.md +1 -2
- package/commands/gspec.practices.md +3 -1
- package/commands/gspec.research.md +1 -1
- package/commands/gspec.stack.md +11 -6
- package/commands/gspec.style.md +18 -23
- package/dist/antigravity/gspec-analyze/SKILL.md +2 -4
- package/dist/antigravity/gspec-architect/SKILL.md +3 -4
- package/dist/antigravity/gspec-feature/SKILL.md +39 -9
- package/dist/antigravity/gspec-implement/SKILL.md +15 -20
- package/dist/antigravity/gspec-migrate/SKILL.md +6 -7
- package/dist/antigravity/gspec-practices/SKILL.md +4 -2
- package/dist/antigravity/gspec-profile/SKILL.md +1 -1
- package/dist/antigravity/gspec-research/SKILL.md +4 -4
- package/dist/antigravity/gspec-stack/SKILL.md +12 -7
- package/dist/antigravity/gspec-style/SKILL.md +19 -24
- package/dist/claude/gspec-analyze/SKILL.md +2 -4
- package/dist/claude/gspec-architect/SKILL.md +3 -4
- package/dist/claude/gspec-feature/SKILL.md +39 -9
- package/dist/claude/gspec-implement/SKILL.md +15 -20
- package/dist/claude/gspec-migrate/SKILL.md +6 -7
- package/dist/claude/gspec-practices/SKILL.md +4 -2
- package/dist/claude/gspec-profile/SKILL.md +1 -1
- package/dist/claude/gspec-research/SKILL.md +4 -4
- package/dist/claude/gspec-stack/SKILL.md +12 -7
- package/dist/claude/gspec-style/SKILL.md +19 -24
- package/dist/codex/gspec-analyze/SKILL.md +2 -4
- package/dist/codex/gspec-architect/SKILL.md +3 -4
- package/dist/codex/gspec-feature/SKILL.md +39 -9
- package/dist/codex/gspec-implement/SKILL.md +15 -20
- package/dist/codex/gspec-migrate/SKILL.md +6 -7
- package/dist/codex/gspec-practices/SKILL.md +4 -2
- package/dist/codex/gspec-profile/SKILL.md +1 -1
- package/dist/codex/gspec-research/SKILL.md +4 -4
- package/dist/codex/gspec-stack/SKILL.md +12 -7
- package/dist/codex/gspec-style/SKILL.md +19 -24
- package/dist/cursor/gspec-analyze.mdc +2 -4
- package/dist/cursor/gspec-architect.mdc +3 -4
- package/dist/cursor/gspec-feature.mdc +39 -9
- package/dist/cursor/gspec-implement.mdc +15 -20
- package/dist/cursor/gspec-migrate.mdc +6 -7
- package/dist/cursor/gspec-practices.mdc +4 -2
- package/dist/cursor/gspec-profile.mdc +1 -1
- package/dist/cursor/gspec-research.mdc +4 -4
- package/dist/cursor/gspec-stack.mdc +12 -7
- package/dist/cursor/gspec-style.mdc +19 -24
- package/dist/opencode/gspec-analyze/SKILL.md +168 -0
- package/dist/opencode/gspec-architect/SKILL.md +361 -0
- package/dist/opencode/gspec-feature/SKILL.md +204 -0
- package/dist/opencode/gspec-implement/SKILL.md +200 -0
- package/dist/opencode/gspec-migrate/SKILL.md +118 -0
- package/dist/opencode/gspec-practices/SKILL.md +137 -0
- package/dist/opencode/gspec-profile/SKILL.md +221 -0
- package/dist/opencode/gspec-research/SKILL.md +302 -0
- package/dist/opencode/gspec-stack/SKILL.md +305 -0
- package/dist/opencode/gspec-style/SKILL.md +224 -0
- package/package.json +3 -1
- package/starters/features/about-page.md +98 -0
- package/starters/features/contact-form.md +147 -0
- package/starters/features/contact-page.md +103 -0
- package/starters/features/home-page.md +103 -0
- package/starters/features/responsive-navbar.md +113 -0
- package/starters/features/services-page.md +103 -0
- package/starters/features/site-footer.md +121 -0
- package/starters/features/theme-switcher.md +124 -0
- package/starters/practices/tdd-pipeline-first.md +192 -0
- package/starters/stacks/astro-tailwind-github-pages.md +283 -0
- package/starters/stacks/nextjs-supabase-vercel.md +319 -0
- package/starters/stacks/nextjs-vercel-typescript.md +264 -0
- package/starters/styles/clean-professional.md +316 -0
- package/starters/styles/dark-minimal-developer.md +442 -0
- package/templates/spec-sync.md +2 -2
- package/commands/gspec.epic.md +0 -228
- package/dist/antigravity/gspec-epic/SKILL.md +0 -232
- package/dist/claude/gspec-epic/SKILL.md +0 -233
- package/dist/codex/gspec-epic/SKILL.md +0 -232
- package/dist/cursor/gspec-epic.mdc +0 -231
package/README.md
CHANGED
|
@@ -25,7 +25,7 @@ These documents become the shared context for all subsequent AI interactions. Wh
|
|
|
25
25
|
|
|
26
26
|
The only commands you *need* are the four fundamentals and `implement`. Everything else exists to help when your project calls for it.
|
|
27
27
|
|
|
28
|
-
The fundamentals give your AI tool enough context to build well — it knows what the product is, how it should look, what technologies to use, and what engineering standards to follow. From there, `implement` can take a plain-language description and start building. The remaining commands — `research`, `feature`, `
|
|
28
|
+
The fundamentals give your AI tool enough context to build well — it knows what the product is, how it should look, what technologies to use, and what engineering standards to follow. From there, `implement` can take a plain-language description and start building. The remaining commands — `research`, `feature`, `architect`, `analyze`, `dor`, and `record` — add structure and rigor when the scope or complexity warrants it.
|
|
29
29
|
|
|
30
30
|
```mermaid
|
|
31
31
|
flowchart LR
|
|
@@ -37,7 +37,7 @@ flowchart LR
|
|
|
37
37
|
competitive analysis"]
|
|
38
38
|
|
|
39
39
|
Specify["3. Specify
|
|
40
|
-
feature
|
|
40
|
+
feature"]
|
|
41
41
|
|
|
42
42
|
Architect["4. Architect
|
|
43
43
|
technical blueprint"]
|
|
@@ -97,10 +97,9 @@ Use `research` when you want to understand what competitors offer, identify tabl
|
|
|
97
97
|
|
|
98
98
|
| Command | Role | What it produces |
|
|
99
99
|
|---|---|---|
|
|
100
|
-
| `gspec.feature` | Product Manager |
|
|
101
|
-
| `gspec.epic` | Product Manager | Breaks a large epic into multiple feature PRDs with dependency mapping |
|
|
100
|
+
| `gspec.feature` | Product Manager | One or more feature PRDs with prioritized capabilities |
|
|
102
101
|
|
|
103
|
-
Use `feature` when you want
|
|
102
|
+
Use `feature` when you want detailed PRDs with prioritized capabilities and acceptance criteria before building. It handles both single features and larger bodies of work — if the scope is large enough, it will propose a multi-feature breakdown for your approval. For smaller tasks or rapid prototyping, you can skip straight to `implement` with a plain-language description.
|
|
104
103
|
|
|
105
104
|
**4. Architect** *(optional)* — Translate specs into a concrete technical blueprint.
|
|
106
105
|
|
|
@@ -182,8 +181,6 @@ project-root/
|
|
|
182
181
|
├── practices.md # Development standards
|
|
183
182
|
├── architecture.md # Technical architecture blueprint
|
|
184
183
|
├── research.md # Competitive analysis and feature gaps
|
|
185
|
-
├── epics/
|
|
186
|
-
│ └── onboarding-flow.md
|
|
187
184
|
└── features/
|
|
188
185
|
├── user-authentication.md
|
|
189
186
|
├── dashboard-analytics.md
|
package/bin/gspec.js
CHANGED
|
@@ -9,6 +9,7 @@ import chalk from 'chalk';
|
|
|
9
9
|
|
|
10
10
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
11
|
const DIST_DIR = join(__dirname, '..', 'dist');
|
|
12
|
+
const STARTERS_DIR = join(__dirname, '..', 'starters');
|
|
12
13
|
const pkg = JSON.parse(await readFile(join(__dirname, '..', 'package.json'), 'utf-8'));
|
|
13
14
|
|
|
14
15
|
const BANNER = `
|
|
@@ -51,6 +52,12 @@ const TARGETS = {
|
|
|
51
52
|
label: 'Codex',
|
|
52
53
|
layout: 'directory',
|
|
53
54
|
},
|
|
55
|
+
opencode: {
|
|
56
|
+
sourceDir: join(DIST_DIR, 'opencode'),
|
|
57
|
+
installDir: '.opencode/skills',
|
|
58
|
+
label: 'Open Code',
|
|
59
|
+
layout: 'directory',
|
|
60
|
+
},
|
|
54
61
|
};
|
|
55
62
|
|
|
56
63
|
const TARGET_CHOICES = [
|
|
@@ -58,6 +65,7 @@ const TARGET_CHOICES = [
|
|
|
58
65
|
{ key: '2', name: 'cursor', label: 'Cursor' },
|
|
59
66
|
{ key: '3', name: 'antigravity', label: 'Antigravity' },
|
|
60
67
|
{ key: '4', name: 'codex', label: 'Codex' },
|
|
68
|
+
{ key: '5', name: 'opencode', label: 'Open Code' },
|
|
61
69
|
];
|
|
62
70
|
|
|
63
71
|
function promptTarget() {
|
|
@@ -70,7 +78,7 @@ function promptTarget() {
|
|
|
70
78
|
console.log();
|
|
71
79
|
|
|
72
80
|
return new Promise((resolve) => {
|
|
73
|
-
rl.question(chalk.bold(' Select [1-
|
|
81
|
+
rl.question(chalk.bold(' Select [1-5]: '), (answer) => {
|
|
74
82
|
rl.close();
|
|
75
83
|
const trimmed = answer.trim().toLowerCase();
|
|
76
84
|
|
|
@@ -83,7 +91,7 @@ function promptTarget() {
|
|
|
83
91
|
if (byName) return resolve(byName.name);
|
|
84
92
|
|
|
85
93
|
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
86
|
-
console.error(`Valid options: 1, 2, 3, 4, claude, cursor, antigravity, codex`);
|
|
94
|
+
console.error(`Valid options: 1, 2, 3, 4, 5, claude, cursor, antigravity, codex, opencode`);
|
|
87
95
|
process.exit(1);
|
|
88
96
|
});
|
|
89
97
|
});
|
|
@@ -109,6 +117,246 @@ function promptConfirmNo(message) {
|
|
|
109
117
|
});
|
|
110
118
|
}
|
|
111
119
|
|
|
120
|
+
// --- Feature dependency map ---
|
|
121
|
+
// Maps feature slugs to their required feature dependencies (other feature slugs).
|
|
122
|
+
// This is used to auto-include dependencies when a user selects a feature.
|
|
123
|
+
const FEATURE_DEPENDENCIES = {
|
|
124
|
+
'home-page': [],
|
|
125
|
+
'about-page': ['home-page'],
|
|
126
|
+
'contact-page': ['home-page'],
|
|
127
|
+
'services-page': ['home-page'],
|
|
128
|
+
'responsive-navbar': ['home-page'],
|
|
129
|
+
'contact-form': ['contact-page'],
|
|
130
|
+
'site-footer': ['home-page', 'about-page', 'contact-page'],
|
|
131
|
+
'theme-switcher': ['home-page', 'about-page', 'contact-page'],
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
function resolveFeatureDependencies(selectedSlugs) {
|
|
135
|
+
const resolved = new Set(selectedSlugs);
|
|
136
|
+
let changed = true;
|
|
137
|
+
while (changed) {
|
|
138
|
+
changed = false;
|
|
139
|
+
for (const slug of [...resolved]) {
|
|
140
|
+
const deps = FEATURE_DEPENDENCIES[slug] || [];
|
|
141
|
+
for (const dep of deps) {
|
|
142
|
+
if (!resolved.has(dep)) {
|
|
143
|
+
resolved.add(dep);
|
|
144
|
+
changed = true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return [...resolved];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// --- Starter template utilities ---
|
|
153
|
+
|
|
154
|
+
async function parseStarterDescription(filePath) {
|
|
155
|
+
const content = await readFile(filePath, 'utf-8');
|
|
156
|
+
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
|
157
|
+
if (!match) return '';
|
|
158
|
+
const descLine = match[1].split('\n').find((l) => l.startsWith('description:'));
|
|
159
|
+
return descLine ? descLine.replace(/^description:\s*/, '').trim() : '';
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
async function listStarterTemplates(category) {
|
|
163
|
+
const dir = join(STARTERS_DIR, category);
|
|
164
|
+
let entries;
|
|
165
|
+
try {
|
|
166
|
+
entries = await readdir(dir);
|
|
167
|
+
} catch (e) {
|
|
168
|
+
if (e.code === 'ENOENT') return [];
|
|
169
|
+
throw e;
|
|
170
|
+
}
|
|
171
|
+
const mdFiles = entries.filter((f) => f.endsWith('.md'));
|
|
172
|
+
const templates = [];
|
|
173
|
+
for (const f of mdFiles) {
|
|
174
|
+
const slug = f.replace(/\.md$/, '');
|
|
175
|
+
const description = await parseStarterDescription(join(dir, f));
|
|
176
|
+
templates.push({ slug, description });
|
|
177
|
+
}
|
|
178
|
+
return templates;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function formatStarterName(slug) {
|
|
182
|
+
if (slug === '_none') return 'None';
|
|
183
|
+
return slug
|
|
184
|
+
.split('-')
|
|
185
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
186
|
+
.join(' ');
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function stampVersion(content) {
|
|
190
|
+
return content.replace(/^(---\s*\n[\s\S]*?)gspec-version:\s*.+/m, `$1gspec-version: ${pkg.version}`);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function promptSelect(message, choices) {
|
|
194
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
195
|
+
console.log(chalk.bold(`\n${message}\n`));
|
|
196
|
+
for (let i = 0; i < choices.length; i++) {
|
|
197
|
+
const label = formatStarterName(choices[i].slug);
|
|
198
|
+
const desc = choices[i].description ? ` — ${choices[i].description}` : '';
|
|
199
|
+
console.log(` ${chalk.cyan(String(i + 1))}) ${label}${desc}`);
|
|
200
|
+
}
|
|
201
|
+
console.log();
|
|
202
|
+
|
|
203
|
+
return new Promise((resolve) => {
|
|
204
|
+
rl.question(chalk.bold(` Select [1-${choices.length}]: `), (answer) => {
|
|
205
|
+
rl.close();
|
|
206
|
+
const num = parseInt(answer.trim(), 10);
|
|
207
|
+
if (num >= 1 && num <= choices.length) return resolve(choices[num - 1].slug);
|
|
208
|
+
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
209
|
+
process.exit(1);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function promptMultiSelect(message, choices) {
|
|
215
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
216
|
+
console.log(chalk.bold(`\n${message}\n`));
|
|
217
|
+
for (let i = 0; i < choices.length; i++) {
|
|
218
|
+
const label = formatStarterName(choices[i].slug);
|
|
219
|
+
const desc = choices[i].description ? ` — ${choices[i].description}` : '';
|
|
220
|
+
console.log(` ${chalk.cyan(String(i + 1))}) ${label}${desc}`);
|
|
221
|
+
}
|
|
222
|
+
console.log();
|
|
223
|
+
|
|
224
|
+
return new Promise((resolve) => {
|
|
225
|
+
rl.question(chalk.bold(' Enter numbers (comma-separated), "all", or press Enter to skip: '), (answer) => {
|
|
226
|
+
rl.close();
|
|
227
|
+
const trimmed = answer.trim().toLowerCase();
|
|
228
|
+
if (trimmed === '') return resolve([]);
|
|
229
|
+
if (trimmed === 'all') return resolve(choices.map((c) => c.slug));
|
|
230
|
+
|
|
231
|
+
const nums = trimmed.split(',').map((s) => parseInt(s.trim(), 10));
|
|
232
|
+
const invalid = nums.find((n) => isNaN(n) || n < 1 || n > choices.length);
|
|
233
|
+
if (invalid !== undefined) {
|
|
234
|
+
console.error(chalk.red(`\nInvalid selection: "${answer.trim()}"`));
|
|
235
|
+
process.exit(1);
|
|
236
|
+
}
|
|
237
|
+
resolve(nums.map((n) => choices[n - 1].slug));
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async function seedStarterTemplates(cwd) {
|
|
243
|
+
const wantStarters = await promptConfirm(chalk.bold(' Would you like to start from a starter template? [y/N]: '));
|
|
244
|
+
if (!wantStarters) {
|
|
245
|
+
console.log(chalk.dim('\n Skipped starter templates.\n'));
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const practices = await listStarterTemplates('practices');
|
|
250
|
+
const stacks = await listStarterTemplates('stacks');
|
|
251
|
+
const styles = await listStarterTemplates('styles');
|
|
252
|
+
const features = await listStarterTemplates('features');
|
|
253
|
+
|
|
254
|
+
if (practices.length === 0 || stacks.length === 0 || styles.length === 0) {
|
|
255
|
+
console.log(chalk.yellow(' Missing starter templates (practices, stacks, or styles). Skipping.\n'));
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const NONE_OPTION = { slug: '_none', description: 'I will define my own' };
|
|
260
|
+
|
|
261
|
+
// Single-select with auto-select for single-option categories
|
|
262
|
+
const practice = practices.length === 1
|
|
263
|
+
? (console.log(chalk.dim(`\n Using practice: ${formatStarterName(practices[0].slug)}`)), practices[0].slug)
|
|
264
|
+
: await promptSelect('Select a development practice', [...practices, NONE_OPTION]);
|
|
265
|
+
|
|
266
|
+
const stack = stacks.length === 1
|
|
267
|
+
? (console.log(chalk.dim(` Using stack: ${formatStarterName(stacks[0].slug)}`)), stacks[0].slug)
|
|
268
|
+
: await promptSelect('Select a technology stack', [...stacks, NONE_OPTION]);
|
|
269
|
+
|
|
270
|
+
const style = styles.length === 1
|
|
271
|
+
? (console.log(chalk.dim(` Using style: ${formatStarterName(styles[0].slug)}`)), styles[0].slug)
|
|
272
|
+
: await promptSelect('Select a visual style', [...styles, NONE_OPTION]);
|
|
273
|
+
|
|
274
|
+
let selectedFeatures = [];
|
|
275
|
+
if (features.length > 0) {
|
|
276
|
+
selectedFeatures = await promptMultiSelect('Select features (optional)', [...features, NONE_OPTION]);
|
|
277
|
+
selectedFeatures = selectedFeatures.filter(f => f !== '_none');
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Auto-include feature dependencies
|
|
281
|
+
if (selectedFeatures.length > 0) {
|
|
282
|
+
const resolved = resolveFeatureDependencies(selectedFeatures);
|
|
283
|
+
const added = resolved.filter((f) => !selectedFeatures.includes(f));
|
|
284
|
+
if (added.length > 0) {
|
|
285
|
+
console.log(chalk.cyan(`\n Auto-including dependencies: ${added.map(formatStarterName).join(', ')}`));
|
|
286
|
+
selectedFeatures = resolved;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// Check for existing files
|
|
291
|
+
const gspecDir = join(cwd, 'gspec');
|
|
292
|
+
const filesToWrite = [];
|
|
293
|
+
if (practice !== '_none') {
|
|
294
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'practices', `${practice}.md`), dest: join(gspecDir, 'practices.md'), label: 'gspec/practices.md' });
|
|
295
|
+
}
|
|
296
|
+
if (stack !== '_none') {
|
|
297
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'stacks', `${stack}.md`), dest: join(gspecDir, 'stack.md'), label: 'gspec/stack.md' });
|
|
298
|
+
}
|
|
299
|
+
if (style !== '_none') {
|
|
300
|
+
filesToWrite.push({ src: join(STARTERS_DIR, 'styles', `${style}.md`), dest: join(gspecDir, 'style.md'), label: 'gspec/style.md' });
|
|
301
|
+
}
|
|
302
|
+
for (const feature of selectedFeatures) {
|
|
303
|
+
filesToWrite.push({
|
|
304
|
+
src: join(STARTERS_DIR, 'features', `${feature}.md`),
|
|
305
|
+
dest: join(gspecDir, 'features', `${feature}.md`),
|
|
306
|
+
label: `gspec/features/${feature}.md`,
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const existingFiles = [];
|
|
311
|
+
for (const f of filesToWrite) {
|
|
312
|
+
try {
|
|
313
|
+
await stat(f.dest);
|
|
314
|
+
existingFiles.push(f.label);
|
|
315
|
+
} catch (e) {
|
|
316
|
+
if (e.code !== 'ENOENT') throw e;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (filesToWrite.length === 0) {
|
|
321
|
+
console.log(chalk.dim('\n No starter templates selected. You can define these files using gspec commands.\n'));
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
if (existingFiles.length > 0) {
|
|
326
|
+
console.log(chalk.yellow(`\n The following files already exist and will be overwritten:\n`));
|
|
327
|
+
for (const label of existingFiles) {
|
|
328
|
+
console.log(` ${chalk.yellow('!')} ${label}`);
|
|
329
|
+
}
|
|
330
|
+
console.log();
|
|
331
|
+
const confirmed = await promptConfirm(chalk.bold(' Continue and overwrite? [y/N]: '));
|
|
332
|
+
if (!confirmed) {
|
|
333
|
+
console.log(chalk.dim('\n Skipped starter templates.\n'));
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// Copy files with version stamping
|
|
339
|
+
console.log(chalk.bold('\n Seeding starter templates...\n'));
|
|
340
|
+
for (const f of filesToWrite) {
|
|
341
|
+
await mkdir(dirname(f.dest), { recursive: true });
|
|
342
|
+
const content = await readFile(f.src, 'utf-8');
|
|
343
|
+
await writeFile(f.dest, stampVersion(content), 'utf-8');
|
|
344
|
+
console.log(` ${chalk.green('+')} ${f.label}`);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Summary
|
|
348
|
+
console.log(chalk.bold('\n Seeded gspec/ with:'));
|
|
349
|
+
console.log(` Practice: ${practice === '_none' ? chalk.dim('(will define)') : formatStarterName(practice)}`);
|
|
350
|
+
console.log(` Stack: ${stack === '_none' ? chalk.dim('(will define)') : formatStarterName(stack)}`);
|
|
351
|
+
console.log(` Style: ${style === '_none' ? chalk.dim('(will define)') : formatStarterName(style)}`);
|
|
352
|
+
if (selectedFeatures.length > 0) {
|
|
353
|
+
console.log(` Features: ${selectedFeatures.map(formatStarterName).join(', ')}`);
|
|
354
|
+
} else {
|
|
355
|
+
console.log(` Features: ${chalk.dim('(will define)')}`);
|
|
356
|
+
}
|
|
357
|
+
console.log();
|
|
358
|
+
}
|
|
359
|
+
|
|
112
360
|
async function findExistingFiles(target, cwd) {
|
|
113
361
|
const existing = [];
|
|
114
362
|
const destBase = join(cwd, target.installDir);
|
|
@@ -257,6 +505,11 @@ const SPEC_SYNC = {
|
|
|
257
505
|
mode: 'append',
|
|
258
506
|
wrap: (content) => content,
|
|
259
507
|
},
|
|
508
|
+
opencode: {
|
|
509
|
+
file: 'AGENTS.md',
|
|
510
|
+
mode: 'append',
|
|
511
|
+
wrap: (content) => content,
|
|
512
|
+
},
|
|
260
513
|
};
|
|
261
514
|
|
|
262
515
|
const GSPEC_SECTION_MARKER = '<!-- gspec:spec-sync -->';
|
|
@@ -312,6 +565,7 @@ const MIGRATE_COMMANDS = {
|
|
|
312
565
|
cursor: '/gspec-migrate',
|
|
313
566
|
antigravity: '/gspec-migrate',
|
|
314
567
|
codex: '/gspec-migrate',
|
|
568
|
+
opencode: '/gspec-migrate',
|
|
315
569
|
};
|
|
316
570
|
|
|
317
571
|
function parseGspecVersion(content) {
|
|
@@ -326,7 +580,7 @@ async function collectGspecFiles(gspecDir) {
|
|
|
326
580
|
|
|
327
581
|
const topEntries = await readdir(gspecDir);
|
|
328
582
|
for (const entry of topEntries) {
|
|
329
|
-
if (entry.endsWith('.md')) {
|
|
583
|
+
if (entry.endsWith('.md') && entry.toLowerCase() !== 'readme.md') {
|
|
330
584
|
files.push({ path: join(gspecDir, entry), label: `gspec/${entry}` });
|
|
331
585
|
}
|
|
332
586
|
}
|
|
@@ -394,7 +648,7 @@ program
|
|
|
394
648
|
.name('gspec')
|
|
395
649
|
.description('Install gspec specification commands')
|
|
396
650
|
.version(pkg.version)
|
|
397
|
-
.option('-t, --target <target>', 'target platform (claude, cursor, antigravity, codex)')
|
|
651
|
+
.option('-t, --target <target>', 'target platform (claude, cursor, antigravity, codex, opencode)')
|
|
398
652
|
.action(async (opts) => {
|
|
399
653
|
console.log(BANNER);
|
|
400
654
|
|
|
@@ -406,12 +660,25 @@ program
|
|
|
406
660
|
|
|
407
661
|
await install(targetName, process.cwd());
|
|
408
662
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
}
|
|
663
|
+
await seedStarterTemplates(process.cwd());
|
|
664
|
+
|
|
665
|
+
await installSpecSync(targetName, process.cwd());
|
|
413
666
|
|
|
414
667
|
await checkGspecFiles(process.cwd(), targetName);
|
|
668
|
+
|
|
669
|
+
// Post-install: instruct user to generate profile.md
|
|
670
|
+
const targetLabel = TARGETS[targetName].label;
|
|
671
|
+
console.log();
|
|
672
|
+
console.log(chalk.bold.cyan(' ═══ Next Step ═══════════════════════════════════════════════'));
|
|
673
|
+
console.log();
|
|
674
|
+
console.log(chalk.bold.white(' Generate your product profile before continuing.'));
|
|
675
|
+
console.log();
|
|
676
|
+
console.log(` Run ${chalk.bold.yellow('/gspec-profile')} in ${targetLabel} to create gspec/profile.md`);
|
|
677
|
+
console.log(` — it defines what your product is, who it serves, and why it`);
|
|
678
|
+
console.log(` exists. All other gspec commands use the profile as their foundation.`);
|
|
679
|
+
console.log();
|
|
680
|
+
console.log(chalk.bold.cyan(' ═════════════════════════════════════════════════════════════'));
|
|
681
|
+
console.log();
|
|
415
682
|
});
|
|
416
683
|
|
|
417
684
|
program.parse();
|
|
@@ -23,12 +23,11 @@ Read **every** available gspec document in this order:
|
|
|
23
23
|
|
|
24
24
|
1. `gspec/profile.md` — Product identity, scope, audience, and positioning
|
|
25
25
|
2. `gspec/stack.md` — Technology choices, frameworks, infrastructure
|
|
26
|
-
3. `gspec/style.md` — Visual design language, tokens, component
|
|
26
|
+
3. `gspec/style.md` — Visual design language, tokens, component styling
|
|
27
27
|
4. `gspec/practices.md` — Development standards, testing, conventions
|
|
28
28
|
5. `gspec/architecture.md` — Technical blueprint: project structure, data model, API design, environment
|
|
29
29
|
6. `gspec/research.md` — Competitive analysis and feature proposals
|
|
30
|
-
7. `gspec/
|
|
31
|
-
8. `gspec/features/*.md` — Individual feature requirements
|
|
30
|
+
7. `gspec/features/*.md` — Individual feature requirements and dependencies
|
|
32
31
|
|
|
33
32
|
If fewer than two spec files exist, inform the user that there is nothing to cross-reference and stop.
|
|
34
33
|
|
|
@@ -64,7 +63,6 @@ Systematically compare specs against each other. Look for these categories of di
|
|
|
64
63
|
#### Scope & Priority Conflicts
|
|
65
64
|
- A feature capability is marked P0 in one place but P1 or P2 in another
|
|
66
65
|
- Profile describes scope or positioning that conflicts with what features actually define
|
|
67
|
-
- Epic dependency ordering conflicts with feature priority levels
|
|
68
66
|
- Research recommendations conflict with decisions already made in other specs
|
|
69
67
|
|
|
70
68
|
#### Behavioral Conflicts
|
|
@@ -4,7 +4,7 @@ Your task is to take the established product specifications and produce a **Tech
|
|
|
4
4
|
|
|
5
5
|
Beyond defining the architecture, you are also responsible for **identifying technical gaps and ambiguities** in the existing specs and **proposing implementation solutions**. This is the place in the gspec workflow where underspecified technical behavior is surfaced and resolved — so that `gspec-implement` can focus on building rather than making architectural decisions.
|
|
6
6
|
|
|
7
|
-
This command is meant to be run **after** the foundation specs (profile, stack, style, practices) and feature specs
|
|
7
|
+
This command is meant to be run **after** the foundation specs (profile, stack, style, practices) and feature specs are defined, and **before** `gspec-implement`.
|
|
8
8
|
|
|
9
9
|
You should:
|
|
10
10
|
- Read all existing gspec documents first — this architecture must serve the product, stack, style, and features already defined
|
|
@@ -27,8 +27,7 @@ Before generating the architecture document, read **all** existing gspec documen
|
|
|
27
27
|
2. **`gspec/stack.md`** — Technology choices, frameworks, and infrastructure. Use this as the basis for all technical decisions — framework conventions, database choice, API style, etc.
|
|
28
28
|
3. **`gspec/style.md`** — Design system and tokens. Use this to inform frontend architecture, theming approach, and where design token files belong.
|
|
29
29
|
4. **`gspec/practices.md`** — Development standards. Use this to align file organization, testing patterns, and code structure with team conventions.
|
|
30
|
-
5. **`gspec/
|
|
31
|
-
6. **`gspec/features/*.md`** — Individual feature requirements. Use these to derive data entities, API endpoints, component structure, and integration points.
|
|
30
|
+
5. **`gspec/features/*.md`** — Individual feature requirements and dependencies. Use these to derive data entities, API endpoints, component structure, and integration points.
|
|
32
31
|
|
|
33
32
|
All of these provide essential context. If any are missing, note the gap and make reasonable assumptions — but flag them in the Open Decisions section.
|
|
34
33
|
|
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
You are a senior Product Manager at a high-performing software company.
|
|
2
2
|
|
|
3
|
-
Your task is to take the provided feature description (which may be vague or detailed) and produce
|
|
3
|
+
Your task is to take the provided feature description (which may be vague or detailed, small or large) and produce **one or more Product Requirements Documents (PRDs)** that clearly define *what* is being built and *why*, without deep technical or architectural implementation details.
|
|
4
|
+
|
|
5
|
+
## Scope Assessment
|
|
6
|
+
|
|
7
|
+
Before writing anything, assess whether the user's description is:
|
|
8
|
+
|
|
9
|
+
1. **A single feature** — a focused piece of functionality that can be captured in one PRD (e.g., "user authentication", "CSV export", "dark mode support")
|
|
10
|
+
2. **A large body of work** — something broad enough that it should be decomposed into multiple independent features (e.g., "a complete onboarding experience", "a full e-commerce checkout flow", "social features for the app")
|
|
11
|
+
|
|
12
|
+
**If it's a single feature**, produce one PRD and save it to `gspec/features/`.
|
|
13
|
+
|
|
14
|
+
**If it's large enough to warrant multiple features:**
|
|
15
|
+
|
|
16
|
+
1. Propose a breakdown — list the distinct features you'd create, with a one-line description of each and their dependencies on each other
|
|
17
|
+
2. **Ask the user to confirm, adjust, or reprioritize** the breakdown before writing any specs
|
|
18
|
+
3. Once confirmed, generate a separate PRD for each feature in `gspec/features/`
|
|
19
|
+
|
|
20
|
+
When in doubt, lean toward fewer features. Don't over-decompose — a feature should only be split out if it delivers independent user value and has a meaningfully different scope.
|
|
4
21
|
|
|
5
22
|
## Important: Agent-Oriented Documentation
|
|
6
23
|
|
|
@@ -57,19 +74,20 @@ Feature PRDs are designed to be **portable across projects**. A feature spec wri
|
|
|
57
74
|
|
|
58
75
|
## Output Rules
|
|
59
76
|
|
|
60
|
-
- Output
|
|
61
|
-
- Save
|
|
62
|
-
- Name
|
|
63
|
-
- Begin
|
|
77
|
+
- Output one or more Markdown documents — **one per feature**
|
|
78
|
+
- Save each file to the `gspec/features/` folder in the root of the project, create it if it doesn't exist
|
|
79
|
+
- Name each file based on the feature (e.g., `user-authentication.md`, `dashboard-analytics.md`)
|
|
80
|
+
- Begin each file with YAML frontmatter containing the gspec version:
|
|
64
81
|
```
|
|
65
82
|
---
|
|
66
83
|
gspec-version: <<<VERSION>>>
|
|
67
84
|
---
|
|
68
85
|
```
|
|
69
86
|
The frontmatter must be the very first content in the file, before the main heading.
|
|
70
|
-
- **Before generating
|
|
87
|
+
- **Before generating any document, you MUST resolve ambiguities through conversation.** Ask clarifying questions in the chat if:
|
|
71
88
|
- The target users are unclear
|
|
72
89
|
- The scope or boundaries of the feature are ambiguous
|
|
90
|
+
- The breakdown into multiple features is not obvious (for large requests)
|
|
73
91
|
- Success criteria cannot be determined from the description
|
|
74
92
|
- Priority or urgency is unspecified
|
|
75
93
|
- Any assumption would materially change the shape of the spec
|
|
@@ -107,7 +125,7 @@ This separation — combined with the portability principles above — allows th
|
|
|
107
125
|
|
|
108
126
|
---
|
|
109
127
|
|
|
110
|
-
## Required Sections
|
|
128
|
+
## Required Sections (per feature PRD)
|
|
111
129
|
|
|
112
130
|
**IMPORTANT**: Only include the sections listed below. Do NOT add additional sections such as "Technology Notes", "Implementation Details", "Technical Architecture", or any other custom sections. Stick strictly to this structure.
|
|
113
131
|
|
|
@@ -157,11 +175,23 @@ This separation — combined with the portability principles above — allows th
|
|
|
157
175
|
|
|
158
176
|
---
|
|
159
177
|
|
|
178
|
+
## Multi-Feature Output
|
|
179
|
+
|
|
180
|
+
When generating multiple features from a large request:
|
|
181
|
+
|
|
182
|
+
- **Cross-reference dependencies** — each feature's Dependencies section should link to sibling features when applicable
|
|
183
|
+
- **Maintain consistent terminology** — use the same terms for shared concepts across all generated PRDs
|
|
184
|
+
- **Assign priorities holistically** — P0/P1/P2 levels should be consistent across the set (don't make everything P0)
|
|
185
|
+
- **Suggest a build order** — after generating all PRDs, briefly note the recommended implementation sequence based on dependencies (e.g., "Build `user-authentication` first, then `user-profiles`, then `social-connections`")
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
160
189
|
## Tone & Style
|
|
161
190
|
|
|
162
191
|
- Clear, neutral, product-led
|
|
163
192
|
- No fluff, no jargon
|
|
164
193
|
- Designed to be skimmed
|
|
194
|
+
- Consistent across all generated documents
|
|
165
195
|
|
|
166
196
|
---
|
|
167
197
|
|
|
@@ -2,13 +2,13 @@ You are a Senior Software Engineer and Tech Lead at a high-performing software c
|
|
|
2
2
|
|
|
3
3
|
Your task is to take the project's **gspec specification documents** and use them to **implement the software**. You bridge the gap between product requirements and working code. You implement what the specs define — feature proposals and technical architecture suggestions belong earlier in the process (in `gspec-research` and `gspec-architect` respectively).
|
|
4
4
|
|
|
5
|
-
**Features
|
|
5
|
+
**Features are optional.** When `gspec/features/*.md` exist, they guide implementation feature by feature. When they don't exist, you rely on the remaining gspec files (`profile.md`, `stack.md`, `style.md`, `practices.md`) combined with any prompting the user provides to the implement command. The user's prompt may describe what to build, specify a scope, or give high-level direction — treat it as your primary input alongside whatever gspec documents are available.
|
|
6
6
|
|
|
7
7
|
You should:
|
|
8
8
|
- Read and internalize all available gspec documents before writing any code
|
|
9
9
|
- Implement incrementally, one logical unit at a time
|
|
10
10
|
- Follow the project's defined stack, style, and practices exactly
|
|
11
|
-
- **When no features
|
|
11
|
+
- **When no features exist**, use the user's prompt and the remaining gspec files to determine what to build, then plan and implement incrementally
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -19,8 +19,7 @@ You should:
|
|
|
19
19
|
Before writing any code, read all available gspec documents in this order:
|
|
20
20
|
|
|
21
21
|
1. `gspec/profile.md` — Understand what the product is and who it's for
|
|
22
|
-
2. `gspec/
|
|
23
|
-
3. `gspec/features/*.md` — Understand individual feature requirements
|
|
22
|
+
2. `gspec/features/*.md` — Understand individual feature requirements and dependencies
|
|
24
23
|
> **Note:** Feature PRDs are designed to be portable and project-agnostic. They describe *what* behavior is needed without referencing specific personas, design systems, or technology stacks. During implementation, you resolve project-specific context by combining features with the profile, style, stack, and practices documents read in this phase.
|
|
25
24
|
4. `gspec/stack.md` — Understand the technology choices
|
|
26
25
|
5. `gspec/style.md` — Understand the visual design language
|
|
@@ -29,7 +28,7 @@ Before writing any code, read all available gspec documents in this order:
|
|
|
29
28
|
|
|
30
29
|
If any of these files are missing, note what's missing and proceed with what's available.
|
|
31
30
|
|
|
32
|
-
- **Features
|
|
31
|
+
- **Features are optional.** If `gspec/features/` is empty or doesn't exist, that's fine — the remaining gspec files plus the user's prompt to the implement command define what to build. Do not block on their absence or insist the user generate them first.
|
|
33
32
|
- For other missing files (profile, stack, style, practices), note the gap and ask the user if they want to generate them first or proceed without them.
|
|
34
33
|
|
|
35
34
|
#### Assess Implementation Status
|
|
@@ -47,8 +46,6 @@ For each feature PRD, build an implementation status summary:
|
|
|
47
46
|
|
|
48
47
|
Present this summary to the user so they understand the starting point. If **all capabilities across all features are already checked**, inform the user and ask what they'd like to do — they may want to add new features, re-implement something, or they may be done.
|
|
49
48
|
|
|
50
|
-
For epic summary files, check whether the features listed in the "Features Breakdown" section have checkboxes. A feature in an epic is considered complete when all its capabilities in the corresponding feature PRD are checked.
|
|
51
|
-
|
|
52
49
|
### Phase 2: Plan — Define the Build Order
|
|
53
50
|
|
|
54
51
|
**Enter plan mode** and create a concrete, phased implementation plan.
|
|
@@ -103,13 +100,12 @@ Present a brief scaffold summary to the user before proceeding to feature implem
|
|
|
103
100
|
|
|
104
101
|
1. **Announce the phase** — State which phase you're starting, what it covers, and what capabilities will be implemented
|
|
105
102
|
2. **Implement the phase:**
|
|
106
|
-
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`
|
|
107
|
-
b. **Follow the practices** — Adhere to coding standards, testing
|
|
108
|
-
c. **Follow the style** — Apply the design system, tokens, and
|
|
103
|
+
a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`. The stack is the single authority for technology choices (testing tools, CI/CD platform, package manager). Where stack-specific practices (Section 15 of `stack.md`) conflict with general practices in `practices.md`, the stack's technology-specific guidance takes precedence for framework-specific concerns.
|
|
104
|
+
b. **Follow the practices** — Adhere to coding standards, testing philosophy, pipeline structure, and conventions from `gspec/practices.md`
|
|
105
|
+
c. **Follow the style** — Apply the design system, tokens, and icon library from `gspec/style.md`. The style is the single authority for icon library choices. Component libraries (e.g., shadcn/ui) are defined in `gspec/stack.md`.
|
|
109
106
|
d. **Satisfy the requirements** — Trace each piece of code back to a functional requirement in the feature PRD (if available) or to the user's stated goals and the approved implementation plan
|
|
110
107
|
3. **Mark capabilities as implemented** — After successfully implementing each capability, immediately update the feature PRD by changing its checkbox from `- [ ]` to `- [x]`. Do this incrementally as each capability is completed, not in a batch at the end. If a capability line did not have a checkbox prefix, add one as `- [x]`. This ensures that if the session is interrupted, progress is not lost. When updating gspec files, preserve existing `gspec-version` YAML frontmatter. If a file lacks frontmatter, add `---\ngspec-version: <<<VERSION>>>\n---` at the top.
|
|
111
|
-
4. **
|
|
112
|
-
5. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
|
|
108
|
+
4. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
|
|
113
109
|
6. **Surface new gaps** — If implementation reveals new ambiguities, pause and consult the user rather than making silent assumptions
|
|
114
110
|
7. **Pause and report** — After completing the phase and confirming tests pass, present a phase completion summary to the user:
|
|
115
111
|
|
|
@@ -153,21 +149,20 @@ When you encounter something the specs don't fully cover during implementation:
|
|
|
153
149
|
|
|
154
150
|
## Selecting What to Implement
|
|
155
151
|
|
|
156
|
-
### When no features
|
|
152
|
+
### When no features exist:
|
|
157
153
|
|
|
158
|
-
If `gspec/features/`
|
|
154
|
+
If `gspec/features/` is empty or absent, use the **user's prompt** as the primary guide for what to build:
|
|
159
155
|
|
|
160
156
|
1. **If the user provided a prompt** to the implement command, treat it as your primary directive. The prompt may describe a feature, a scope of work, a user story, or a high-level goal. Combine it with the remaining gspec files (profile, stack, style, practices) to plan and build.
|
|
161
157
|
2. **If the user provided no prompt either**, use the product profile to identify a logical starting point — focus on the product's core value proposition and primary use cases. Suggest a starting point and confirm with the user.
|
|
162
158
|
|
|
163
|
-
### When features
|
|
159
|
+
### When features exist:
|
|
164
160
|
|
|
165
161
|
**Filter by implementation status first.** Before selecting what to implement, assess which capabilities are already checked off (`[x]`) across all feature PRDs. Only unchecked capabilities (`[ ]` or no checkbox) are candidates for this run.
|
|
166
162
|
|
|
167
163
|
If the user doesn't specify which feature to implement:
|
|
168
164
|
|
|
169
|
-
1.
|
|
170
|
-
2. **Focus on features with unchecked capabilities** — Features with all capabilities checked are complete and can be skipped
|
|
165
|
+
1. **Focus on features with unchecked capabilities** — Features with all capabilities checked are complete and can be skipped
|
|
171
166
|
3. Among features with pending work, prioritize unchecked P0 capabilities over P1, P1 over P2
|
|
172
167
|
4. Respect dependency ordering — build foundations before dependent features
|
|
173
168
|
5. Suggest a starting point and confirm with the user
|
|
@@ -176,9 +171,9 @@ If the user specifies a feature, focus on that feature's **unchecked capabilitie
|
|
|
176
171
|
- Note any unmet dependencies
|
|
177
172
|
- If the user explicitly asks to re-implement a checked capability, honor that request
|
|
178
173
|
|
|
179
|
-
### When the user provides a prompt alongside existing features
|
|
174
|
+
### When the user provides a prompt alongside existing features:
|
|
180
175
|
|
|
181
|
-
The user's prompt takes priority for scoping. Use it to determine focus, and reference existing feature PRDs
|
|
176
|
+
The user's prompt takes priority for scoping. Use it to determine focus, and reference existing feature PRDs as supporting context rather than the sole driver.
|
|
182
177
|
|
|
183
178
|
---
|
|
184
179
|
|
|
@@ -11,7 +11,7 @@ Your task is to update existing gspec specification documents to match the curre
|
|
|
11
11
|
Scan the `gspec/` directory for all Markdown files:
|
|
12
12
|
- `gspec/*.md` (profile, stack, style, practices, architecture)
|
|
13
13
|
- `gspec/features/*.md` (individual feature PRDs)
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
|
|
16
16
|
For each file, check the YAML frontmatter at the top of the file:
|
|
17
17
|
- If the file starts with `---` followed by YAML content and another `---`, read the `gspec-version` field
|
|
@@ -40,7 +40,6 @@ For each file that needs migration, determine its document type and read the cor
|
|
|
40
40
|
| `gspec/practices.md` | Development Practices | Read the `gspec-practices` skill definition |
|
|
41
41
|
| `gspec/architecture.md` | Technical Architecture | Read the `gspec-architect` skill definition |
|
|
42
42
|
| `gspec/features/*.md` | Feature PRD | Read the `gspec-feature` skill definition |
|
|
43
|
-
| `gspec/epics/*.md` | Epic Summary | Read the `gspec-epic` skill definition |
|
|
44
43
|
|
|
45
44
|
The skill definitions are located in your installed skills directory. Read them to understand the current "Required Sections" structure for each document type.
|
|
46
45
|
|