lean-spec 0.2.5 → 0.2.6-dev.20251125010539

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 (85) hide show
  1. package/dist/{chunk-7WXYOHZU.js → chunk-RTEGSMVL.js} +1253 -678
  2. package/dist/chunk-RTEGSMVL.js.map +1 -0
  3. package/dist/cli.js +7 -1
  4. package/dist/cli.js.map +1 -1
  5. package/dist/mcp-server.js +1 -1
  6. package/package.json +2 -3
  7. package/templates/detailed/AGENTS.md +113 -0
  8. package/templates/detailed/README.md +28 -0
  9. package/templates/detailed/files/DESIGN.md +43 -0
  10. package/templates/detailed/files/PLAN.md +59 -0
  11. package/templates/detailed/files/README.md +30 -0
  12. package/templates/detailed/files/TEST.md +71 -0
  13. package/templates/examples/api-refactor/README.md +81 -0
  14. package/templates/examples/api-refactor/package.json +16 -0
  15. package/templates/examples/api-refactor/src/app.js +40 -0
  16. package/templates/examples/api-refactor/src/services/currencyService.js +43 -0
  17. package/templates/examples/api-refactor/src/services/timezoneService.js +41 -0
  18. package/templates/examples/api-refactor/src/services/weatherService.js +42 -0
  19. package/templates/examples/dark-theme/README.md +66 -0
  20. package/templates/examples/dark-theme/package.json +16 -0
  21. package/templates/examples/dark-theme/src/public/app.js +277 -0
  22. package/templates/examples/dark-theme/src/public/index.html +225 -0
  23. package/templates/examples/dark-theme/src/public/style.css +625 -0
  24. package/templates/examples/dark-theme/src/server.js +18 -0
  25. package/templates/examples/dashboard-widgets/README.md +70 -0
  26. package/templates/examples/dashboard-widgets/index.html +12 -0
  27. package/templates/examples/dashboard-widgets/package.json +22 -0
  28. package/templates/examples/dashboard-widgets/src/App.css +20 -0
  29. package/templates/examples/dashboard-widgets/src/App.jsx +16 -0
  30. package/templates/examples/dashboard-widgets/src/components/Dashboard.css +17 -0
  31. package/templates/examples/dashboard-widgets/src/components/Dashboard.jsx +15 -0
  32. package/templates/examples/dashboard-widgets/src/components/WidgetWrapper.css +23 -0
  33. package/templates/examples/dashboard-widgets/src/components/WidgetWrapper.jsx +16 -0
  34. package/templates/examples/dashboard-widgets/src/components/widgets/ChartWidget.css +33 -0
  35. package/templates/examples/dashboard-widgets/src/components/widgets/ChartWidget.jsx +28 -0
  36. package/templates/examples/dashboard-widgets/src/components/widgets/StatsWidget.css +24 -0
  37. package/templates/examples/dashboard-widgets/src/components/widgets/StatsWidget.jsx +22 -0
  38. package/templates/examples/dashboard-widgets/src/index.css +13 -0
  39. package/templates/examples/dashboard-widgets/src/main.jsx +10 -0
  40. package/templates/examples/dashboard-widgets/src/utils/mockData.js +30 -0
  41. package/templates/examples/dashboard-widgets/vite.config.js +6 -0
  42. package/templates/standard/AGENTS.md +113 -0
  43. package/templates/standard/README.md +4 -2
  44. package/dist/chunk-7WXYOHZU.js.map +0 -1
  45. package/templates/_shared/agents-components/core-rules-base-additions.md +0 -4
  46. package/templates/_shared/agents-components/core-rules-enterprise-additions.md +0 -4
  47. package/templates/_shared/agents-components/core-rules-shared.md +0 -1
  48. package/templates/_shared/agents-components/discovery-commands-enterprise-additions.md +0 -6
  49. package/templates/_shared/agents-components/discovery-commands-minimal-additions.md +0 -0
  50. package/templates/_shared/agents-components/discovery-commands-shared.md +0 -8
  51. package/templates/_shared/agents-components/discovery-commands-standard-additions.md +0 -3
  52. package/templates/_shared/agents-components/enterprise-approval.md +0 -10
  53. package/templates/_shared/agents-components/enterprise-compliance.md +0 -12
  54. package/templates/_shared/agents-components/enterprise-when-required.md +0 -13
  55. package/templates/_shared/agents-components/essential-commands-enterprise-additions.md +0 -29
  56. package/templates/_shared/agents-components/essential-commands-minimal-additions.md +0 -1
  57. package/templates/_shared/agents-components/essential-commands-shared.md +0 -15
  58. package/templates/_shared/agents-components/essential-commands-standard-additions.md +0 -18
  59. package/templates/_shared/agents-components/frontmatter-enterprise.md +0 -33
  60. package/templates/_shared/agents-components/frontmatter-minimal.md +0 -18
  61. package/templates/_shared/agents-components/frontmatter-standard.md +0 -23
  62. package/templates/_shared/agents-components/quality-standards-enterprise-additions.md +0 -4
  63. package/templates/_shared/agents-components/quality-standards-minimal-additions.md +0 -3
  64. package/templates/_shared/agents-components/quality-standards-shared.md +0 -6
  65. package/templates/_shared/agents-components/status-update-triggers.md +0 -14
  66. package/templates/_shared/agents-components/when-to-use-enterprise.md +0 -11
  67. package/templates/_shared/agents-components/when-to-use-minimal.md +0 -9
  68. package/templates/_shared/agents-components/when-to-use-standard.md +0 -9
  69. package/templates/_shared/agents-components/workflow-enterprise.md +0 -11
  70. package/templates/_shared/agents-components/workflow-standard-detailed.md +0 -10
  71. package/templates/_shared/agents-components/workflow-standard.md +0 -8
  72. package/templates/_shared/agents-template.hbs +0 -43
  73. package/templates/enterprise/README.md +0 -25
  74. package/templates/enterprise/agents-config.json +0 -16
  75. package/templates/enterprise/files/AGENTS.md +0 -194
  76. package/templates/enterprise/spec-template.md +0 -80
  77. package/templates/minimal/README.md +0 -18
  78. package/templates/minimal/agents-config.json +0 -13
  79. package/templates/minimal/config.json +0 -15
  80. package/templates/minimal/files/AGENTS.md +0 -116
  81. package/templates/minimal/spec-template.md +0 -25
  82. package/templates/standard/agents-config.json +0 -13
  83. package/templates/standard/files/AGENTS.md +0 -142
  84. /package/templates/{enterprise → detailed}/config.json +0 -0
  85. /package/templates/standard/{spec-template.md → files/README.md} +0 -0
