gspec 1.7.0 → 1.11.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.
Files changed (72) hide show
  1. package/bin/gspec.js +275 -8
  2. package/commands/gspec.analyze.md +1 -1
  3. package/commands/gspec.implement.md +10 -8
  4. package/commands/gspec.practices.md +3 -1
  5. package/commands/gspec.stack.md +11 -6
  6. package/commands/gspec.style.md +18 -23
  7. package/dist/antigravity/gspec-analyze/SKILL.md +1 -1
  8. package/dist/antigravity/gspec-architect/SKILL.md +1 -1
  9. package/dist/antigravity/gspec-feature/SKILL.md +1 -1
  10. package/dist/antigravity/gspec-implement/SKILL.md +11 -9
  11. package/dist/antigravity/gspec-migrate/SKILL.md +5 -5
  12. package/dist/antigravity/gspec-practices/SKILL.md +4 -2
  13. package/dist/antigravity/gspec-profile/SKILL.md +1 -1
  14. package/dist/antigravity/gspec-research/SKILL.md +3 -3
  15. package/dist/antigravity/gspec-stack/SKILL.md +12 -7
  16. package/dist/antigravity/gspec-style/SKILL.md +19 -24
  17. package/dist/claude/gspec-analyze/SKILL.md +1 -1
  18. package/dist/claude/gspec-architect/SKILL.md +1 -1
  19. package/dist/claude/gspec-feature/SKILL.md +1 -1
  20. package/dist/claude/gspec-implement/SKILL.md +11 -9
  21. package/dist/claude/gspec-migrate/SKILL.md +5 -5
  22. package/dist/claude/gspec-practices/SKILL.md +4 -2
  23. package/dist/claude/gspec-profile/SKILL.md +1 -1
  24. package/dist/claude/gspec-research/SKILL.md +3 -3
  25. package/dist/claude/gspec-stack/SKILL.md +12 -7
  26. package/dist/claude/gspec-style/SKILL.md +19 -24
  27. package/dist/codex/gspec-analyze/SKILL.md +1 -1
  28. package/dist/codex/gspec-architect/SKILL.md +1 -1
  29. package/dist/codex/gspec-feature/SKILL.md +1 -1
  30. package/dist/codex/gspec-implement/SKILL.md +11 -9
  31. package/dist/codex/gspec-migrate/SKILL.md +5 -5
  32. package/dist/codex/gspec-practices/SKILL.md +4 -2
  33. package/dist/codex/gspec-profile/SKILL.md +1 -1
  34. package/dist/codex/gspec-research/SKILL.md +3 -3
  35. package/dist/codex/gspec-stack/SKILL.md +12 -7
  36. package/dist/codex/gspec-style/SKILL.md +19 -24
  37. package/dist/cursor/gspec-analyze.mdc +1 -1
  38. package/dist/cursor/gspec-architect.mdc +1 -1
  39. package/dist/cursor/gspec-feature.mdc +1 -1
  40. package/dist/cursor/gspec-implement.mdc +11 -9
  41. package/dist/cursor/gspec-migrate.mdc +5 -5
  42. package/dist/cursor/gspec-practices.mdc +4 -2
  43. package/dist/cursor/gspec-profile.mdc +1 -1
  44. package/dist/cursor/gspec-research.mdc +3 -3
  45. package/dist/cursor/gspec-stack.mdc +12 -7
  46. package/dist/cursor/gspec-style.mdc +19 -24
  47. package/dist/opencode/gspec-analyze/SKILL.md +168 -0
  48. package/dist/opencode/gspec-architect/SKILL.md +361 -0
  49. package/dist/opencode/gspec-feature/SKILL.md +204 -0
  50. package/dist/opencode/gspec-implement/SKILL.md +202 -0
  51. package/dist/opencode/gspec-migrate/SKILL.md +118 -0
  52. package/dist/opencode/gspec-practices/SKILL.md +137 -0
  53. package/dist/opencode/gspec-profile/SKILL.md +221 -0
  54. package/dist/opencode/gspec-research/SKILL.md +302 -0
  55. package/dist/opencode/gspec-stack/SKILL.md +305 -0
  56. package/dist/opencode/gspec-style/SKILL.md +224 -0
  57. package/package.json +3 -1
  58. package/starters/features/about-page.md +98 -0
  59. package/starters/features/contact-form.md +147 -0
  60. package/starters/features/contact-page.md +103 -0
  61. package/starters/features/home-page.md +103 -0
  62. package/starters/features/responsive-navbar.md +113 -0
  63. package/starters/features/services-page.md +103 -0
  64. package/starters/features/site-footer.md +121 -0
  65. package/starters/features/theme-switcher.md +124 -0
  66. package/starters/practices/tdd-pipeline-first.md +192 -0
  67. package/starters/stacks/astro-tailwind-github-pages.md +283 -0
  68. package/starters/stacks/nextjs-supabase-vercel.md +319 -0
  69. package/starters/stacks/nextjs-vercel-typescript.md +264 -0
  70. package/starters/styles/clean-professional.md +316 -0
  71. package/starters/styles/dark-minimal-developer.md +442 -0
  72. package/templates/spec-sync.md +1 -1
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-4]: '), (answer) => {
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
- const skipSync = await promptConfirmNo(chalk.bold(' Enable automatic spec sync? (keeps gspec specs up to date as code changes) [Y/n]: '));
410
- if (!skipSync) {
411
- await installSpecSync(targetName, process.cwd());
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,7 +23,7 @@ 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 patterns
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
@@ -57,8 +57,9 @@ Present this summary to the user so they understand the starting point. If **all
57
57
  - Identify files to create or modify
58
58
  - Note dependencies on prior phases
59
59
  - Include an estimated scope (small/medium/large)
60
- 3. **Define test expectations per phase** — For each phase, specify what tests will be run to verify correctness before moving on (unit tests, integration tests, build verification, etc.)
61
- 4. **Present the plan** — Show the user the full phased plan with clear phase boundaries and ask for approval
60
+ 3. **Account for every unchecked capability** — The plan must explicitly place every unchecked capability from in-scope feature PRDs into a phase **or** list it under a "Proposed to Defer" section with a reason. No unchecked capability may be silently omitted from the plan. The user reviews and approves what gets deferred at plan approval time.
61
+ 4. **Define test expectations per phase** — For each phase, specify what tests will be run to verify correctness before moving on (unit tests, integration tests, build verification, etc.)
62
+ 5. **Present the plan** — Show the user the full phased plan with clear phase boundaries and ask for approval
62
63
 
63
64
  **Wait for user approval before proceeding to Phase 3.** The user may reorder phases, adjust scope, or split/merge phases.
64
65
 
@@ -100,9 +101,9 @@ Present a brief scaffold summary to the user before proceeding to feature implem
100
101
 
101
102
  1. **Announce the phase** — State which phase you're starting, what it covers, and what capabilities will be implemented
102
103
  2. **Implement the phase:**
103
- a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`
104
- b. **Follow the practices** — Adhere to coding standards, testing requirements, and conventions from `gspec/practices.md`
105
- c. **Follow the style** — Apply the design system, tokens, and component patterns from `gspec/style.md`
104
+ 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.
105
+ b. **Follow the practices** — Adhere to coding standards, testing philosophy, pipeline structure, and conventions from `gspec/practices.md`
106
+ 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`.
106
107
  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
107
108
  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.
108
109
  4. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
@@ -124,8 +125,8 @@ After implementation:
124
125
  1. **Walk through each functional requirement** from the feature PRD (if available) or the approved implementation plan and confirm it's satisfied
125
126
  2. **Review against acceptance criteria** — For each capability in the feature PRDs, check that every acceptance criterion listed under it is satisfied. These sub-listed conditions are the definition of "done" for each capability. If any criterion is not met, the capability should not be marked `[x]`.
126
127
  3. **Check the Definition of Done** from `gspec/practices.md`
127
- 4. **Note any deferred items** — Requirements that were intentionally postponed or descoped during implementation
128
- 5. **Verify checkbox accuracy** — Confirm that every capability marked `[x]` in the feature PRDs is genuinely implemented and working. Confirm that capabilities left as `[ ]` were intentionally deferred. Present a final status summary:
128
+ 4. **Verify no unapproved deferrals** — Compare the final implementation against the approved plan. If any capability that was assigned to a phase was not implemented, **do not silently leave it unchecked**. Flag it to the user, explain why it wasn't completed, and get explicit approval before marking it as deferred. Only capabilities the user approved for deferral during planning (or explicitly approves now) may remain unchecked.
129
+ 5. **Verify checkbox accuracy** — Confirm that every capability marked `[x]` in the feature PRDs is genuinely implemented and working. Confirm that capabilities left as `[ ]` were approved for deferral by the user. Present a final status summary:
129
130
 
130
131
  > **Implementation Summary:**
131
132
  > - Feature X: 7/7 capabilities implemented (complete)
@@ -144,6 +145,7 @@ When you encounter something the specs don't fully cover during implementation:
144
145
  - **If the ambiguity is significant** (e.g., unclear user flow, missing data model, conflicting requirements), pause and consult the user rather than making silent assumptions
145
146
  - **Never silently implement unspecified behavior** that contradicts or significantly extends the original spec — ask first
146
147
  - **Never override explicit spec decisions** with your own preferences
148
+ - **Never skip or descope a PRD capability without user approval** — ambiguity in *how* to implement something is not grounds for dropping it. If a capability seems too complex, unclear, or problematic, raise it with the user rather than omitting it
147
149
 
148
150
  ---
149
151
 
@@ -173,7 +175,7 @@ If the user specifies a feature, focus on that feature's **unchecked capabilitie
173
175
 
174
176
  ### When the user provides a prompt alongside existing features:
175
177
 
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.
178
+ 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. However, if the user's prompt narrows scope such that some unchecked PRD capabilities will not be implemented this run, explicitly list those excluded capabilities in the plan under "Out of Scope for This Run" so the user can see what is being deferred and why.
177
179
 
178
180
  ---
179
181
 
@@ -34,8 +34,10 @@ You should:
34
34
  - Focus on practices that matter for this specific project
35
35
  - Avoid generic advice that doesn't apply
36
36
  - **Do NOT include technology stack information** — this is documented separately
37
- - **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices, not which tools to use
37
+ - **Do NOT prescribe specific testing frameworks, tools, or libraries** — focus on testing principles, patterns, and practices. The stack document (`gspec/stack.md`) is the single authority for which test tools are used.
38
+ - **DO define CI/CD pipeline structure** — the practices document defines pipeline stages, gates, and ordering (lint → typecheck → test → build → deploy). The stack document defines which CI/CD platform technology is used (GitHub Actions, GitLab CI, etc.).
38
39
  - **Mark sections as "Not Applicable"** when they don't apply to this project
40
+ - **Precedence rule**: Where this document conflicts with technology-specific practices in `gspec/stack.md`, the stack's technology-specific practices take precedence for framework-specific concerns (e.g., file naming conventions dictated by a framework). This document governs general engineering principles.
39
41
 
40
42
  ---
41
43
 
@@ -91,6 +91,8 @@ You should:
91
91
  - Responsive design tooling
92
92
 
93
93
  - **Note**: Visual design values (colors, typography, spacing) are documented separately as framework-agnostic design tokens; include here how the chosen CSS framework maps to those tokens
94
+ - **Component library** (if applicable) — e.g., shadcn/ui, Headless UI, Radix UI. Component libraries are framework-specific technology choices and belong in the stack, not the style guide.
95
+ - **Note**: Icon libraries (e.g., HeroIcons, Lucide) are defined in `gspec/style.md`, not here. The stack defines the CSS framework and component library; the style defines the icon set. Do NOT include an iconography section in the stack document.
94
96
 
95
97
  ### 5. Backend Stack
96
98
  **Mark as N/A if this is a frontend-only or static site project**
@@ -129,9 +131,9 @@ You should:
129
131
  - Scaling approach
130
132
 
131
133
  #### CI/CD Pipeline
132
- - CI/CD platform (GitHub Actions, GitLab CI, Jenkins, etc.)
133
- - Pipeline stages
134
- - Deployment automation
134
+ - CI/CD platform technology (GitHub Actions, GitLab CI, Jenkins, etc.) and rationale
135
+ - Deployment automation and trigger configuration
136
+ - **Note**: The stack defines *which CI/CD technology* is used. The pipeline structure (stages, gates, ordering) is defined in `gspec/practices.md`. Include platform-specific configuration details here (e.g., workflow YAML format, runner setup), not pipeline philosophy.
135
137
 
136
138
  #### Infrastructure as Code
137
139
  - IaC tool (Terraform, CloudFormation, Pulumi, etc.)
@@ -189,10 +191,13 @@ You should:
189
191
 
190
192
  ### 10. Testing Infrastructure
191
193
 
194
+ > **The stack is the single authority for test tooling choices.** Define which frameworks and tools are used here. Testing philosophy, patterns, and coverage requirements are defined in `gspec/practices.md`.
195
+
192
196
  #### Testing Frameworks
193
- - Unit testing framework
197
+ - Unit testing framework (Vitest, Jest, pytest, etc.) and rationale
194
198
  - Integration testing tools
195
- - E2E testing framework (Playwright, Cypress, etc.)
199
+ - E2E testing framework (Playwright, Cypress, etc.) and rationale
200
+ - Component testing tools (if applicable)
196
201
 
197
202
  #### Test Data Management
198
203
  - Test database strategy
@@ -219,7 +224,7 @@ You should:
219
224
  ### 12. Development Tools
220
225
 
221
226
  #### Package Management
222
- - Package manager (npm, yarn, pnpm, pip, maven, etc.)
227
+ - **Package manager** — Explicitly declare the package manager (npm, yarn, pnpm, pip, maven, etc.) with rationale for the choice. This must be stated clearly so all other gspec commands and CI/CD configuration use the correct tool.
223
228
  - Dependency management strategy
224
229
  - Private package registry (if applicable)
225
230
 
@@ -110,34 +110,27 @@ You should:
110
110
  - Component color adjustments
111
111
  - Contrast considerations
112
112
 
113
- #### Theme Switching
114
- - How themes interact with the color palette
115
- - Token mapping between themes
113
+ ### 6. Component Styling
116
114
 
117
- ### 6. Components
115
+ > **Focus on visual styling only** — colors, borders, typography, spacing, and state appearances. Do NOT define component structure, layout behavior, or interaction patterns (those belong in feature PRDs). The goal is to answer "what does it look like?" not "how does it work?"
118
116
 
119
117
  #### Buttons
120
- - Primary, secondary, tertiary styles
121
- - States (default, hover, active, disabled)
122
- - Sizes and padding
123
- - Border radius
118
+ - Color treatments for primary, secondary, ghost variants
119
+ - States: default, hover, active, disabled appearances
120
+ - Sizes and border radius
124
121
 
125
122
  #### Form Elements
126
- - Input fields
127
- - Dropdowns, checkboxes, radio buttons
128
- - Labels and helper text
129
- - Validation states
123
+ - Input field colors, borders, and focus ring styles
124
+ - Label and helper text typography
125
+ - Validation state colors (error, success)
130
126
 
131
127
  #### Cards & Containers
132
- - Background colors
133
- - Border styles
134
- - Shadow elevations
135
- - Corner radius
128
+ - Background colors and border styles
129
+ - Shadow elevations and corner radius
136
130
 
137
- #### Navigation
138
- - Header/navbar styles
139
- - Menu patterns
140
- - Active states
131
+ #### Navigation Elements
132
+ - Link colors: default, hover, active states
133
+ - Background treatments for navigation surfaces
141
134
 
142
135
  ### 7. Visual Effects
143
136
 
@@ -157,11 +150,13 @@ You should:
157
150
 
158
151
  ### 8. Iconography
159
152
 
160
- #### Icon Style
161
- - Outlined vs filled
153
+ > **The style guide is the single authority for icon library choices.** The stack document defines the CSS framework and component library (e.g., shadcn/ui); the style guide defines which icon set is used. This separation ensures icon decisions are driven by design rationale (visual consistency, stroke style) while component library decisions remain with the technology stack (framework compatibility).
154
+
155
+ #### Icon Library
156
+ - Specific icon library recommendation with rationale
157
+ - Outlined vs filled style
162
158
  - Stroke width
163
159
  - Size standards
164
- - Icon library recommendation
165
160
 
166
161
  #### Usage Guidelines
167
162
  - When to use icons
@@ -28,7 +28,7 @@ Read **every** available gspec document in this order:
28
28
 
29
29
  1. `gspec/profile.md` — Product identity, scope, audience, and positioning
30
30
  2. `gspec/stack.md` — Technology choices, frameworks, infrastructure
31
- 3. `gspec/style.md` — Visual design language, tokens, component patterns
31
+ 3. `gspec/style.md` — Visual design language, tokens, component styling
32
32
  4. `gspec/practices.md` — Development standards, testing, conventions
33
33
  5. `gspec/architecture.md` — Technical blueprint: project structure, data model, API design, environment
34
34
  6. `gspec/research.md` — Competitive analysis and feature proposals
@@ -45,7 +45,7 @@ All of these provide essential context. If any are missing, note the gap and mak
45
45
  - Begin the file with YAML frontmatter containing the gspec version:
46
46
  ```
47
47
  ---
48
- gspec-version: 1.7.0
48
+ gspec-version: 1.11.0
49
49
  ---
50
50
  ```
51
51
  The frontmatter must be the very first content in the file, before the main heading.
@@ -85,7 +85,7 @@ Feature PRDs are designed to be **portable across projects**. A feature spec wri
85
85
  - Begin each file with YAML frontmatter containing the gspec version:
86
86
  ```
87
87
  ---
88
- gspec-version: 1.7.0
88
+ gspec-version: 1.11.0
89
89
  ---
90
90
  ```
91
91
  The frontmatter must be the very first content in the file, before the main heading.
@@ -62,8 +62,9 @@ Present this summary to the user so they understand the starting point. If **all
62
62
  - Identify files to create or modify
63
63
  - Note dependencies on prior phases
64
64
  - Include an estimated scope (small/medium/large)
65
- 3. **Define test expectations per phase** — For each phase, specify what tests will be run to verify correctness before moving on (unit tests, integration tests, build verification, etc.)
66
- 4. **Present the plan** — Show the user the full phased plan with clear phase boundaries and ask for approval
65
+ 3. **Account for every unchecked capability** — The plan must explicitly place every unchecked capability from in-scope feature PRDs into a phase **or** list it under a "Proposed to Defer" section with a reason. No unchecked capability may be silently omitted from the plan. The user reviews and approves what gets deferred at plan approval time.
66
+ 4. **Define test expectations per phase** — For each phase, specify what tests will be run to verify correctness before moving on (unit tests, integration tests, build verification, etc.)
67
+ 5. **Present the plan** — Show the user the full phased plan with clear phase boundaries and ask for approval
67
68
 
68
69
  **Wait for user approval before proceeding to Phase 3.** The user may reorder phases, adjust scope, or split/merge phases.
69
70
 
@@ -105,11 +106,11 @@ Present a brief scaffold summary to the user before proceeding to feature implem
105
106
 
106
107
  1. **Announce the phase** — State which phase you're starting, what it covers, and what capabilities will be implemented
107
108
  2. **Implement the phase:**
108
- a. **Follow the stack** — Use the exact technologies, frameworks, and patterns defined in `gspec/stack.md`
109
- b. **Follow the practices** — Adhere to coding standards, testing requirements, and conventions from `gspec/practices.md`
110
- c. **Follow the style** — Apply the design system, tokens, and component patterns from `gspec/style.md`
109
+ 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.
110
+ b. **Follow the practices** — Adhere to coding standards, testing philosophy, pipeline structure, and conventions from `gspec/practices.md`
111
+ 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`.
111
112
  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
112
- 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: 1.7.0\n---` at the top.
113
+ 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: 1.11.0\n---` at the top.
113
114
  4. **Run tests** — Execute the tests defined for this phase (and any existing tests to catch regressions). Fix any failures before proceeding.
114
115
  6. **Surface new gaps** — If implementation reveals new ambiguities, pause and consult the user rather than making silent assumptions
115
116
  7. **Pause and report** — After completing the phase and confirming tests pass, present a phase completion summary to the user:
@@ -129,8 +130,8 @@ After implementation:
129
130
  1. **Walk through each functional requirement** from the feature PRD (if available) or the approved implementation plan and confirm it's satisfied
130
131
  2. **Review against acceptance criteria** — For each capability in the feature PRDs, check that every acceptance criterion listed under it is satisfied. These sub-listed conditions are the definition of "done" for each capability. If any criterion is not met, the capability should not be marked `[x]`.
131
132
  3. **Check the Definition of Done** from `gspec/practices.md`
132
- 4. **Note any deferred items** — Requirements that were intentionally postponed or descoped during implementation
133
- 5. **Verify checkbox accuracy** — Confirm that every capability marked `[x]` in the feature PRDs is genuinely implemented and working. Confirm that capabilities left as `[ ]` were intentionally deferred. Present a final status summary:
133
+ 4. **Verify no unapproved deferrals** — Compare the final implementation against the approved plan. If any capability that was assigned to a phase was not implemented, **do not silently leave it unchecked**. Flag it to the user, explain why it wasn't completed, and get explicit approval before marking it as deferred. Only capabilities the user approved for deferral during planning (or explicitly approves now) may remain unchecked.
134
+ 5. **Verify checkbox accuracy** — Confirm that every capability marked `[x]` in the feature PRDs is genuinely implemented and working. Confirm that capabilities left as `[ ]` were approved for deferral by the user. Present a final status summary:
134
135
 
135
136
  > **Implementation Summary:**
136
137
  > - Feature X: 7/7 capabilities implemented (complete)
@@ -149,6 +150,7 @@ When you encounter something the specs don't fully cover during implementation:
149
150
  - **If the ambiguity is significant** (e.g., unclear user flow, missing data model, conflicting requirements), pause and consult the user rather than making silent assumptions
150
151
  - **Never silently implement unspecified behavior** that contradicts or significantly extends the original spec — ask first
151
152
  - **Never override explicit spec decisions** with your own preferences
153
+ - **Never skip or descope a PRD capability without user approval** — ambiguity in *how* to implement something is not grounds for dropping it. If a capability seems too complex, unclear, or problematic, raise it with the user rather than omitting it
152
154
 
153
155
  ---
154
156
 
@@ -178,7 +180,7 @@ If the user specifies a feature, focus on that feature's **unchecked capabilitie
178
180
 
179
181
  ### When the user provides a prompt alongside existing features:
180
182
 
181
- 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.
183
+ 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. However, if the user's prompt narrows scope such that some unchecked PRD capabilities will not be implemented this run, explicitly list those excluded capabilities in the plan under "Out of Scope for This Run" so the user can see what is being deferred and why.
182
184
 
183
185
  ---
184
186