forge-dev-framework 1.0.1 → 1.2.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 (109) hide show
  1. package/.claude/commands/forge/README.md +281 -0
  2. package/.claude/commands/forge/add-phase.md +90 -0
  3. package/.claude/commands/forge/complete-milestone.md +130 -0
  4. package/.claude/commands/forge/config.md +115 -0
  5. package/.claude/commands/forge/convert.md +31 -0
  6. package/.claude/commands/forge/debug.md +31 -0
  7. package/.claude/commands/forge/discuss.md +78 -0
  8. package/.claude/commands/forge/execute.md +85 -0
  9. package/.claude/commands/forge/generate.md +21 -0
  10. package/.claude/commands/forge/help.md +18 -0
  11. package/.claude/commands/forge/init.md +21 -0
  12. package/.claude/commands/forge/insert-phase.md +99 -0
  13. package/.claude/commands/forge/new-milestone.md +114 -0
  14. package/.claude/commands/forge/new-project.md +24 -0
  15. package/.claude/commands/forge/pause-work.md +111 -0
  16. package/.claude/commands/forge/plan.md +129 -0
  17. package/.claude/commands/forge/quick.md +41 -0
  18. package/.claude/commands/forge/remove-phase.md +92 -0
  19. package/.claude/commands/forge/resume.md +22 -0
  20. package/.claude/commands/forge/status.md +87 -0
  21. package/.claude/commands/forge/team-add.md +24 -0
  22. package/.claude/commands/forge/team-create.md +22 -0
  23. package/.claude/commands/forge/team-remove.md +24 -0
  24. package/.claude/commands/forge/team-start.md +22 -0
  25. package/.claude/commands/forge/team-view.md +18 -0
  26. package/.claude/commands/forge/verify.md +95 -0
  27. package/.claude/hooks/forge-context-cleanup.cjs +79 -0
  28. package/.claude/hooks/forge-event-guard.cjs +36 -0
  29. package/.claude/hooks/forge-size-guard.cjs +55 -0
  30. package/.claude/rules/api-patterns.md +13 -98
  31. package/.claude/rules/context-efficiency.md +10 -0
  32. package/.claude/rules/security-baseline.md +18 -204
  33. package/.claude/rules/testing-standards.md +16 -177
  34. package/.claude/rules/ui-conventions.md +17 -142
  35. package/README.md +1 -0
  36. package/bin/forge.js +5 -3
  37. package/dist/bin/forge.js +5 -3
  38. package/dist/cli/index.d.ts.map +1 -1
  39. package/dist/cli/index.js +15 -1
  40. package/dist/cli/index.js.map +1 -1
  41. package/dist/commands/convert.d.ts +6 -0
  42. package/dist/commands/convert.d.ts.map +1 -0
  43. package/dist/commands/convert.js +132 -0
  44. package/dist/commands/convert.js.map +1 -0
  45. package/dist/commands/generate.d.ts.map +1 -1
  46. package/dist/commands/generate.js +3 -2
  47. package/dist/commands/generate.js.map +1 -1
  48. package/dist/commands/index.d.ts +4 -4
  49. package/dist/commands/index.d.ts.map +1 -1
  50. package/dist/commands/index.js +4 -4
  51. package/dist/commands/index.js.map +1 -1
  52. package/dist/generators/gsd-converter.d.ts +100 -0
  53. package/dist/generators/gsd-converter.d.ts.map +1 -0
  54. package/dist/generators/gsd-converter.js +335 -0
  55. package/dist/generators/gsd-converter.js.map +1 -0
  56. package/dist/templates/.claude/rules/api-patterns.md.template +212 -0
  57. package/dist/templates/.claude/rules/security-baseline.md.template +322 -0
  58. package/dist/templates/.claude/rules/testing-standards.md.template +280 -0
  59. package/dist/templates/.claude/rules/ui-conventions.md.template +264 -0
  60. package/dist/templates/.planning/forge.config.json.template +75 -0
  61. package/dist/templates/CLAUDE.md.template +161 -0
  62. package/dist/templates/PLAN.md.template +177 -0
  63. package/dist/templates/PROJECT.md.template +156 -0
  64. package/dist/templates/REQUIREMENTS.md.template +221 -0
  65. package/dist/templates/ROADMAP.md.template +130 -0
  66. package/dist/types/index.d.ts +2 -2
  67. package/dist/types/index.d.ts.map +1 -1
  68. package/dist/types/index.js +2 -2
  69. package/dist/types/index.js.map +1 -1
  70. package/dist/utils/index.d.ts +5 -5
  71. package/dist/utils/index.d.ts.map +1 -1
  72. package/dist/utils/index.js +5 -5
  73. package/dist/utils/index.js.map +1 -1
  74. package/dist/utils/template-client.d.ts.map +1 -1
  75. package/dist/utils/template-client.js +3 -2
  76. package/dist/utils/template-client.js.map +1 -1
  77. package/package.json +6 -4
  78. package/dist/git/__tests__/worktree.test.d.ts +0 -5
  79. package/dist/git/__tests__/worktree.test.d.ts.map +0 -1
  80. package/dist/git/__tests__/worktree.test.js +0 -121
  81. package/dist/git/__tests__/worktree.test.js.map +0 -1
  82. package/dist/git/codeowners.d.ts +0 -101
  83. package/dist/git/codeowners.d.ts.map +0 -1
  84. package/dist/git/codeowners.js +0 -216
  85. package/dist/git/codeowners.js.map +0 -1
  86. package/dist/git/commit.d.ts +0 -135
  87. package/dist/git/commit.d.ts.map +0 -1
  88. package/dist/git/commit.js +0 -223
  89. package/dist/git/commit.js.map +0 -1
  90. package/dist/git/hooks/commit-msg.d.ts +0 -8
  91. package/dist/git/hooks/commit-msg.d.ts.map +0 -1
  92. package/dist/git/hooks/commit-msg.js +0 -34
  93. package/dist/git/hooks/commit-msg.js.map +0 -1
  94. package/dist/git/hooks/pre-commit.d.ts +0 -8
  95. package/dist/git/hooks/pre-commit.d.ts.map +0 -1
  96. package/dist/git/hooks/pre-commit.js +0 -34
  97. package/dist/git/hooks/pre-commit.js.map +0 -1
  98. package/dist/git/pre-commit-hooks.d.ts +0 -117
  99. package/dist/git/pre-commit-hooks.d.ts.map +0 -1
  100. package/dist/git/pre-commit-hooks.js +0 -270
  101. package/dist/git/pre-commit-hooks.js.map +0 -1
  102. package/dist/git/wipe-protocol.d.ts +0 -281
  103. package/dist/git/wipe-protocol.d.ts.map +0 -1
  104. package/dist/git/wipe-protocol.js +0 -237
  105. package/dist/git/wipe-protocol.js.map +0 -1
  106. package/dist/git/worktree.d.ts +0 -69
  107. package/dist/git/worktree.d.ts.map +0 -1
  108. package/dist/git/worktree.js +0 -202
  109. package/dist/git/worktree.js.map +0 -1
