@c0x12c/spartan-ai-toolkit 1.2.0 → 1.3.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 (42) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +2 -2
  3. package/README.md +6 -4
  4. package/VERSION +2 -1
  5. package/bin/cli.js +155 -31
  6. package/claude-md/00-header.md +2 -2
  7. package/claude-md/01-core.md +30 -8
  8. package/claude-md/20-frontend-react.md +2 -1
  9. package/claude-md/30-project-mgmt.md +1 -0
  10. package/claude-md/40-product.md +3 -1
  11. package/commands/spartan/brownfield.md +1 -1
  12. package/commands/spartan/build.md +22 -3
  13. package/commands/spartan/contribute.md +140 -0
  14. package/commands/spartan/epic.md +190 -0
  15. package/commands/spartan/kotlin-service.md +4 -4
  16. package/commands/spartan/map-codebase.md +1 -1
  17. package/commands/spartan/migration.md +1 -1
  18. package/commands/spartan/plan.md +210 -0
  19. package/commands/spartan/qa.md +222 -0
  20. package/commands/spartan/sessions.md +143 -0
  21. package/commands/spartan/spec.md +131 -0
  22. package/commands/spartan/testcontainer.md +1 -1
  23. package/commands/spartan/think.md +1 -1
  24. package/commands/spartan/workstreams.md +1 -1
  25. package/commands/spartan.md +142 -2
  26. package/lib/assembler.js +147 -2
  27. package/lib/assembler.test.js +159 -0
  28. package/lib/detector.js +166 -0
  29. package/lib/detector.test.js +221 -0
  30. package/lib/resolver.js +129 -1
  31. package/lib/resolver.test.js +159 -1
  32. package/package.json +2 -2
  33. package/packs/core.yaml +4 -1
  34. package/packs/frontend-react.yaml +2 -0
  35. package/packs/packs.compiled.json +10 -4
  36. package/packs/project-mgmt.yaml +1 -0
  37. package/skills/browser-qa/SKILL.md +180 -0
  38. package/skills/database-table-creator/SKILL.md +12 -394
  39. package/skills/database-table-creator/kotlin-templates.md +400 -0
  40. package/skills/database-table-creator/migration-template.sql +1 -1
  41. package/templates/epic.md +1 -1
  42. package/commands/spartan/quickplan.md +0 -122
@@ -8,9 +8,9 @@
8
8
  "plugins": [
9
9
  {
10
10
  "name": "spartan-ai-toolkit",
11
- "description": "5 workflows, 48 commands, 11 rules, 18 skills, 4 agents — organized in 11 packs with dependencies",
11
+ "description": "5 workflows, 53 commands, 11 rules, 19 skills, 4 agents — organized in 11 packs with dependencies",
12
12
  "source": "./toolkit",
13
- "version": "1.2.0"
13
+ "version": "1.3.0"
14
14
  }
15
15
  ]