package/dist/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- import { analyzeCommand, archiveCommand, backfillCommand, boardCommand, checkCommand, compactCommand, createCommand, depsCommand, filesCommand, ganttCommand, initCommand, linkCommand, listCommand, mcpCommand, migrateCommand, openCommand, searchCommand, splitCommand, statsCommand, templatesCommand, timelineCommand, tokensCommand, uiCommand, unlinkCommand, updateCommand, validateCommand, viewCommand } from './chunk-7WXYOHZU.js';
1
+ import { analyzeCommand, archiveCommand, backfillCommand, boardCommand, checkCommand, compactCommand, createCommand, depsCommand, examplesCommand, filesCommand, ganttCommand, initCommand, linkCommand, listCommand, mcpCommand, migrateCommand, openCommand, searchCommand, splitCommand, statsCommand, templatesCommand, timelineCommand, tokensCommand, uiCommand, unlinkCommand, updateCommand, validateCommand, viewCommand } from './chunk-RTEGSMVL.js';
2
2
  import './chunk-LVD7ZAVZ.js';
3
3
  import { Command } from 'commander';
4
4
  import { readFileSync } from 'fs';
@@ -15,6 +15,7 @@ function registerCommands(program2) {
15
15
  program2.addCommand(compactCommand());
16
16
  program2.addCommand(createCommand());
17
17
  program2.addCommand(depsCommand());
18
+ program2.addCommand(examplesCommand());
18
19
  program2.addCommand(filesCommand());
19
20
  program2.addCommand(ganttCommand());
20
21
  program2.addCommand(initCommand());
@@ -51,6 +52,7 @@ Command Groups:
51
52
  archive <spec> Move spec to archived/
52
53
  backfill [specs...] Backfill timestamps from git history
53
54
  create <name> Create new spec
55
+ examples List example projects for tutorials
54
56
  init Initialize LeanSpec in current directory
55
57
  link <spec> Add relationships between specs
56
58
  migrate <input-path> Migrate specs from other SDD tools
@@ -90,6 +92,10 @@ Command Groups:
90
92
 
91
93
  Examples:
92
94
  $ lean-spec init
95
+ $ lean-spec init -y
96
+ $ lean-spec init --example dark-theme
97
+ $ lean-spec init --example dashboard-widgets --name my-demo
98
+ $ lean-spec examples
93
99
  $ lean-spec create my-feature --priority high
94
100
  $ lean-spec list --status in-progress
95
101
  $ lean-spec view 042
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/commands/registry.ts","../src/cli.ts"],"names":["program"],"mappings":"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","file":"cli.js","sourcesContent":["import { Command } from 'commander';\nimport {\n analyzeCommand,\n archiveCommand,\n backfillCommand,\n boardCommand,\n checkCommand,\n compactCommand,\n createCommand,\n depsCommand,\n filesCommand,\n ganttCommand,\n initCommand,\n linkCommand,\n listCommand,\n mcpCommand,\n migrateCommand,\n openCommand,\n searchCommand,\n splitCommand,\n statsCommand,\n templatesCommand,\n timelineCommand,\n tokensCommand,\n uiCommand,\n unlinkCommand,\n updateCommand,\n validateCommand,\n viewCommand,\n} from './index.js';\n\n/**\n * Register all commands in alphabetical order\n */\nexport function registerCommands(program: Command): void {\n // Alphabetically sorted command registration\n program.addCommand(analyzeCommand());\n program.addCommand(archiveCommand());\n program.addCommand(backfillCommand());\n program.addCommand(boardCommand());\n program.addCommand(checkCommand());\n program.addCommand(compactCommand());\n program.addCommand(createCommand());\n program.addCommand(depsCommand());\n program.addCommand(filesCommand());\n program.addCommand(ganttCommand());\n program.addCommand(initCommand());\n program.addCommand(linkCommand());\n program.addCommand(listCommand());\n program.addCommand(mcpCommand());\n program.addCommand(migrateCommand());\n program.addCommand(openCommand());\n program.addCommand(searchCommand());\n program.addCommand(splitCommand());\n program.addCommand(statsCommand());\n program.addCommand(templatesCommand());\n program.addCommand(timelineCommand());\n program.addCommand(tokensCommand());\n program.addCommand(uiCommand());\n program.addCommand(unlinkCommand());\n program.addCommand(updateCommand());\n program.addCommand(validateCommand());\n program.addCommand(viewCommand());\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { registerCommands } from './commands/registry.js';\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\n);\n\nconst program = new Command();\n\nprogram\n .name('lean-spec')\n .description('Manage LeanSpec documents')\n .version(packageJson.version);\n\n// Add custom help text with grouped commands\nprogram.addHelpText('after', `\nCommand Groups:\n\n Core Workflow:\n archive <spec> Move spec to archived/\n backfill [specs...] Backfill timestamps from git history\n create <name> Create new spec\n init Initialize LeanSpec in current directory\n link <spec> Add relationships between specs\n migrate <input-path> Migrate specs from other SDD tools\n unlink <spec> Remove relationships between specs\n update <spec> Update spec metadata\n \n Discovery & Search:\n files <spec> List files in a spec\n list List all specs\n open <spec> Open spec in editor\n search <query> Full-text search with metadata filters\n view <spec> View spec content\n \n Project Analytics:\n board Show Kanban-style board view\n deps <spec> Show dependency graph for a spec\n gantt Show timeline with dependencies\n stats Show aggregate statistics\n timeline Show creation/completion over time\n \n Quality & Optimization:\n analyze <spec> Analyze spec complexity and structure\n check Check for sequence conflicts\n tokens [spec] Count tokens for LLM context management\n validate [specs...] Validate specs for quality issues\n \n Advanced Editing:\n compact <spec> Remove specified line ranges from spec\n split <spec> Split spec into multiple files\n \n Configuration:\n templates Manage spec templates\n \n Integration:\n mcp Start MCP server for AI assistants\n ui Start local web UI for spec management\n\nExamples:\n $ lean-spec init\n $ lean-spec create my-feature --priority high\n $ lean-spec list --status in-progress\n $ lean-spec view 042\n $ lean-spec link 085 --depends-on 042,035\n $ lean-spec link 085 --related 082\n $ lean-spec unlink 085 --depends-on 042\n $ lean-spec deps 085\n $ lean-spec backfill --dry-run\n $ lean-spec migrate ./docs/adr\n $ lean-spec migrate ./docs/rfcs --with copilot\n $ lean-spec board --tag backend\n $ lean-spec search \"authentication\"\n $ lean-spec validate\n $ lean-spec tokens 059\n $ lean-spec analyze 045 --json\n $ lean-spec split 045 --output README.md:1-150 --output DESIGN.md:151-end\n $ lean-spec ui\n $ lean-spec ui --port 3001 --no-open\n $ lean-spec ui --specs ./docs/specs --dry-run\n`);\n\n// Register all commands (alphabetically ordered)\nregisterCommands(program);\n\n// Parse and execute\nprogram.parse();\n"]}
1
+ {"version":3,"sources":["../src/commands/registry.ts","../src/cli.ts"],"names":["program"],"mappings":"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","file":"cli.js","sourcesContent":["import { Command } from 'commander';\nimport {\n analyzeCommand,\n archiveCommand,\n backfillCommand,\n boardCommand,\n checkCommand,\n compactCommand,\n createCommand,\n depsCommand,\n examplesCommand,\n filesCommand,\n ganttCommand,\n initCommand,\n linkCommand,\n listCommand,\n mcpCommand,\n migrateCommand,\n openCommand,\n searchCommand,\n splitCommand,\n statsCommand,\n templatesCommand,\n timelineCommand,\n tokensCommand,\n uiCommand,\n unlinkCommand,\n updateCommand,\n validateCommand,\n viewCommand,\n} from './index.js';\n\n/**\n * Register all commands in alphabetical order\n */\nexport function registerCommands(program: Command): void {\n // Alphabetically sorted command registration\n program.addCommand(analyzeCommand());\n program.addCommand(archiveCommand());\n program.addCommand(backfillCommand());\n program.addCommand(boardCommand());\n program.addCommand(checkCommand());\n program.addCommand(compactCommand());\n program.addCommand(createCommand());\n program.addCommand(depsCommand());\n program.addCommand(examplesCommand());\n program.addCommand(filesCommand());\n program.addCommand(ganttCommand());\n program.addCommand(initCommand());\n program.addCommand(linkCommand());\n program.addCommand(listCommand());\n program.addCommand(mcpCommand());\n program.addCommand(migrateCommand());\n program.addCommand(openCommand());\n program.addCommand(searchCommand());\n program.addCommand(splitCommand());\n program.addCommand(statsCommand());\n program.addCommand(templatesCommand());\n program.addCommand(timelineCommand());\n program.addCommand(tokensCommand());\n program.addCommand(uiCommand());\n program.addCommand(unlinkCommand());\n program.addCommand(updateCommand());\n program.addCommand(validateCommand());\n program.addCommand(viewCommand());\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { fileURLToPath } from 'url';\nimport { dirname, join } from 'path';\nimport { registerCommands } from './commands/registry.js';\n\n// Get version from package.json\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf-8')\n);\n\nconst program = new Command();\n\nprogram\n .name('lean-spec')\n .description('Manage LeanSpec documents')\n .version(packageJson.version);\n\n// Add custom help text with grouped commands\nprogram.addHelpText('after', `\nCommand Groups:\n\n Core Workflow:\n archive <spec> Move spec to archived/\n backfill [specs...] Backfill timestamps from git history\n create <name> Create new spec\n examples List example projects for tutorials\n init Initialize LeanSpec in current directory\n link <spec> Add relationships between specs\n migrate <input-path> Migrate specs from other SDD tools\n unlink <spec> Remove relationships between specs\n update <spec> Update spec metadata\n \n Discovery & Search:\n files <spec> List files in a spec\n list List all specs\n open <spec> Open spec in editor\n search <query> Full-text search with metadata filters\n view <spec> View spec content\n \n Project Analytics:\n board Show Kanban-style board view\n deps <spec> Show dependency graph for a spec\n gantt Show timeline with dependencies\n stats Show aggregate statistics\n timeline Show creation/completion over time\n \n Quality & Optimization:\n analyze <spec> Analyze spec complexity and structure\n check Check for sequence conflicts\n tokens [spec] Count tokens for LLM context management\n validate [specs...] Validate specs for quality issues\n \n Advanced Editing:\n compact <spec> Remove specified line ranges from spec\n split <spec> Split spec into multiple files\n \n Configuration:\n templates Manage spec templates\n \n Integration:\n mcp Start MCP server for AI assistants\n ui Start local web UI for spec management\n\nExamples:\n $ lean-spec init\n $ lean-spec init -y\n $ lean-spec init --example dark-theme\n $ lean-spec init --example dashboard-widgets --name my-demo\n $ lean-spec examples\n $ lean-spec create my-feature --priority high\n $ lean-spec list --status in-progress\n $ lean-spec view 042\n $ lean-spec link 085 --depends-on 042,035\n $ lean-spec link 085 --related 082\n $ lean-spec unlink 085 --depends-on 042\n $ lean-spec deps 085\n $ lean-spec backfill --dry-run\n $ lean-spec migrate ./docs/adr\n $ lean-spec migrate ./docs/rfcs --with copilot\n $ lean-spec board --tag backend\n $ lean-spec search \"authentication\"\n $ lean-spec validate\n $ lean-spec tokens 059\n $ lean-spec analyze 045 --json\n $ lean-spec split 045 --output README.md:1-150 --output DESIGN.md:151-end\n $ lean-spec ui\n $ lean-spec ui --port 3001 --no-open\n $ lean-spec ui --specs ./docs/specs --dry-run\n`);\n\n// Register all commands (alphabetically ordered)\nregisterCommands(program);\n\n// Parse and execute\nprogram.parse();\n"]}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export { createMcpServer } from './chunk-7WXYOHZU.js';
2
+ export { createMcpServer } from './chunk-RTEGSMVL.js';
3
3
  import './chunk-LVD7ZAVZ.js';
4
4
  //# sourceMappingURL=mcp-server.js.map
5
5
  //# sourceMappingURL=mcp-server.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lean-spec",
3
- "version": "0.2.5",
3
+ "version": "0.2.6-dev.20251125010539",
4
4
  "description": "Specification-driven development made simple",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,7 +48,6 @@
48
48
  "commander": "^14.0.2",
49
49
  "dayjs": "^1.11.19",
50
50
  "gray-matter": "^4.0.3",
51
- "handlebars": "^4.7.8",
52
51
  "ink": "^6.4.0",
53
52
  "ink-gradient": "^3.0.0",
54
53
  "ink-progress-bar": "^3.0.0",
@@ -68,7 +67,7 @@
68
67
  "zod": "^3.25.76"
69
68
  },
70
69
  "devDependencies": {
71
- "@leanspec/core": "^0.2.5",
70
+ "@leanspec/core": "workspace:*",
72
71
  "@types/js-yaml": "^4.0.9",
73
72
  "@types/marked-terminal": "^6.1.1",
74
73
  "@types/node": "^20.10.0",
@@ -0,0 +1,113 @@
1
+ # AI Agent Instructions
2
+
3
+ ## Project: {project_name}
4
+
5
+ Lightweight spec methodology for AI-powered development.
6
+
7
+ ## Core Rules
8
+
9
+ 1. **Read README.md first** - Understand project context
10
+ 2. **Check specs/** - Review existing specs before starting
11
+ 3. **Use `lean-spec --help`** - When unsure about commands, check the built-in help
12
+ 4. **Follow LeanSpec principles** - Clarity over documentation
13
+ 5. **Keep it minimal** - If it doesn't add clarity, cut it
14
+ 6. **NEVER manually edit system-managed frontmatter** - Fields like `status`, `priority`, `tags`, `assignee`, `transitions`, `created_at`, `updated_at`, `completed_at`, `depends_on`, `related` are system-managed. Always use `lean-spec update`, `lean-spec link`, `lean-spec unlink`, or `lean-spec create` commands. Manual edits will cause metadata corruption and tracking issues.
15
+ 7. **Never use nested code blocks** - Markdown doesn't support code blocks within code blocks. If you need to show code examples in documentation, use indentation or describe the structure instead of nesting backticks.
16
+
17
+ ## When to Use Specs
18
+
19
+ Write a spec for:
20
+ - Features affecting multiple parts of the system
21
+ - Breaking changes or significant refactors
22
+ - Design decisions needing team alignment
23
+
24
+ Skip specs for:
25
+ - Bug fixes
26
+ - Trivial changes
27
+ - Self-explanatory refactors
28
+
29
+ ## Essential Commands
30
+
31
+ **Quick Reference** (for full details, see `lean-spec --help`):
32
+
33
+ **Discovery:**
34
+ - `lean-spec list` - See all specs
35
+ - `lean-spec search "<query>"` - Find relevant specs
36
+
37
+ **Working with specs:**
38
+ - `lean-spec create <name>` - Create new spec
39
+ - `lean-spec update <spec> --status <status>` - Update status (REQUIRED - never edit frontmatter manually)
40
+ - `lean-spec update <spec> --priority <priority>` - Update priority
41
+ - `lean-spec deps <spec>` - Show dependency graph
42
+ - `lean-spec tokens <spec>` - Count tokens for context management
43
+
44
+ **Project overview:**
45
+ - `lean-spec board` - Kanban view with project health
46
+ - `lean-spec stats` - Quick project metrics
47
+
48
+ **When in doubt:** Run `lean-spec --help` or `lean-spec <command> --help` to discover commands.
49
+
50
+ ## Spec Relationships
51
+
52
+ LeanSpec has two types of relationships:
53
+
54
+ ### `related` - Bidirectional Soft Reference
55
+ Informational relationship between specs. Automatically shown from both sides.
56
+
57
+ **Use when:** Specs cover related topics, work is coordinated but not blocking.
58
+
59
+ ### `depends_on` - Directional Blocking Dependency
60
+ Hard dependency - spec cannot start until dependencies complete.
61
+
62
+ **Use when:** Spec truly cannot start until another completes, work order matters.
63
+
64
+ **Best Practice:** Use `related` by default. Reserve `depends_on` for true blocking dependencies.
65
+
66
+ ## SDD Workflow
67
+
68
+ 1. **Discover** - Check existing specs with `lean-spec list`
69
+ 2. **Plan** - Create spec with `lean-spec create <name>` (status: `planned`)
70
+ 3. **Start Work** - Run `lean-spec update <spec> --status in-progress` before implementing
71
+ 4. **Implement** - Write code/docs, keep spec in sync as you learn
72
+ 5. **Complete** - Run `lean-spec update <spec> --status complete` after implementation done
73
+ 6. **Document** - Report progress and document changes into the spec
74
+
75
+ **CRITICAL - What "Work" Means:**
76
+ - ❌ **NOT**: Creating/writing the spec document itself
77
+ - ✅ **YES**: Implementing what the spec describes (code, docs, features, etc.)
78
+
79
+ **Frontmatter Editing Rules:**
80
+ - **NEVER manually edit**: `status`, `priority`, `tags`, `assignee`, `transitions`, timestamps, `depends_on`, `related`
81
+ - **Use CLI commands**: `lean-spec update`, `lean-spec link`, `lean-spec unlink`
82
+
83
+ **Note on Archiving**: Archive specs when they're no longer actively referenced (weeks/months after completion), not immediately. Use `lean-spec archive <spec>` to move old/stale specs to `archived/` directory.
84
+
85
+ ## Quality Standards
86
+
87
+ - Code is clear and maintainable
88
+ - Tests cover critical paths
89
+ - Specs stay in sync with implementation
90
+ - **Status tracking is mandatory:**
91
+ - Specs start as `planned` after creation
92
+ - Mark `in-progress` BEFORE starting implementation work
93
+ - Mark `complete` AFTER implementation is finished
94
+ - **Remember**: Status tracks implementation, not spec document completion
95
+ - Never leave specs with stale status
96
+
97
+ ## Spec Complexity Guidelines
98
+
99
+ **Token Thresholds:**
100
+ - **<2,000 tokens**: ✅ Optimal
101
+ - **2,000-3,500 tokens**: ✅ Good
102
+ - **3,500-5,000 tokens**: ⚠️ Warning - Consider splitting
103
+ - **>5,000 tokens**: 🔴 Should split
104
+
105
+ **Check with:** `lean-spec tokens <spec>`
106
+
107
+ **When to split:** >3,500 tokens, multiple concerns, takes >10 min to read
108
+
109
+ **How to split:** Use sub-specs or split into related specs with `lean-spec link --related`
110
+
111
+ ---
112
+
113
+ **Remember**: LeanSpec is a mindset, not a rulebook. When in doubt, keep it simple and use `lean-spec --help` to discover features as needed.
@@ -0,0 +1,28 @@
1
+ # Detailed Template
2
+
3
+ For complex specs that benefit from structured sub-specs. Demonstrates how to manage token limits.
4
+
5
+ ## What's Included
6
+
7
+ - **AGENTS.md** - Same AI agent instructions as standard template
8
+ - **Sub-spec structure** - README.md + DESIGN.md + PLAN.md + TEST.md
9
+ - Demonstrates splitting specs to stay under token limits
10
+ - Example of real-world sub-spec organization
11
+
12
+ ## When to Use
13
+
14
+ - Complex features with lots of detail
15
+ - Specs approaching 3,500+ tokens
16
+ - Need clear separation of concerns (design, plan, test)
17
+ - Large teams with multiple reviewers
18
+
19
+ ## Philosophy
20
+
21
+ Keep it lean, but organized. Use sub-specs to manage complexity without overwhelming context. Each file stays focused and under token limits.
22
+
23
+ ## Next Steps
24
+
25
+ 1. Customize AGENTS.md for your project
26
+ 2. Create your first spec: `lean-spec create my-feature`
27
+ 3. When a spec grows large, split sections into sub-spec files
28
+
@@ -0,0 +1,43 @@
1
+ # Design: {name}
2
+
3
+ > Part of [{name}](README.md)
4
+
5
+ ## Architecture
6
+
7
+ <!-- High-level system design, components, interactions -->
8
+
9
+ ## Technical Approach
10
+
11
+ <!-- Specific technologies, patterns, frameworks -->
12
+
13
+ ## Design Decisions
14
+
15
+ <!-- Key decisions and rationale -->
16
+
17
+ ### Decision 1
18
+
19
+ **Context**: <!-- What problem does this solve? -->
20
+
21
+ **Decision**: <!-- What did we choose? -->
22
+
23
+ **Rationale**: <!-- Why this approach? -->
24
+
25
+ **Trade-offs**: <!-- What are we giving up? -->
26
+
27
+ ## Dependencies
28
+
29
+ <!-- What does this depend on? What depends on this? -->
30
+
31
+ ### System Dependencies
32
+ -
33
+
34
+ ### Team Dependencies
35
+ -
36
+
37
+ ## Security & Compliance
38
+
39
+ <!-- Security implications, compliance requirements -->
40
+
41
+ - [ ] Handles sensitive data (PII, credentials, etc.)
42
+ - [ ] Security review completed
43
+ - [ ] Compliance requirements addressed
@@ -0,0 +1,59 @@
1
+ # Plan: {name}
2
+
3
+ > Part of [{name}](README.md)
4
+
5
+ ## Implementation Phases
6
+
7
+ ### Phase 1: [Name]
8
+
9
+ **Goal**: <!-- What does this phase achieve? -->
10
+
11
+ **Tasks**:
12
+ - [ ] Task 1
13
+ - [ ] Task 2
14
+ - [ ] Task 3
15
+
16
+ **Dependencies**: <!-- What must be done before this? -->
17
+
18
+ **Success criteria**: <!-- How do we know this is done? -->
19
+
20
+ ### Phase 2: [Name]
21
+
22
+ **Goal**: <!-- What does this phase achieve? -->
23
+
24
+ **Tasks**:
25
+ - [ ] Task 1
26
+ - [ ] Task 2
27
+ - [ ] Task 3
28
+
29
+ **Dependencies**: <!-- What must be done before this? -->
30
+
31
+ **Success criteria**: <!-- How do we know this is done? -->
32
+
33
+ ## Rollout Strategy
34
+
35
+ <!-- How will this be deployed to production? -->
36
+
37
+ **Staging**:
38
+ -
39
+
40
+ **Production**:
41
+ -
42
+
43
+ **Monitoring**:
44
+ -
45
+
46
+ **Rollback plan**:
47
+ -
48
+
49
+ ## Timeline
50
+
51
+ | Phase | Duration | Dependencies |
52
+ |-------|----------|--------------|
53
+ | | | |
54
+
55
+ ## Risks
56
+
57
+ | Risk | Impact | Mitigation |
58
+ |------|--------|------------|
59
+ | | | |
@@ -0,0 +1,30 @@
1
+ ---
2
+ status: planned
3
+ created: '{date}'
4
+ tags: []
5
+ priority: medium
6
+ ---
7
+
8
+ # {name}
9
+
10
+ > **Status**: {status} · **Priority**: {priority} · **Created**: {date}
11
+
12
+ ## Overview
13
+
14
+ <!-- What are we solving? Why now? Expected impact? -->
15
+
16
+ ## Sub-Specs
17
+
18
+ For detailed information, see:
19
+
20
+ - **[DESIGN.md](DESIGN.md)** - Technical architecture and design decisions
21
+ - **[PLAN.md](PLAN.md)** - Implementation plan and phases
22
+ - **[TEST.md](TEST.md)** - Testing strategy and verification
23
+
24
+ ## Quick Summary
25
+
26
+ <!-- Brief summary of the spec (2-3 paragraphs max) -->
27
+
28
+ ## Notes
29
+
30
+ <!-- Key decisions, constraints, open questions -->
@@ -0,0 +1,71 @@
1
+ # Test: {name}
2
+
3
+ > Part of [{name}](README.md)
4
+
5
+ ## Testing Strategy
6
+
7
+ <!-- Overall approach to verifying this works -->
8
+
9
+ ## Unit Tests
10
+
11
+ <!-- Component-level testing -->
12
+
13
+ **Scope**:
14
+ -
15
+
16
+ **Key test cases**:
17
+ - [ ] Test case 1
18
+ - [ ] Test case 2
19
+ - [ ] Test case 3
20
+
21
+ ## Integration Tests
22
+
23
+ <!-- System interaction testing -->
24
+
25
+ **Scope**:
26
+ -
27
+
28
+ **Key test cases**:
29
+ - [ ] Test case 1
30
+ - [ ] Test case 2
31
+ - [ ] Test case 3
32
+
33
+ ## Performance Tests
34
+
35
+ <!-- Load, stress, and performance testing -->
36
+
37
+ **Requirements**:
38
+ -
39
+
40
+ **Test scenarios**:
41
+ - [ ] Scenario 1
42
+ - [ ] Scenario 2
43
+
44
+ ## Security Tests
45
+
46
+ <!-- Security validation -->
47
+
48
+ **Security checks**:
49
+ - [ ] Authentication/authorization
50
+ - [ ] Input validation
51
+ - [ ] Data encryption
52
+ - [ ] Audit logging
53
+
54
+ ## Acceptance Criteria
55
+
56
+ <!-- What must be true for this to be considered complete? -->
57
+
58
+ - [ ] Criterion 1
59
+ - [ ] Criterion 2
60
+ - [ ] Criterion 3
61
+
62
+ ## Test Data
63
+
64
+ <!-- What test data is needed? -->
65
+
66
+ ## Manual Testing
67
+
68
+ <!-- What requires human verification? -->
69
+
70
+ - [ ] Manual test 1
71
+ - [ ] Manual test 2
@@ -0,0 +1,81 @@
1
+ # API Refactor Demo
2
+
3
+ > **Tutorial**: [Refactoring with Specs](https://leanspec.dev/docs/tutorials/refactoring-specs)
4
+
5
+ ## Scenario
6
+
7
+ You're maintaining a Node.js application that started simple but has grown messy. The app integrates with multiple external services (weather API, currency converter, timezone lookup), but all the HTTP logic is tangled together in the main application code.
8
+
9
+ You want to extract a reusable API client module that:
10
+ - Centralizes HTTP request handling
11
+ - Provides a clean interface for service calls
12
+ - Handles errors consistently
13
+ - Makes the code easier to test and maintain
14
+
15
+ ## What's Here
16
+
17
+ A monolithic Node.js app with:
18
+ - Weather lookup feature (calls external API)
19
+ - Currency conversion (calls external API)
20
+ - Timezone lookup (calls external API)
21
+ - All HTTP logic mixed into business logic (tight coupling)
22
+ - No error handling abstraction
23
+ - Hard to test individual parts
24
+
25
+ **Files:**
26
+ - `src/app.js` - Main application with all features
27
+ - `src/services/weatherService.js` - Weather API calls (tightly coupled)
28
+ - `src/services/currencyService.js` - Currency API calls (tightly coupled)
29
+ - `src/services/timezoneService.js` - Timezone API calls (tightly coupled)
30
+
31
+ ## Getting Started
32
+
33
+ ```bash
34
+ # Install dependencies
35
+ npm install
36
+
37
+ # Run the app
38
+ npm start
39
+
40
+ # Try the features:
41
+ # - Weather: Get weather for a city
42
+ # - Currency: Convert between currencies
43
+ # - Timezone: Look up timezone info
44
+ ```
45
+
46
+ ## Your Mission
47
+
48
+ Refactor the HTTP logic into a clean, reusable API client. Follow the tutorial and ask your AI assistant:
49
+
50
+ > "Help me refactor this app using LeanSpec. I want to extract a reusable API client module that centralizes all the HTTP logic."
51
+
52
+ The AI will guide you through:
53
+ 1. Creating a refactoring spec
54
+ 2. Designing the API client interface
55
+ 3. Extracting the HTTP logic step by step
56
+ 4. Updating services to use the new client
57
+ 5. Verifying everything still works
58
+
59
+ ## Current Problems
60
+
61
+ - **Duplicated code**: Each service reimplements HTTP requests
62
+ - **No error handling**: Errors handled inconsistently
63
+ - **Hard to test**: Can't mock HTTP calls easily
64
+ - **Tight coupling**: Business logic mixed with HTTP details
65
+ - **No retry logic**: Network failures aren't handled
66
+
67
+ These are perfect opportunities to practice refactoring with specs!
68
+
69
+ ## Expected Result
70
+
71
+ After refactoring, you should have:
72
+ ```
73
+ src/
74
+ app.js (unchanged interface)
75
+ client/
76
+ apiClient.js (new - centralized HTTP logic)
77
+ services/
78
+ weatherService.js (simplified - uses apiClient)
79
+ currencyService.js (simplified - uses apiClient)
80
+ timezoneService.js (simplified - uses apiClient)
81
+ ```
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "api-refactor-demo",
3
+ "version": "1.0.0",
4
+ "description": "Monolithic Node.js app for LeanSpec Tutorial 3",
5
+ "type": "module",
6
+ "scripts": {
7
+ "start": "node src/app.js",
8
+ "dev": "node --watch src/app.js"
9
+ },
10
+ "keywords": ["leanspec", "tutorial", "demo"],
11
+ "author": "",
12
+ "license": "MIT",
13
+ "dependencies": {
14
+ "node-fetch": "^3.3.2"
15
+ }
16
+ }
@@ -0,0 +1,40 @@
1
+ import { getWeather } from './services/weatherService.js';
2
+ import { convertCurrency } from './services/currencyService.js';
3
+ import { getTimezone } from './services/timezoneService.js';
4
+
5
+ console.log('=== Multi-Service App Demo ===\n');
6
+
7
+ // Demo 1: Weather lookup
8
+ console.log('1. Weather Lookup:');
9
+ try {
10
+ const weather = await getWeather('London');
11
+ console.log(` ${weather.city}: ${weather.temp}°C, ${weather.condition}`);
12
+ } catch (error) {
13
+ console.log(` Error: ${error.message}`);
14
+ }
15
+
16
+ console.log('');
17
+
18
+ // Demo 2: Currency conversion
19
+ console.log('2. Currency Conversion:');
20
+ try {
21
+ const result = await convertCurrency(100, 'USD', 'EUR');
22
+ console.log(` ${result.amount} ${result.from} = ${result.converted} ${result.to}`);
23
+ } catch (error) {
24
+ console.log(` Error: ${error.message}`);
25
+ }
26
+
27
+ console.log('');
28
+
29
+ // Demo 3: Timezone lookup
30
+ console.log('3. Timezone Lookup:');
31
+ try {
32
+ const timezone = await getTimezone('America/New_York');
33
+ console.log(` ${timezone.name}: ${timezone.offset} (${timezone.abbreviation})`);
34
+ } catch (error) {
35
+ console.log(` Error: ${error.message}`);
36
+ }
37
+
38
+ console.log('');
39
+ console.log('Notice: All services work, but they all duplicate HTTP logic!');
40
+ console.log('Your task: Extract a reusable API client module.');
@@ -0,0 +1,43 @@
1
+ import fetch from 'node-fetch';
2
+
3
+ /**
4
+ * Convert currency
5
+ *
6
+ * PROBLEM: Duplicates HTTP logic from weatherService
7
+ * - Same fetch boilerplate
8
+ * - Same error handling pattern
9
+ * - Same JSON parsing
10
+ * - Should be using a shared HTTP client!
11
+ */
12
+ export async function convertCurrency(amount, from, to) {
13
+ // Mock API endpoint (replace with real API in production)
14
+ const url = `https://api.exchangerate.host/convert?from=${from}&to=${to}&amount=${amount}`;
15
+
16
+ try {
17
+ const response = await fetch(url);
18
+
19
+ if (!response.ok) {
20
+ throw new Error(`Currency API error: ${response.status}`);
21
+ }
22
+
23
+ const data = await response.json();
24
+
25
+ // Business logic: Transform API response to our format
26
+ return {
27
+ amount,
28
+ from,
29
+ to,
30
+ converted: data.result || (amount * 0.85).toFixed(2),
31
+ rate: data.info?.rate || 0.85,
32
+ };
33
+ } catch (error) {
34
+ // For demo, return mock data on error
35
+ return {
36
+ amount,
37
+ from,
38
+ to,
39
+ converted: (amount * 0.85).toFixed(2),
40
+ rate: 0.85,
41
+ };
42
+ }
43
+ }
@@ -0,0 +1,41 @@
1
+ import fetch from 'node-fetch';
2
+
3
+ /**
4
+ * Get timezone information
5
+ *
6
+ * PROBLEM: Yet another copy of the same HTTP logic!
7
+ * - Third time we're writing fetch + error handling + JSON parsing
8
+ * - Violates DRY principle
9
+ * - Makes testing hard (need to mock fetch in 3 places)
10
+ * - Changes to HTTP logic need updates in 3 files
11
+ */
12
+ export async function getTimezone(zone) {
13
+ // Mock API endpoint (replace with real API in production)
14
+ const url = `http://worldtimeapi.org/api/timezone/${zone}`;
15
+
16
+ try {
17
+ const response = await fetch(url);
18
+
19
+ if (!response.ok) {
20
+ throw new Error(`Timezone API error: ${response.status}`);
21
+ }
22
+
23
+ const data = await response.json();
24
+
25
+ // Business logic: Transform API response to our format
26
+ return {
27
+ name: data.timezone || zone,
28
+ offset: data.utc_offset || '-05:00',
29
+ abbreviation: data.abbreviation || 'EST',
30
+ datetime: data.datetime || new Date().toISOString(),
31
+ };
32
+ } catch (error) {
33
+ // For demo, return mock data on error
34
+ return {
35
+ name: zone,
36
+ offset: '-05:00',
37
+ abbreviation: 'EST',
38
+ datetime: new Date().toISOString(),
39
+ };
40
+ }
41
+ }