@@ -0,0 +1,335 @@
1
+ /**
2
+ * GSD to FORGE Project Converter
3
+ *
4
+ * Converts existing GSD projects to FORGE format by:
5
+ * 1. Reading GSD artifacts (PROJECT.md, ROADMAP.md, phase plans)
6
+ * 2. Creating FORGE equivalents (CLAUDE.md, STATE.json)
7
+ * 3. Preserving roadmap and phase structure
8
+ *
9
+ * @private - Not published to NPM
10
+ */
11
+ import { readFile, writeFile, mkdir, access, readdir } from 'fs/promises';
12
+ import { join, dirname } from 'path';
13
+ import { existsSync } from 'fs';
14
+ /**
15
+ * Detect if current directory is a GSD project
16
+ */
17
+ export async function detectGSDProject(projectPath) {
18
+ const projectMdPath = join(projectPath, 'PROJECT.md');
19
+ const roadmapMdPath = join(projectPath, 'ROADMAP.md');
20
+ const planningDir = join(projectPath, '.planning');
21
+ const info = {
22
+ name: '',
23
+ hasProjectMd: false,
24
+ hasRoadmapMd: false,
25
+ hasPlanningDir: false,
26
+ phases: [],
27
+ };
28
+ // Check for PROJECT.md
29
+ try {
30
+ await access(projectMdPath);
31
+ info.hasProjectMd = true;
32
+ const content = await readFile(projectMdPath, 'utf-8');
33
+ // Extract project name from first line or title
34
+ const nameMatch = content.match(/^#\s+(.+)$/m) || content.match(/^# Project: (.+)$/m);
35
+ if (nameMatch) {
36
+ info.name = nameMatch[1].trim();
37
+ }
38
+ }
39
+ catch {
40
+ // PROJECT.md doesn't exist
41
+ }
42
+ // Check for ROADMAP.md
43
+ try {
44
+ await access(roadmapMdPath);
45
+ info.hasRoadmapMd = true;
46
+ }
47
+ catch {
48
+ // ROADMAP.md doesn't exist
49
+ }
50
+ // Check for .planning directory and phases
51
+ try {
52
+ await access(planningDir);
53
+ info.hasPlanningDir = true;
54
+ // List phases
55
+ const phasesDir = join(planningDir, 'phases');
56
+ try {
57
+ await access(phasesDir);
58
+ const entries = await readdir(phasesDir, { withFileTypes: true });
59
+ info.phases = entries
60
+ .filter((e) => e.name.endsWith('.md') || e.isDirectory())
61
+ .map((e) => e.name)
62
+ .sort();
63
+ }
64
+ catch {
65
+ // phases directory doesn't exist
66
+ }
67
+ }
68
+ catch {
69
+ // .planning directory doesn't exist
70
+ }
71
+ return info;
72
+ }
73
+ /**
74
+ * Extract project metadata from PROJECT.md
75
+ */
76
+ export async function extractProjectMetadata(projectPath) {
77
+ const projectMdPath = join(projectPath, 'PROJECT.md');
78
+ const metadata = {
79
+ name: '',
80
+ description: '',
81
+ techStack: [],
82
+ team: [],
83
+ };
84
+ try {
85
+ const content = await readFile(projectMdPath, 'utf-8');
86
+ // Extract name from title
87
+ const nameMatch = content.match(/^#\s+(.+)$/m);
88
+ if (nameMatch) {
89
+ metadata.name = nameMatch[1].trim();
90
+ }
91
+ // Extract description (usually after title)
92
+ const descMatch = content.match(/^#\s+.+\n+(.+)$/m);
93
+ if (descMatch) {
94
+ metadata.description = descMatch[1].trim();
95
+ }
96
+ // Extract tech stack (looks for "Tech Stack" or similar section)
97
+ const techStackMatch = content.match(/##?\s*(?:Tech Stack|Technology Stack|Stack)\n+([\s\S]+?)(?=\n##|\n*$)/i);
98
+ if (techStackMatch) {
99
+ const techLines = techStackMatch[1]
100
+ .split('\n')
101
+ .map((line) => line.replace(/^[\s\-\*]+/, '').trim())
102
+ .filter((line) => line.length > 0);
103
+ metadata.techStack = techLines;
104
+ }
105
+ }
106
+ catch (error) {
107
+ // PROJECT.md doesn't exist or couldn't be read
108
+ }
109
+ return metadata;
110
+ }
111
+ /**
112
+ * Generate CLAUDE.md from PROJECT.md content
113
+ */
114
+ export async function generateClaudeMd(projectPath) {
115
+ const projectMdPath = join(projectPath, 'PROJECT.md');
116
+ let projectMdContent = '';
117
+ try {
118
+ projectMdContent = await readFile(projectMdPath, 'utf-8');
119
+ }
120
+ catch {
121
+ // PROJECT.md doesn't exist, use template
122
+ }
123
+ const metadata = await extractProjectMetadata(projectPath);
124
+ // Build CLAUDE.md content
125
+ let claudeMd = `# ${metadata.name || 'FORGE Project'}\n\n`;
126
+ claudeMd += `> **Converted from GSD.** This project was migrated from GSD to FORGE.\n`;
127
+ claudeMd += `> Conversion date: ${new Date().toISOString()}\n\n`;
128
+ // Add tech stack if available
129
+ if (metadata.techStack && metadata.techStack.length > 0) {
130
+ claudeMd += `## Tech Stack\n\n`;
131
+ metadata.techStack.forEach((tech) => {
132
+ claudeMd += `- ${tech}\n`;
133
+ });
134
+ claudeMd += `\n`;
135
+ }
136
+ // Add FORGE-specific sections
137
+ claudeMd += `## Core Architecture\n\n`;
138
+ claudeMd += `### Event-Sourced State\n\n`;
139
+ claudeMd += `FORGE uses an **append-only event log** with **single-writer state derivation**:\n\n`;
140
+ claudeMd += `1. All agents write events to \`state/events/\`\n`;
141
+ claudeMd += `2. State Steward (ARCHITECT) merges events → canonical \`STATE.json\`\n`;
142
+ claudeMd += `3. Events are **never modified**, only appended\n`;
143
+ claudeMd += `4. State is **deterministically replayable** from event log\n\n`;
144
+ claudeMd += `### Command System\n\n`;
145
+ claudeMd += `FORGE provides slash commands for Claude Code:\n\n`;
146
+ claudeMd += `\`\`\`\n`;
147
+ claudeMd += `/forge:new-project # Initialize new FORGE project\n`;
148
+ claudeMd += `/forge:init # Initialize FORGE in current directory\n`;
149
+ claudeMd += `/forge:status # Show project progress\n`;
150
+ claudeMd += `/forge:config # View/edit configuration\n`;
151
+ claudeMd += `/forge:discuss # Capture phase context\n`;
152
+ claudeMd += `/forge:plan # Generate task breakdown\n`;
153
+ claudeMd += `/forge:verify # Verify plan against requirements\n`;
154
+ claudeMd += `/forge:execute # Execute phase with agent teams\n`;
155
+ claudeMd += `/forge:generate # Generate artifact from template\n`;
156
+ claudeMd += `/forge:help # Show command reference\n`;
157
+ claudeMd += `\`\`\`\n\n`;
158
+ claudeMd += `### The Wipe Protocol\n\n`;
159
+ claudeMd += `Agent context is **ephemeral**, git is **persistent**:\n\n`;
160
+ claudeMd += `1. **Hydrate** — Agent reads CLAUDE.md + STATE.json + task + contracts\n`;
161
+ claudeMd += `2. **Execute** — Agent writes code, runs tests\n`;
162
+ claudeMd += `3. **Commit** — Atomic git commit (one task = one commit)\n`;
163
+ claudeMd += `4. **Terminate** — Session ends, context wiped\n`;
164
+ claudeMd += `5. **Reincarnate** — Next task starts with fresh context\n\n`;
165
+ claudeMd += `## Hard Rules\n\n`;
166
+ claudeMd += `### 5-6 Task Limit\n\n`;
167
+ claudeMd += `Each teammate gets **maximum 6 atomic tasks per phase**.\n\n`;
168
+ claudeMd += `### Atomic Commits\n\n`;
169
+ claudeMd += `**Every task = one git commit.** No exceptions.\n\n`;
170
+ claudeMd += `Commit format: \`type(scope): description\`\n\n`;
171
+ // Include original PROJECT.md content as appendix
172
+ if (projectMdContent) {
173
+ claudeMd += `\n---\n\n## Original GSD Content\n\n`;
174
+ claudeMd += `The following content was preserved from the original GSD PROJECT.md:\n\n`;
175
+ claudeMd += projectMdContent;
176
+ }
177
+ return claudeMd;
178
+ }
179
+ /**
180
+ * Extract tasks from GSD phase plans and convert to FORGE tasks
181
+ */
182
+ export async function extractTasksFromPhases(projectPath) {
183
+ const phasesDir = join(projectPath, '.planning', 'phases');
184
+ const tasks = [];
185
+ let currentMilestone = 'v1.0-M1';
186
+ let taskId = 1;
187
+ try {
188
+ await access(phasesDir);
189
+ const entries = await readdir(phasesDir, { withFileTypes: true });
190
+ for (const entry of entries.filter((e) => e.isFile())) {
191
+ const phasePath = join(phasesDir, entry.name);
192
+ const phaseContent = await readFile(phasePath, 'utf-8');
193
+ // Extract tasks from phase plan
194
+ // GSD phase plans typically have tasks as list items or under "Tasks" section
195
+ const taskMatches = phaseContent.matchAll(/^[\s]*(?:[-*+]|\d+\.)\s+\[?\[?(?:task|Task)?\]?\]?\s*(.+?)(?:\s+\[([^\]]+)\])?$/gm);
196
+ for (const match of taskMatches) {
197
+ const taskTitle = match[1]?.trim() || '';
198
+ const taskOwner = match[2]?.trim() || 'unassigned';
199
+ if (taskTitle.length > 0 && !taskTitle.toLowerCase().includes('optional')) {
200
+ tasks.push({
201
+ id: `task-${String(taskId).padStart(3, '0')}`,
202
+ title: taskTitle,
203
+ ownerRole: taskOwner,
204
+ status: 'pending',
205
+ deps: [],
206
+ allowedPaths: [],
207
+ acceptance: [],
208
+ verify: [],
209
+ commit: null,
210
+ requests: [],
211
+ priority: 5,
212
+ blockedBy: [],
213
+ blocks: [],
214
+ assignedTo: null,
215
+ createdAt: new Date().toISOString(),
216
+ startedAt: null,
217
+ completedAt: null,
218
+ });
219
+ taskId++;
220
+ }
221
+ }
222
+ }
223
+ }
224
+ catch {
225
+ // No phases directory or couldn't read
226
+ }
227
+ return { currentMilestone, tasks };
228
+ }
229
+ /**
230
+ * Create initial STATE.json for FORGE project
231
+ */
232
+ export async function createForgeState(projectName, tasks) {
233
+ const projectState = {
234
+ name: projectName,
235
+ status: 'in_progress',
236
+ currentMilestone: 'v1.0-M1',
237
+ currentPhase: 1,
238
+ updatedAt: new Date().toISOString(),
239
+ };
240
+ return {
241
+ project: projectState,
242
+ tasks,
243
+ contracts: [],
244
+ eventsPointer: 'state/events/',
245
+ };
246
+ }
247
+ /**
248
+ * Main conversion function
249
+ */
250
+ export async function convertGSDToForge(projectPath, options = {}) {
251
+ const result = {
252
+ success: false,
253
+ message: '',
254
+ filesCreated: [],
255
+ warnings: [],
256
+ };
257
+ const log = (msg) => {
258
+ if (options.verbose) {
259
+ console.log(`[convert] ${msg}`);
260
+ }
261
+ };
262
+ // Detect GSD project
263
+ log('Detecting GSD project...');
264
+ const gsdInfo = await detectGSDProject(projectPath);
265
+ if (!gsdInfo.hasProjectMd && !gsdInfo.hasPlanningDir) {
266
+ result.message = 'Not a GSD project: No PROJECT.md or .planning/ directory found.';
267
+ return result;
268
+ }
269
+ log(`Found GSD project: ${gsdInfo.name || projectPath}`);
270
+ log(` - PROJECT.md: ${gsdInfo.hasProjectMd}`);
271
+ log(` - ROADMAP.md: ${gsdInfo.hasRoadmapMd}`);
272
+ log(` - Phases: ${gsdInfo.phases.length}`);
273
+ if (options.dryRun) {
274
+ result.success = true;
275
+ result.message = 'Dry run completed. No files modified.';
276
+ return result;
277
+ }
278
+ // Create FORGE directory structure
279
+ const stateDir = join(projectPath, 'state');
280
+ const eventsDir = join(stateDir, 'events');
281
+ const contractsDir = join(projectPath, 'contracts');
282
+ const claudeRulesDir = join(projectPath, '.claude', 'rules');
283
+ for (const dir of [stateDir, eventsDir, contractsDir, claudeRulesDir]) {
284
+ if (!existsSync(dir)) {
285
+ await mkdir(dir, { recursive: true });
286
+ result.filesCreated.push(dir);
287
+ log(`Created directory: ${dir}`);
288
+ }
289
+ }
290
+ // Generate CLAUDE.md
291
+ log('Generating CLAUDE.md...');
292
+ const claudeMd = await generateClaudeMd(projectPath);
293
+ const claudeMdPath = join(projectPath, 'CLAUDE.md');
294
+ await writeFile(claudeMdPath, claudeMd, 'utf-8');
295
+ result.filesCreated.push(claudeMdPath);
296
+ log(`Created: ${claudeMdPath}`);
297
+ // Extract tasks and create STATE.json
298
+ log('Extracting tasks from phase plans...');
299
+ const { currentMilestone, tasks } = await extractTasksFromPhases(projectPath);
300
+ const projectName = gsdInfo.name || 'Forge Project';
301
+ log(`Extracted ${tasks.length} tasks from ${gsdInfo.phases.length} phase plans`);
302
+ const forgeState = await createForgeState(projectName, tasks);
303
+ const stateJsonPath = join(stateDir, 'STATE.json');
304
+ await writeFile(stateJsonPath, JSON.stringify(forgeState, null, 2), 'utf-8');
305
+ result.filesCreated.push(stateJsonPath);
306
+ log(`Created: ${stateJsonPath}`);
307
+ // Create forge.config.json
308
+ log('Creating forge.config.json...');
309
+ const config = {
310
+ mode: 'interactive',
311
+ depth: 'standard',
312
+ maxTeammates: 5,
313
+ taskLimit: 6,
314
+ conventionalCommits: true,
315
+ worktreeIsolation: true,
316
+ convertedFrom: 'GSD',
317
+ convertedAt: new Date().toISOString(),
318
+ };
319
+ const configPath = join(projectPath, '.planning', 'forge.config.json');
320
+ await mkdir(dirname(configPath), { recursive: true });
321
+ await writeFile(configPath, JSON.stringify(config, null, 2), 'utf-8');
322
+ result.filesCreated.push(configPath);
323
+ log(`Created: ${configPath}`);
324
+ // Warnings
325
+ if (!gsdInfo.hasRoadmapMd) {
326
+ result.warnings.push('No ROADMAP.md found. You may need to create one manually.');
327
+ }
328
+ if (tasks.length === 0) {
329
+ result.warnings.push('No tasks found in phase plans. You may need to run `forge plan <phase>` to create tasks.');
330
+ }
331
+ result.success = true;
332
+ result.message = `Successfully converted GSD project to FORGE. Created ${result.filesCreated.length} files.`;
333
+ return result;
334
+ }
335
+ //# sourceMappingURL=gsd-converter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gsd-converter.js","sourceRoot":"","sources":["../../src/generators/gsd-converter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,212 @@
1
+ # API Design Patterns — {{projectName}}
2
+
3
+ > **Scope:** Backend API development | **Loaded On-Demand**
4
+
5
+ ---
6
+
7
+ ## RESTful Conventions
8
+
9
+ ### URL Structure
10
+ {{#if apiUrlStructure}}
11
+ {{apiUrlStructure}}
12
+ {{else}}
13
+ - Use kebab-case for resource names: `/api/v1/user-profiles`
14
+ - Use plural for collections: `/api/v1/users` (not `/api/v1/user`)
15
+ - Nest resources logically: `/api/v1/users/{userId}/posts`
16
+ {{/if}}
17
+
18
+ ### HTTP Methods
19
+ {{#if httpMethods}}
20
+ {{#each httpMethods}}
21
+ - **{{this.method}}** {{this.usage}}
22
+ {{/each}}
23
+ {{else}}
24
+ - **GET** — Retrieve resources (no side effects)
25
+ - **POST** — Create new resources
26
+ - **PATCH** — Partial updates (preferred over PUT)
27
+ - **PUT** — Full replacement (rarely used)
28
+ - **DELETE** — Resource deletion
29
+ {{/if}}
30
+
31
+ ### Response Format
32
+ {{#if responseFormat}}
33
+ {{responseFormat}}
34
+ {{else}}
35
+ Always return consistent JSON structure:
36
+
37
+ ```json
38
+ {
39
+ "data": { ... },
40
+ "meta": {
41
+ "page": 1,
42
+ "perPage": 20,
43
+ "total": 100
44
+ },
45
+ "errors": null
46
+ }
47
+ ```
48
+ {{/if}}
49
+
50
+ ---
51
+
52
+ ## Error Handling
53
+
54
+ ### Error Response Structure
55
+ ```json
56
+ {
57
+ "error": {
58
+ "code": "VALIDATION_FAILED",
59
+ "message": "User-friendly message",
60
+ "details": [
61
+ {
62
+ "field": "email",
63
+ "message": "Invalid email format"
64
+ }
65
+ ],
66
+ "requestId": "req_abc123"
67
+ }
68
+ }
69
+ ```
70
+
71
+ ### HTTP Status Codes
72
+ {{#if errorCodes}}
73
+ {{#each errorCodes}}
74
+ - **{{this.code}}** — {{this.description}}
75
+ {{/each}}
76
+ {{else}}
77
+ - **200** — Success
78
+ - **201** — Created
79
+ - **204** — No Content
80
+ - **400** — Bad Request (validation errors)
81
+ - **401** — Unauthorized (not logged in)
82
+ - **403** — Forbidden (logged in, no permission)
83
+ - **404** — Not Found
84
+ - **409** — Conflict (duplicate, state mismatch)
85
+ - **422** — Unprocessable Entity
86
+ - **429** — Too Many Requests (rate limit)
87
+ - **500** — Internal Server Error
88
+ - **503** — Service Unavailable
89
+ {{/if}}
90
+
91
+ ### Error Codes Naming
92
+ {{#if errorNaming}}
93
+ Use {{errorNaming}}
94
+ {{else}}
95
+ Use SCREAMING_SNAKE_CASE for error codes:
96
+ - `VALIDATION_FAILED`
97
+ - `AUTHENTICATION_REQUIRED`
98
+ - `RATE_LIMIT_EXCEEDED`
99
+ - `RESOURCE_NOT_FOUND`
100
+ {{/if}}
101
+
102
+ ---
103
+
104
+ ## Authentication & Authorization
105
+
106
+ {{#if authPatterns}}
107
+ {{authPatterns}}
108
+ {{else}}
109
+ ### Authentication
110
+ - Use JWT tokens with httpOnly cookies
111
+ - Include `expiresIn` claim
112
+ - Refresh token endpoint: `POST /api/v1/auth/refresh`
113
+
114
+ ### Authorization
115
+ - Check permissions at route level
116
+ - Use role-based access control (RBAC)
117
+ - Return 403 for permission errors (not 401)
118
+ {{/if}}
119
+
120
+ ---
121
+
122
+ ## Pagination
123
+
124
+ ### Standard Pagination
125
+ {{#if pagination}}
126
+ {{pagination}}
127
+ {{else}}
128
+ Default: page-based pagination
129
+ ```
130
+ GET /api/v1/users?page=1&perPage=20
131
+ ```
132
+
133
+ Response:
134
+ ```json
135
+ {
136
+ "data": [...],
137
+ "meta": {
138
+ "page": 1,
139
+ "perPage": 20,
140
+ "totalPages": 5,
141
+ "total": 100
142
+ }
143
+ }
144
+ ```
145
+ {{/if}}
146
+
147
+ ---
148
+
149
+ ## Rate Limiting
150
+
151
+ {{#if rateLimiting}}
152
+ {{rateLimiting}}
153
+ {{else}}
154
+ - Standard: 100 requests/minute per IP
155
+ - Authenticated: 1000 requests/minute per user
156
+ - Headers returned:
157
+ - `X-RateLimit-Limit`
158
+ - `X-RateLimit-Remaining`
159
+ - `X-RateLimit-Reset`
160
+ {{/if}}
161
+
162
+ ---
163
+
164
+ ## Versioning
165
+
166
+ {{#if apiVersioning}}
167
+ {{apiVersioning}}
168
+ {{else}}
169
+ - URL-based versioning: `/api/v1/`, `/api/v2/`
170
+ - Maintain backward compatibility for at least one major version
171
+ - Document deprecation timeline
172
+ {{/if}}
173
+
174
+ ---
175
+
176
+ ## Validation
177
+
178
+ {{#if validationRules}}
179
+ {{validationRules}}
180
+ {{else}}
181
+ ### Request Validation
182
+ - Validate all inputs at handler boundary
183
+ - Return detailed field-level errors
184
+ - Use Zod or similar schema validation
185
+
186
+ ### Response Validation
187
+ - Validate contracts against OpenAPI schema
188
+ - Type-safe client generation from OpenAPI
189
+ {{/if}}
190
+
191
+ ---
192
+
193
+ ## OpenAPI Contract Requirements
194
+
195
+ {{#if openApiRequirements}}
196
+ {{openApiRequirements}}
197
+ {{else}}
198
+ Every API must have:
199
+ 1. OpenAPI 3.1 spec in `/contracts/`
200
+ 2. All endpoints documented with:
201
+ - Summary and description
202
+ - Request/response schemas
203
+ - Error responses
204
+ - Authentication requirements
205
+ 3. Auto-generated TypeScript types
206
+ 4. Example requests/responses
207
+ {{/if}}
208
+
209
+ ---
210
+
211
+ > **Token Budget:** ~1000 tokens max
212
+ > **Loaded On-Demand** — Only when working on API code