16
16
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "spartan-ai-toolkit",
3
- "version": "1.2.0",
4
- "description": "Engineering discipline layer for Claude Code — 5 workflows, 48 commands, 11 rules, 18 skills, 4 agents organized in 11 packs",
3
+ "version": "1.3.0",
4
+ "description": "Engineering discipline layer for Claude Code — 5 workflows, 53 commands, 11 rules, 19 skills, 4 agents organized in 11 packs",
5
5
  "author": {
6
6
  "name": "Khoa Tran",
7
7
  "url": "https://github.com/spartan-stratos"
package/README.md CHANGED
@@ -66,7 +66,8 @@ After install, open any project, run `claude`, then type `/spartan`.
66
66
  **Direct commands** — one command, one job. Best when you know what step you need. Saves tokens.
67
67
 
68
68
  ```
69
- /spartan:quickplan "task" just the planning step
69
+ /spartan:spec "feature" write the spec
70
+ /spartan:plan "feature" ← plan the implementation
70
71
  /spartan:review ← just the code review
71
72
  /spartan:pr-ready ← just the PR creation
72
73
  /spartan:migration "desc" ← just the migration
@@ -135,7 +136,7 @@ npx @c0x12c/spartan-ai-toolkit@latest --all
135
136
 
136
137
  | Pack | Category | Depends on | What you get |
137
138
  |------|----------|------------|--------------|
138
- | **core** | Core | — | Always installed. Workflows (build, fix, onboard), quickplan, pr-ready, daily, safety commands |
139
+ | **core** | Core | — | Always installed. Workflows (build, fix, onboard), spec, plan, pr-ready, daily, safety commands |
139
140
  | **backend-micronaut** | Backend | database, shared-backend | Kotlin service scaffold, code review, testcontainers, API/DB/Kotlin rules, 5 skills, 2 agents |
140
141
  | **backend-nodejs** | Backend | database, shared-backend | Coming soon |
141
142
  | **backend-python** | Backend | database, shared-backend | Coming soon |
@@ -151,7 +152,7 @@ Hidden packs (`database`, `shared-backend`) get pulled in as dependencies — yo
151
152
 
152
153
  ## Commands
153
154
 
154
- All commands start with `/spartan:` (e.g., `/spartan:quickplan "task"`).
155
+ All commands start with `/spartan:` (e.g., `/spartan:spec "feature"`).
155
156
 
156
157
  Type `/spartan` to get the smart router — it asks what you need and picks the right command.
157
158
 
@@ -167,7 +168,8 @@ Type `/spartan` to get the smart router — it asks what you need and picks the
167
168
  ### Core (always installed)
168
169
  | Command | What it does |
169
170
  |---------|-------------|
170
- | `quickplan "task"` | Task < 1 dayspec + plan + branch in one shot |
171
+ | `spec "feature"` | Write a feature specsaves to `.planning/specs/` |
172
+ | `plan "feature"` | Write implementation plan from spec — saves to `.planning/plans/` |
171
173
  | `daily` | Standup summary from git history |
172
174
  | `pr-ready` | Full checklist before creating any PR |
173
175
  | `init-project` | Auto-generate CLAUDE.md from codebase scan |
package/VERSION CHANGED
@@ -1 +1,2 @@
1
- 1.2.0
1
+ 1.3.0
2
+
package/bin/cli.js CHANGED
@@ -48,11 +48,15 @@ function blue(s) { return `${C.blue}${s}${C.reset}`; }
48
48
 
49
49
  // ── Pack definitions (loaded from YAML manifests) ───────────────
50
50
  import { PACKS, PACK_ORDER } from '../lib/packs.js';
51
- import { assembleCLAUDEmd } from '../lib/assembler.js';
52
- import { resolve as resolveDeps, resolveAliases, loadManifests } from '../lib/resolver.js';
51
+ import { assembleCLAUDEmd, assembleAGENTSmd } from '../lib/assembler.js';
52
+ import { resolve as resolveDeps, resolveAliases, loadManifests, loadExternalPacks } from '../lib/resolver.js';
53
+ import { detectStacks } from '../lib/detector.js';
53
54
 
54
55
  const manifests = loadManifests(join(PKG_ROOT, 'packs'));
55
56
 
57
+ // Maps community pack names to their source directory (for file resolution)
58
+ const externalPackSources = {};
59
+
56
60
  // ── Parse args ──────────────────────────────────────────────────
57
61
  const args = process.argv.slice(2);
58
62
 
@@ -61,12 +65,18 @@ let packsArg = '';
61
65
  let installAll = false;
62
66
  let mode = 'global'; // default for claude-code
63
67
  let showHelp = false;
68
+ let format = ''; // '' = default, 'agents-md' = export AGENTS.md
69
+ let autoDetect = false;
70
+ let packDirArg = ''; // external community pack directory
64
71
 
65
72
  for (const arg of args) {
66
73
  if (arg === '--help' || arg === '-h') showHelp = true;
67
74
  else if (arg.startsWith('--agent=')) agent = arg.split('=')[1];
68
75
  else if (arg.startsWith('--packs=')) packsArg = arg.split('=')[1];
76
+ else if (arg.startsWith('--format=')) format = arg.split('=')[1];
77
+ else if (arg.startsWith('--pack-dir=')) packDirArg = arg.split('=')[1];
69
78
  else if (arg === '--all') installAll = true;
79
+ else if (arg === '--auto') autoDetect = true;
70
80
  else if (arg === '--global') mode = 'global';
71
81
  else if (arg === '--local') mode = 'local';
72
82
  }
@@ -100,6 +110,9 @@ if (showHelp) {
100
110
  Choices: claude-code, cursor, windsurf, codex, copilot
101
111
  --packs=LIST Comma-separated packs (claude-code only)
102
112
  Example: --packs=backend-micronaut,product
113
+ --auto Auto-detect tech stack and suggest packs (no menu)
114
+ --pack-dir=DIR Load community packs from an external directory
115
+ --format=NAME Output format: agents-md (exports AGENTS.md for cross-tool use)
103
116
  --all Install all packs
104
117
  --global Install to home dir (default for claude-code/codex)
105
118
  --local Install to current project dir
@@ -124,6 +137,12 @@ ${lines.join('\n')}`).join('\n')}
124
137
 
125
138
  ${cyan('npx spartan-ai-toolkit@latest --agent=cursor')}
126
139
  Install rules for Cursor (rules + AGENTS.md only)
140
+
141
+ ${cyan('npx spartan-ai-toolkit@latest --auto')}
142
+ Auto-detect your tech stack and install matching packs
143
+
144
+ ${cyan('npx spartan-ai-toolkit@latest --format=agents-md --packs=backend-micronaut')}
145
+ Export AGENTS.md for any AI coding tool
127
146
  `);
128
147
  process.exit(0);
129
148
  }
@@ -220,6 +239,11 @@ function copyDir(src, dest) {
220
239
  cpSync(src, dest, { recursive: true });
221
240
  }
222
241
 
242
+ /** Get the source root for a pack (built-in uses PKG_ROOT, community uses pack-dir). */
243
+ function getPackSource(packName) {
244
+ return externalPackSources[packName] || PKG_ROOT;
245
+ }
246
+
223
247
  /** Get all items for a category across selected packs, deduplicated. */
224
248
  function gatherItems(selectedPacks, category) {
225
249
  const seen = new Set();
@@ -237,6 +261,24 @@ function gatherItems(selectedPacks, category) {
237
261
  return result;
238
262
  }
239
263
 
264
+ /** Like gatherItems but includes the source root for each item (for community pack support). */
265
+ function gatherItemsWithSource(selectedPacks, category) {
266
+ const seen = new Set();
267
+ const result = [];
268
+ for (const pack of selectedPacks) {
269
+ const def = PACKS[pack];
270
+ if (!def) continue;
271
+ const srcRoot = getPackSource(pack);
272
+ for (const item of def[category]) {
273
+ if (!seen.has(item)) {
274
+ seen.add(item);
275
+ result.push({ item, srcRoot });
276
+ }
277
+ }
278
+ }
279
+ return result;
280
+ }
281
+
240
282
  // ── Pack selection (grouped menu) ───────────────────────────────
241
283
  async function selectPacks(targets) {
242
284
  // --all flag
@@ -253,6 +295,44 @@ async function selectPacks(targets) {
253
295
  return resolveDeps(aliased, manifests);
254
296
  }
255
297
 
298
+ // --auto flag: detect tech stack
299
+ if (autoDetect) {
300
+ const cwd = process.cwd();
301
+ console.log(`\n ${blue('Scanning')} ${dim(cwd)} ${blue('for tech stack...')}\n`);
302
+ const { detected, comingSoon } = detectStacks(cwd);
303
+
304
+ if (detected.length > 0) {
305
+ console.log(` ${bold('Detected stacks:')}`);
306
+ for (const d of detected) {
307
+ console.log(` ${green('✓')} ${bold(d.pack)} ${dim(`(${d.reason})`)}`);
308
+ }
309
+
310
+ if (comingSoon.length > 0) {
311
+ console.log('');
312
+ for (const d of comingSoon) {
313
+ console.log(` ${yellow('~')} ${d.pack} ${dim(`(${d.reason})`)} ${dim('— coming soon, skipped')}`);
314
+ }
315
+ }
316
+ console.log('');
317
+
318
+ const packNames = detected.map(d => d.pack);
319
+ const confirm = await ask(` Install ${bold(packNames.join(' + '))}? [Y/n]: `);
320
+ if (confirm !== 'n' && confirm !== 'N') {
321
+ return resolveDeps(packNames, manifests);
322
+ }
323
+ // User said no — fall through to interactive menu
324
+ console.log('');
325
+ } else {
326
+ console.log(` ${dim('No stacks detected.')}`);
327
+ if (comingSoon.length > 0) {
328
+ for (const d of comingSoon) {
329
+ console.log(` ${yellow('~')} ${d.pack} ${dim(`(${d.reason})`)} ${dim('— coming soon')}`);
330
+ }
331
+ }
332
+ console.log(` ${dim('Falling back to interactive menu...')}\n`);
333
+ }
334
+ }
335
+
256
336
  // Check saved packs
257
337
  if (existsSync(targets.packsFile)) {
258
338
  let saved = readFileSync(targets.packsFile, 'utf-8').trim().split('\n').filter(Boolean);
@@ -358,9 +438,9 @@ async function installFull() {
358
438
  cmdCount++;
359
439
  }
360
440
 
361
- const selectedCommands = gatherItems(selectedPacks, 'commands');
362
- for (const cmd of selectedCommands) {
363
- const src = join(SRC.commandsSub, `${cmd}.md`);
441
+ const selectedCommands = gatherItemsWithSource(selectedPacks, 'commands');
442
+ for (const { item: cmd, srcRoot } of selectedCommands) {
443
+ const src = join(srcRoot, 'commands', 'spartan', `${cmd}.md`);
364
444
  if (existsSync(src)) {
365
445
  copyFile(src, join(targets.commands, `${cmd}.md`));
366
446
  console.log(` ${green('+')} /spartan:${cmd}`);
@@ -372,14 +452,13 @@ async function installFull() {
372
452
  console.log(` ${bold(cmdCount + ' commands')} installed\n`);
373
453
 
374
454
  // 3) Rules (now with subdirectory structure)
375
- const selectedRules = gatherItems(selectedPacks, 'rules');
376
- if (selectedRules.length > 0) {
455
+ const rulesWithSource = gatherItemsWithSource(selectedPacks, 'rules');
456
+ if (rulesWithSource.length > 0) {
377
457
  console.log(`${blue('[3/5]')} ${bold('Installing rules...')}`);
378
458
  let ruleCount = 0;
379
459
 
380
- for (const rule of selectedRules) {
381
- // Rules now have subdir paths like "database/SCHEMA.md"
382
- const src = join(SRC.rules, rule);
460
+ for (const { item: rule, srcRoot } of rulesWithSource) {
461
+ const src = join(srcRoot, 'rules', rule);
383
462
  const dest = join(targets.rules, rule);
384
463
  if (existsSync(src)) {
385
464
  copyFile(src, dest);
@@ -393,14 +472,14 @@ async function installFull() {
393
472
  }
394
473
 
395
474
  // 4) Skills
396
- const selectedSkills = gatherItems(selectedPacks, 'skills');
397
- if (selectedSkills.length > 0) {
475
+ const skillsWithSource = gatherItemsWithSource(selectedPacks, 'skills');
476
+ if (skillsWithSource.length > 0) {
398
477
  console.log(`${blue('[4/5]')} ${bold('Installing skills...')}`);
399
478
  ensureDir(targets.skills);
400
479
  let skillCount = 0;
401
480
 
402
- for (const skill of selectedSkills) {
403
- const src = join(SRC.skills, skill);
481
+ for (const { item: skill, srcRoot } of skillsWithSource) {
482
+ const src = join(srcRoot, 'skills', skill);
404
483
  if (existsSync(src)) {
405
484
  copyDir(src, join(targets.skills, skill));
406
485
  console.log(` ${green('+')} ${skill}`);
@@ -413,14 +492,14 @@ async function installFull() {
413
492
  }
414
493
 
415
494
  // 5) Agents
416
- const selectedAgents = gatherItems(selectedPacks, 'agents');
417
- if (selectedAgents.length > 0) {
495
+ const agentsWithSource = gatherItemsWithSource(selectedPacks, 'agents');
496
+ if (agentsWithSource.length > 0) {
418
497
  console.log(`${blue('[5/5]')} ${bold('Installing agents...')}`);
419
498
  ensureDir(targets.agents);
420
499
  let agentCount = 0;
421
500
 
422
- for (const agentFile of selectedAgents) {
423
- const src = join(SRC.agents, agentFile);
501
+ for (const { item: agentFile, srcRoot } of agentsWithSource) {
502
+ const src = join(srcRoot, 'agents', agentFile);
424
503
  if (existsSync(src)) {
425
504
  copyFile(src, join(targets.agents, agentFile));
426
505
  console.log(` ${green('+')} ${agentFile.replace('.md', '')}`);
@@ -495,23 +574,15 @@ async function installRulesOnly() {
495
574
  console.log(`\n${blue('[1/2]')} ${bold('Rules')} — ${dim('no rule packs selected')}\n`);
496
575
  }
497
576
 
498
- // Install AGENTS.md
577
+ // Install AGENTS.md — assembled from pack sections + agents
499
578
  console.log(`${blue('[2/2]')} ${bold('Installing AGENTS.md...')}`);
500
579
 
501
- const allAgents = gatherItems([...PACK_ORDER], 'agents');
502
- if (allAgents.length > 0 && targets.agentsMd) {
503
- let agentsContent = '# Spartan AI Toolkit — Agents\n\n';
504
- agentsContent += 'Expert agents for your AI coding assistant.\n\n---\n\n';
505
- for (const agentFile of allAgents) {
506
- const src = join(SRC.agents, agentFile);
507
- if (existsSync(src)) {
508
- agentsContent += readFileSync(src, 'utf-8') + '\n\n---\n\n';
509
- }
510
- }
511
- writeFileSync(targets.agentsMd, agentsContent.trimEnd() + '\n', 'utf-8');
580
+ if (targets.agentsMd) {
581
+ const agentsContent = assembleAGENTSmd(SRC.claudeMd, SRC.agents, selectedPacks, PACKS);
582
+ writeFileSync(targets.agentsMd, agentsContent, 'utf-8');
512
583
  console.log(` ${green('+')} AGENTS.md\n`);
513
584
  } else {
514
- console.log(` ${dim('No agents to install')}\n`);
585
+ console.log(` ${dim('No AGENTS.md target')}\n`);
515
586
  }
516
587
 
517
588
  // Save selection
@@ -538,6 +609,49 @@ async function main() {
538
609
  process.exit(1);
539
610
  }
540
611
 
612
+ // Load community packs if --pack-dir is set
613
+ if (packDirArg) {
614
+ const packDirPath = pathResolve(process.cwd(), packDirArg);
615
+ const builtinNames = new Set(manifests.keys());
616
+ console.log(`\n ${blue('Loading community packs from')} ${dim(packDirPath)}`);
617
+ const { loaded, errors } = loadExternalPacks(packDirPath, builtinNames);
618
+
619
+ if (errors.length > 0) {
620
+ for (const err of errors) {
621
+ console.log(` ${yellow('!')} ${err}`);
622
+ }
623
+ }
624
+
625
+ if (loaded.size > 0) {
626
+ for (const [name, manifest] of loaded) {
627
+ manifests.set(name, manifest);
628
+ externalPackSources[name] = packDirPath;
629
+ // Add to PACKS and PACK_ORDER so menus and install work
630
+ PACKS[name] = {
631
+ description: manifest.description,
632
+ category: manifest.category || 'Community',
633
+ priority: manifest.priority ?? 500,
634
+ hidden: manifest.hidden || false,
635
+ comingSoon: manifest['coming-soon'] || false,
636
+ depends: manifest.depends || [],
637
+ commands: manifest.commands || [],
638
+ rules: manifest.rules || [],
639
+ skills: manifest.skills || [],
640
+ agents: manifest.agents || [],
641
+ claudeSections: manifest['claude-sections'] || [],
642
+ };
643
+ PACK_ORDER.push(name);
644
+ }
645
+ // Re-sort PACK_ORDER by priority
646
+ PACK_ORDER.sort((a, b) => (PACKS[a]?.priority ?? 999) - (PACKS[b]?.priority ?? 999));
647
+
648
+ const names = [...loaded.keys()].join(', ');
649
+ console.log(` ${green('+')} Loaded: ${bold(names)}\n`);
650
+ } else {
651
+ console.log(` ${dim('No valid community packs found')}\n`);
652
+ }
653
+ }
654
+
541
655
  let selectedPacks;
542
656
 
543
657
  try {
@@ -554,6 +668,16 @@ async function main() {
554
668
  closeRL();
555
669
  }
556
670
 
671
+ // Export AGENTS.md alongside normal install when --format=agents-md
672
+ if (format === 'agents-md' && (agent === 'claude-code' || agent === 'codex')) {
673
+ const cwd = process.cwd();
674
+ const agentsMdPath = join(cwd, 'AGENTS.md');
675
+ console.log(`${blue('[+]')} ${bold('Exporting AGENTS.md for cross-tool use...')}`);
676
+ const agentsContent = assembleAGENTSmd(SRC.claudeMd, SRC.agents, selectedPacks, PACKS);
677
+ writeFileSync(agentsMdPath, agentsContent, 'utf-8');
678
+ console.log(` ${green('+')} AGENTS.md (works with Cursor, Copilot, Windsurf, Codex, and 20+ tools)\n`);
679
+ }
680
+
557
681
  // Success
558
682
  const userPacks = selectedPacks.filter(p => !PACKS[p]?.hidden);
559
683
  console.log(`${bold(green('================================================'))}`);
@@ -34,6 +34,6 @@ What do you need?
34
34
  | Size | Use |
35
35
  |---|---|
36
36
  | < 30 min, ≤ 3 files | Just ask Claude (no command needed) |
37
- | < 1 day | `/spartan:quickplan` |
38
- | 1–3 days | `/spartan:project new` (lightweight lifecycle) |
37
+ | < 1 day | `/spartan:spec` → `/spartan:build` |
38
+ | 1–3 days | `/spartan:spec` → `/spartan:plan` `/spartan:build` |
39
39
  | > 3 days, multi-session | `/spartan:project new` (full lifecycle) |
@@ -3,16 +3,19 @@
3
3
 
4
4
  ## Core Principles (Always Enforce)
5
5
 
6
- ### 1. Spec Before Code
7
- - Task < 1 day `/spartan:quickplan` for fast spec + plan
6
+ ### 1. Match the User's Language
7
+ **Detect the language of the user's message and respond entirely in that same language.** This is not optional — it overrides the default English behavior of all commands. If the user writes in Vietnamese, ALL output must be in Vietnamese. If in French, respond in French. If in English, respond in English. This applies to everything: explanations, questions, gate prompts, debug reports, summaries, and PR descriptions. Only code syntax, variable names, file paths, and command names (e.g., `/spartan:fix`) stay in their original form.
8
+
9
+ ### 2. Spec Before Code
10
+ - Task < 1 day → `/spartan:spec` + `/spartan:plan` + `/spartan:build`
8
11
  - Task > 1 day → `/spartan:project new` or `/spartan:project milestone-new`
9
12
  - Never write production code without a written spec or plan
10
13
 
11
- ### 2. TDD is Non-Negotiable
14
+ ### 3. TDD is Non-Negotiable
12
15
  - Red → Green → Refactor, always
13
16
  - Write tests first, then the code that makes them pass
14
17
 
15
- ### 3. Atomic Commits
18
+ ### 4. Atomic Commits
16
19
  Each commit = one task, tests passing:
17
20
  ```
18
21
  type(scope): what changed
@@ -21,7 +24,7 @@ type(scope): what changed
21
24
  ```
22
25
  Types: `feat` · `fix` · `test` · `refactor` · `chore` · `docs`
23
26
 
24
- ### 4. Context Hygiene (Auto-Managed)
27
+ ### 5. Context Hygiene (Auto-Managed)
25
28
  Claude proactively manages its own context window:
26
29
  - When detecting context pressure (slow responses, forgetting earlier context, long conversation) → auto-run `/compact` to summarize and free space
27
30
  - If compaction isn't enough → auto-save critical state to `.handoff/` and `.memory/`, then tell user to start a fresh session
@@ -35,7 +38,7 @@ Claude proactively manages its own context window:
35
38
  - Response quality dropping → warn user + compact
36
39
  - Multi-step command taking unusually long → consider compacting between steps
37
40
 
38
- ### 5. Auto Mode
41
+ ### 6. Auto Mode
39
42
  When user says **"auto on"** or **"auto mode"**, all Spartan commands skip confirmation prompts and execute straight through. Claude will:
40
43
  - Show the spec/plan/output but NOT pause to ask "does this match?" or "shall I proceed?"
41
44
  - Continue to the next step automatically after each step completes
@@ -46,7 +49,7 @@ Turn off with **"auto off"**. Default is **auto off** (commands ask for confirma
46
49
 
47
50
  Auto mode is ideal for experienced users who trust the workflow and want maximum velocity.
48
51
 
49
- ### 6. Safety Guardrails
52
+ ### 7. Safety Guardrails
50
53
 
51
54
  | Command | What it does |
52
55
  |---|---|
@@ -58,6 +61,19 @@ Auto mode is ideal for experienced users who trust the workflow and want maximum
58
61
 
59
62
  ## Core Commands (always available)
60
63
 
64
+ ### Feature Workflow
65
+ ```
66
+ /spartan:epic → /spartan:spec → [/spartan:design] → /spartan:plan → /spartan:build → /spartan:pr-ready
67
+ ↑ ↑ ↑ ↑
68
+ Gate 1 Gate 2 Gate 3 Gate 4
69
+ ```
70
+
71
+ | Size | Path |
72
+ |---|---|
73
+ | Single feature | `/spartan:spec` → `/spartan:plan` → `/spartan:build` |
74
+ | Batch of features (1-2 weeks) | `/spartan:epic` → then spec/plan/build each feature |
75
+ | Multi-week project | `/spartan:project new` → milestones + phases |
76
+
61
77
  ### Workflows (start here)
62
78
  | Command | Purpose |
63
79
  |---|---|
@@ -66,10 +82,16 @@ Auto mode is ideal for experienced users who trust the workflow and want maximum
66
82
  | `/spartan:fix "symptom"` | Bug workflow: reproduce → investigate → fix → PR |
67
83
  | `/spartan:onboard` | Codebase understanding: scan → map → setup |
68
84
 
85
+ ### Spec & Plan (saved artifacts)
86
+ | Command | Purpose |
87
+ |---|---|
88
+ | `/spartan:spec "feature"` | Write a feature spec → saves to `.planning/specs/` → Gate 1 |
89
+ | `/spartan:plan "feature"` | Write implementation plan from spec → saves to `.planning/plans/` → Gate 2 |
90
+ | `/spartan:epic "name"` | Break big work into ordered features → saves to `.planning/epics/` |
91
+
69
92
  ### Individual Commands
70
93
  | Command | Purpose |
71
94
  |---|---|
72
- | `/spartan:quickplan "task"` | Spec + plan + branch in one shot (< 1 day) |
73
95
  | `/spartan:pr-ready` | Pre-PR checklist + auto PR description |
74
96
  | `/spartan:daily` | Standup summary from git log |
75
97
  | `/spartan:init-project` | Auto-generate CLAUDE.md from codebase |
@@ -27,7 +27,7 @@ See `templates/workflow-frontend-react.md` for the full workflow with:
27
27
  - File location guide (App Router conventions)
28
28
  - Parallel vs sequential task planning
29
29
 
30
- For small tasks (< 1 day), `/spartan:quickplan` covers spec + plan in one shot.
30
+ For any feature, use `/spartan:spec` `/spartan:plan` `/spartan:build`.
31
31
 
32
32
  ### Frontend Skills
33
33
 
@@ -42,3 +42,4 @@ For small tasks (< 1 day), `/spartan:quickplan` covers spec + plan in one shot.
42
42
  | `/spartan:fe-review` | PR review with Next.js App Router conventions |
43
43
  | `/spartan:figma-to-code [url]` | Convert Figma screen to production code via MCP |
44
44
  | `/spartan:e2e [feature]` | Scaffold Playwright E2E testing |
45
+ | `/spartan:qa [url] [feature]` | Real browser QA — opens Chromium, tests flows, finds bugs |
@@ -5,6 +5,7 @@
5
5
 
6
6
  | Command | Purpose |
7
7
  |---|---|
8
+ | `/spartan:epic "name"` | Break big work into ordered features → each goes through spec → plan → build |
8
9
  | `/spartan:project [action]` | Manage large projects: `new`, `status`, `milestone-new`, `milestone-complete`, `milestone-summary`, `manager` |
9
10
  | `/spartan:phase [action] [N]` | Manage phases: `discuss`, `plan`, `execute`, `verify` |
10
11
  | `/spartan:workstreams [action]` | Parallel workstreams: `list`, `create`, `switch`, `status`, `progress`, `complete`, `resume` |
@@ -19,7 +19,9 @@ These commands help you think deep before writing code. Use them when starting a
19
19
 
20
20
  /spartan:think "feature" ← 6-phase deep thinking before code
21
21
 
22
- /spartan:quickplan "task" Then build it
22
+ /spartan:spec "task" Write the spec
23
+ /spartan:plan "task" ← Plan the work
24
+ /spartan:build "task" ← Then build it
23
25
  ```
24
26
 
25
27
  You don't have to use all of them. Pick what fits your stage.
@@ -154,4 +154,4 @@ This prevents scope creep and keeps each change independently reviewable.
154
154
 
155
155
  After analysis, present the Context Map summary and ask:
156
156
  "Analysis complete. What change would you like to make first?
157
- I'll create a change folder and use `/spartan:quickplan` for it."
157
+ I'll create a change folder and use `/spartan:spec` → `/spartan:build` for it."
@@ -52,13 +52,21 @@ ls .planning/PROJECT.md 2>/dev/null && echo "GSD_ACTIVE"
52
52
 
53
53
  ## Stage 1: Understand
54
54
 
55
- **Ask 3 forcing questions. Always. Even in auto mode.**
55
+ **First, check for a saved spec:**
56
+ ```bash
57
+ ls .planning/specs/*.md 2>/dev/null
58
+ ```
59
+
60
+ If a spec exists for this feature (matching the feature name), read it and use it as the scope. Skip the 3 questions — the spec already answered them. Show:
61
+ > "Found spec: `.planning/specs/{name}.md` — using it as scope."
62
+
63
+ If no spec exists, **ask 3 forcing questions. Always. Even in auto mode.**
56
64
 
57
65
  1. **"What pain does this solve?"** — Not the feature. The pain. If the user says "add a profiles endpoint" ask what user problem it fixes.
58
66
  2. **"What's the narrowest version we can ship?"** — Force MVP thinking. Cut scope until it hurts.
59
67
  3. **"What assumption could be wrong?"** — Surface hidden risks early.
60
68
 
61
- After the user answers, produce a scope block:
69
+ After the user answers (or after reading the spec), produce a scope block:
62
70
 
63
71
  ```markdown
64
72
  ## Scope: [feature name]
@@ -86,10 +94,21 @@ After the user answers, produce a scope block:
86
94
 
87
95
  ## Stage 2: Plan
88
96
 
97
+ ### Check for saved plan
98
+
99
+ ```bash
100
+ ls .planning/plans/*.md 2>/dev/null
101
+ ```
102
+
103
+ If a plan exists for this feature, read it and use it. Skip the inline planning — go straight to Stage 3 (Implement). Show:
104
+ > "Found plan: `.planning/plans/{name}.md` — using it."
105
+
106
+ If no plan exists, do the size check below.
107
+
89
108
  ### Size check
90
109
 
91
110
  Count the expected work:
92
- - **Small** (1-4 tasks, < 1 day): Inline plan right here. Like a mini-quickplan.
111
+ - **Small** (1-4 tasks, < 1 day): Inline plan right here.
93
112
  - **Big** (5+ tasks, multi-day): Use `/spartan:phase plan` for a full wave-parallel plan.
94
113
 
95
114
  ### Inline plan format (small features)