@hustle-together/api-dev-tools 3.12.3 → 3.12.16

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 (96) hide show
  1. package/.claude/commands/hustle-build.md +259 -0
  2. package/.claude/commands/hustle-combine.md +1089 -0
  3. package/.claude/commands/hustle-ui-create-page.md +1078 -0
  4. package/.claude/commands/hustle-ui-create.md +1058 -0
  5. package/.claude/hooks/auto-answer.py +305 -0
  6. package/.claude/hooks/cache-research.py +337 -0
  7. package/.claude/hooks/check-api-routes.py +168 -0
  8. package/.claude/hooks/check-playwright-setup.py +103 -0
  9. package/.claude/hooks/check-storybook-setup.py +81 -0
  10. package/.claude/hooks/check-update.py +132 -0
  11. package/.claude/hooks/completion-promise-detector.py +293 -0
  12. package/.claude/hooks/context-capacity-warning.py +171 -0
  13. package/.claude/hooks/detect-interruption.py +165 -0
  14. package/.claude/hooks/docs-update-check.py +120 -0
  15. package/.claude/hooks/enforce-a11y-audit.py +202 -0
  16. package/.claude/hooks/enforce-brand-guide.py +241 -0
  17. package/.claude/hooks/enforce-component-type-confirm.py +97 -0
  18. package/.claude/hooks/enforce-dry-run.py +134 -0
  19. package/.claude/hooks/enforce-freshness.py +184 -0
  20. package/.claude/hooks/enforce-page-components.py +186 -0
  21. package/.claude/hooks/enforce-page-data-schema.py +155 -0
  22. package/.claude/hooks/enforce-questions-sourced.py +146 -0
  23. package/.claude/hooks/enforce-schema-from-interview.py +248 -0
  24. package/.claude/hooks/enforce-ui-disambiguation.py +108 -0
  25. package/.claude/hooks/enforce-ui-interview.py +130 -0
  26. package/.claude/hooks/generate-adr-options.py +282 -0
  27. package/.claude/hooks/generate-manifest-entry.py +1161 -0
  28. package/.claude/hooks/hook_utils.py +609 -0
  29. package/.claude/hooks/lib/__init__.py +1 -0
  30. package/.claude/hooks/lib/__pycache__/__init__.cpython-314.pyc +0 -0
  31. package/.claude/hooks/lib/__pycache__/greptile.cpython-314.pyc +0 -0
  32. package/.claude/hooks/lib/__pycache__/ntfy.cpython-314.pyc +0 -0
  33. package/.claude/hooks/lib/greptile.py +355 -0
  34. package/.claude/hooks/lib/ntfy.py +209 -0
  35. package/.claude/hooks/notify-input-needed.py +73 -0
  36. package/.claude/hooks/notify-phase-complete.py +90 -0
  37. package/.claude/hooks/ntfy-on-question.py +240 -0
  38. package/.claude/hooks/orchestrator-completion.py +313 -0
  39. package/.claude/hooks/orchestrator-handoff.py +267 -0
  40. package/.claude/hooks/orchestrator-session-startup.py +146 -0
  41. package/.claude/hooks/parallel-orchestrator.py +451 -0
  42. package/.claude/hooks/project-document-prompt.py +302 -0
  43. package/.claude/hooks/remote-question-proxy.py +284 -0
  44. package/.claude/hooks/remote-question-server.py +1224 -0
  45. package/.claude/hooks/run-code-review.py +393 -0
  46. package/.claude/hooks/run-visual-qa.py +338 -0
  47. package/.claude/hooks/session-logger.py +323 -0
  48. package/.claude/hooks/test-orchestrator-reground.py +248 -0
  49. package/.claude/hooks/track-scope-coverage.py +220 -0
  50. package/.claude/hooks/track-token-usage.py +121 -0
  51. package/.claude/hooks/update-adr-decision.py +236 -0
  52. package/.claude/hooks/update-api-showcase.py +161 -0
  53. package/.claude/hooks/update-registry.py +352 -0
  54. package/.claude/hooks/update-testing-checklist.py +195 -0
  55. package/.claude/hooks/update-ui-showcase.py +224 -0
  56. package/.claude/settings.local.json +7 -1
  57. package/.claude/test-auto-answer-bot.py +183 -0
  58. package/.claude/test-completion-detector.py +263 -0
  59. package/.claude/test-orchestrator-state.json +20 -0
  60. package/.claude/test-orchestrator.sh +271 -0
  61. package/.skills/api-create/SKILL.md +88 -3
  62. package/.skills/docs-sync/SKILL.md +260 -0
  63. package/.skills/hustle-build/SKILL.md +459 -0
  64. package/.skills/hustle-build-review/SKILL.md +518 -0
  65. package/CHANGELOG.md +87 -0
  66. package/README.md +86 -9
  67. package/bin/cli.js +1302 -88
  68. package/commands/hustle-api-create.md +22 -0
  69. package/commands/hustle-combine.md +81 -2
  70. package/commands/hustle-ui-create-page.md +84 -2
  71. package/commands/hustle-ui-create.md +82 -2
  72. package/hooks/auto-answer.py +228 -0
  73. package/hooks/check-update.py +132 -0
  74. package/hooks/ntfy-on-question.py +227 -0
  75. package/hooks/orchestrator-completion.py +313 -0
  76. package/hooks/orchestrator-handoff.py +189 -0
  77. package/hooks/orchestrator-session-startup.py +146 -0
  78. package/hooks/periodic-reground.py +230 -67
  79. package/hooks/update-api-showcase.py +13 -1
  80. package/hooks/update-ui-showcase.py +13 -1
  81. package/package.json +7 -3
  82. package/scripts/extract-schema-docs.cjs +322 -0
  83. package/templates/CLAUDE-SECTION.md +89 -64
  84. package/templates/api-showcase/_components/APIModal.tsx +100 -8
  85. package/templates/api-showcase/_components/APIShowcase.tsx +36 -4
  86. package/templates/api-showcase/_components/APITester.tsx +367 -58
  87. package/templates/docs/page.tsx +230 -0
  88. package/templates/hustle-build-defaults.json +84 -0
  89. package/templates/hustle-dev-dashboard/page.tsx +365 -0
  90. package/templates/playwright-report/page.tsx +258 -0
  91. package/templates/settings.json +88 -7
  92. package/templates/test-results/page.tsx +237 -0
  93. package/templates/typedoc.json +19 -0
  94. package/templates/ui-showcase/_components/UIShowcase.tsx +1 -1
  95. package/templates/ui-showcase/page.tsx +1 -1
  96. package/.claude/api-dev-state.json +0 -466
@@ -27,12 +27,15 @@ def copy_showcase_templates(cwd):
27
27
  """Copy API showcase templates to src/app/api-showcase/."""
28
28
  # Source templates (installed by CLI)
29
29
  templates_dir = Path(__file__).parent.parent / "templates" / "api-showcase"
30
+ shared_templates_dir = Path(__file__).parent.parent / "templates" / "shared"
30
31
 
31
32
  # Destination
32
33
  showcase_dir = cwd / "src" / "app" / "api-showcase"
34
+ shared_dir = cwd / "src" / "app" / "shared"
33
35
 
34
- # Create directory if needed
36
+ # Create directories if needed
35
37
  showcase_dir.mkdir(parents=True, exist_ok=True)
38
+ shared_dir.mkdir(parents=True, exist_ok=True)
36
39
 
37
40
  # Copy template files
38
41
  templates_to_copy = [
@@ -55,6 +58,15 @@ def copy_showcase_templates(cwd):
55
58
  shutil.copy2(src_path, dest_path)
56
59
  created_files.append(str(dest_path.relative_to(cwd)))
57
60
 
61
+ # Also copy shared components (HeroHeader, etc.)
62
+ if shared_templates_dir.exists():
63
+ for src_file in shared_templates_dir.iterdir():
64
+ if src_file.is_file():
65
+ dest_path = shared_dir / src_file.name
66
+ if not dest_path.exists():
67
+ shutil.copy2(src_file, dest_path)
68
+ created_files.append(str(dest_path.relative_to(cwd)))
69
+
58
70
  return created_files
59
71
 
60
72
 
@@ -84,12 +84,15 @@ def copy_showcase_templates(cwd):
84
84
  """Copy UI showcase templates to src/app/ui-showcase/."""
85
85
  # Source templates (installed by CLI)
86
86
  templates_dir = Path(__file__).parent.parent / "templates" / "ui-showcase"
87
+ shared_templates_dir = Path(__file__).parent.parent / "templates" / "shared"
87
88
 
88
89
  # Destination
89
90
  showcase_dir = cwd / "src" / "app" / "ui-showcase"
91
+ shared_dir = cwd / "src" / "app" / "shared"
90
92
 
91
- # Create directory if needed
93
+ # Create directories if needed
92
94
  showcase_dir.mkdir(parents=True, exist_ok=True)
95
+ shared_dir.mkdir(parents=True, exist_ok=True)
93
96
 
94
97
  # Copy template files
95
98
  templates_to_copy = [
@@ -111,6 +114,15 @@ def copy_showcase_templates(cwd):
111
114
  shutil.copy2(src_path, dest_path)
112
115
  created_files.append(str(dest_path.relative_to(cwd)))
113
116
 
117
+ # Also copy shared components (HeroHeader, etc.)
118
+ if shared_templates_dir.exists():
119
+ for src_file in shared_templates_dir.iterdir():
120
+ if src_file.is_file():
121
+ dest_path = shared_dir / src_file.name
122
+ if not dest_path.exists():
123
+ shutil.copy2(src_file, dest_path)
124
+ created_files.append(str(dest_path.relative_to(cwd)))
125
+
114
126
  return created_files
115
127
 
116
128
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hustle-together/api-dev-tools",
3
- "version": "3.12.3",
3
+ "version": "3.12.16",
4
4
  "description": "Interview-driven, research-first API development toolkit with 14-phase TDD workflow, enforcement hooks, and 23 Agent Skills for cross-platform AI agents",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {
@@ -23,11 +23,15 @@
23
23
  "test": "node bin/cli.js --scope=project",
24
24
  "usage": "ccusage",
25
25
  "format": "prettier --write .",
26
- "lint": "eslint . --fix"
26
+ "lint": "eslint . --fix",
27
+ "typedoc": "typedoc",
28
+ "typedoc:watch": "typedoc --watch"
27
29
  },
28
30
  "devDependencies": {
29
31
  "prettier": "^3.0.0",
30
- "eslint": "^8.0.0"
32
+ "eslint": "^8.0.0",
33
+ "typedoc": "^0.27.0",
34
+ "typedoc-plugin-markdown": "^4.4.0"
31
35
  },
32
36
  "optionalDependencies": {
33
37
  "ccusage": "^1.0.0"
@@ -0,0 +1,322 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Extract Schema Documentation
4
+ *
5
+ * Parses Zod schema files and extracts parameter documentation
6
+ * for use in the API Showcase registry.
7
+ *
8
+ * Usage:
9
+ * node scripts/extract-schema-docs.cjs <schema-file-path>
10
+ *
11
+ * Output: JSON with parameter documentation
12
+ *
13
+ * Example:
14
+ * node scripts/extract-schema-docs.cjs src/lib/schemas/unsplash.ts
15
+ *
16
+ * Created with Hustle API Dev Tools (v3.12.10)
17
+ */
18
+
19
+ const fs = require('fs');
20
+ const path = require('path');
21
+
22
+ /**
23
+ * Parse Zod schema file and extract documentation
24
+ * Uses regex-based parsing since we can't import TypeScript directly
25
+ */
26
+ function parseZodSchema(filePath) {
27
+ const content = fs.readFileSync(filePath, 'utf-8');
28
+
29
+ const result = {
30
+ file: filePath,
31
+ actions: [],
32
+ schemas: {},
33
+ enums: {},
34
+ constants: {}
35
+ };
36
+
37
+ // Extract action enum values
38
+ const actionMatch = content.match(/ActionSchema\s*=\s*z\.enum\(\[([^\]]+)\]\)/);
39
+ if (actionMatch) {
40
+ result.actions = actionMatch[1]
41
+ .split(',')
42
+ .map(s => s.trim().replace(/['"]/g, ''))
43
+ .filter(Boolean);
44
+ }
45
+
46
+ // Extract all enums
47
+ const enumRegex = /export const (\w+Schema)\s*=\s*z\.enum\(\[([^\]]+)\]\)/g;
48
+ let enumMatch;
49
+ while ((enumMatch = enumRegex.exec(content)) !== null) {
50
+ const name = enumMatch[1].replace('Schema', '');
51
+ const values = enumMatch[2]
52
+ .split(',')
53
+ .map(s => s.trim().replace(/['"]/g, ''))
54
+ .filter(Boolean);
55
+ result.enums[name] = values;
56
+ }
57
+
58
+ // Extract request schemas (z.object definitions)
59
+ const schemaRegex = /export const (\w+RequestSchema)\s*=\s*z\s*\.?\s*object\(\{([^}]+(?:\{[^}]*\}[^}]*)*)\}\)/gs;
60
+ let schemaMatch;
61
+
62
+ while ((schemaMatch = schemaRegex.exec(content)) !== null) {
63
+ const schemaName = schemaMatch[1];
64
+ const schemaBody = schemaMatch[2];
65
+ const params = parseSchemaParams(schemaBody, result.enums);
66
+
67
+ // Get action name from schema name (e.g., SearchRequestSchema -> search)
68
+ const actionName = schemaName
69
+ .replace('RequestSchema', '')
70
+ .replace(/([A-Z])/g, (m, p1, offset) => offset > 0 ? '_' + p1.toLowerCase() : p1.toLowerCase())
71
+ .replace(/^_/, '');
72
+
73
+ result.schemas[actionName] = {
74
+ name: schemaName,
75
+ params: params
76
+ };
77
+ }
78
+
79
+ return result;
80
+ }
81
+
82
+ /**
83
+ * Parse individual parameters from schema body
84
+ */
85
+ function parseSchemaParams(schemaBody, enums) {
86
+ const params = [];
87
+
88
+ // Split by lines and process each field
89
+ const lines = schemaBody.split('\n');
90
+
91
+ for (const line of lines) {
92
+ // Match field definitions like: fieldName: z.string().min(1)...
93
+ const fieldMatch = line.match(/^\s*(\w+)\s*:\s*z\.(.+)/);
94
+ if (!fieldMatch) continue;
95
+
96
+ const [, name, definition] = fieldMatch;
97
+ const param = {
98
+ name,
99
+ type: 'string',
100
+ required: true,
101
+ description: '',
102
+ default: null,
103
+ enum: null
104
+ };
105
+
106
+ // Determine type
107
+ if (definition.includes('string()') || definition.includes('literal(')) {
108
+ param.type = 'string';
109
+ } else if (definition.includes('number()') || definition.includes('coerce.number()')) {
110
+ param.type = 'number';
111
+ } else if (definition.includes('boolean()') || definition.includes('coerce.boolean()')) {
112
+ param.type = 'boolean';
113
+ } else if (definition.includes('array(')) {
114
+ param.type = 'array';
115
+ }
116
+
117
+ // Check if it references an enum
118
+ for (const [enumName, enumValues] of Object.entries(enums)) {
119
+ if (definition.includes(enumName + 'Schema')) {
120
+ param.type = 'enum';
121
+ param.enum = enumValues;
122
+ break;
123
+ }
124
+ }
125
+
126
+ // Check if optional
127
+ if (definition.includes('.optional()')) {
128
+ param.required = false;
129
+ }
130
+
131
+ // Extract default value
132
+ const defaultMatch = definition.match(/\.default\(([^)]+)\)/);
133
+ if (defaultMatch) {
134
+ let defaultVal = defaultMatch[1].trim();
135
+ // Parse the default value
136
+ if (defaultVal === 'true') param.default = true;
137
+ else if (defaultVal === 'false') param.default = false;
138
+ else if (/^\d+$/.test(defaultVal)) param.default = parseInt(defaultVal);
139
+ else param.default = defaultVal.replace(/['"]/g, '');
140
+ param.required = false;
141
+ }
142
+
143
+ // Extract description from validation messages
144
+ const descMatch = definition.match(/['"]([^'"]+is required|[^'"]+too long|[^'"]+invalid)['"]/i);
145
+ if (descMatch) {
146
+ param.description = descMatch[1];
147
+ }
148
+
149
+ // Extract min/max for numbers
150
+ const minMatch = definition.match(/\.min\((\d+)/);
151
+ const maxMatch = definition.match(/\.max\((\d+)/);
152
+ if (minMatch) param.min = parseInt(minMatch[1]);
153
+ if (maxMatch) param.max = parseInt(maxMatch[1]);
154
+
155
+ params.push(param);
156
+ }
157
+
158
+ return params;
159
+ }
160
+
161
+ /**
162
+ * Generate example value for a parameter
163
+ */
164
+ function generateExample(param) {
165
+ if (param.default !== null && param.default !== undefined) {
166
+ return param.default;
167
+ }
168
+
169
+ if (param.enum && param.enum.length > 0) {
170
+ return param.enum[0];
171
+ }
172
+
173
+ // Generate based on param name and type
174
+ const name = param.name.toLowerCase();
175
+
176
+ if (param.type === 'number') {
177
+ if (param.min !== undefined) return param.min;
178
+ if (name.includes('page')) return 1;
179
+ if (name.includes('per_page') || name.includes('count')) return 10;
180
+ return 10;
181
+ }
182
+
183
+ if (param.type === 'boolean') {
184
+ return true;
185
+ }
186
+
187
+ // String examples based on common param names
188
+ if (name === 'query' || name === 'q' || name === 'search') return 'nature sunset';
189
+ if (name.includes('id')) return 'abc123';
190
+ if (name.includes('url')) return 'https://example.com';
191
+ if (name.includes('color')) return 'blue';
192
+ if (name.includes('orientation')) return 'landscape';
193
+ if (name.includes('size')) return 'regular';
194
+
195
+ return 'example';
196
+ }
197
+
198
+ /**
199
+ * Generate working examples for an endpoint
200
+ */
201
+ function generateExamples(action, params, apiId) {
202
+ const examples = {};
203
+ const baseUrl = `http://localhost:3000/api/v2/${apiId}`;
204
+
205
+ // Build query parts from required params
206
+ const buildQuery = (includeOptional = false) => {
207
+ const parts = [`action=${action}`];
208
+ for (const param of params) {
209
+ if (param.name === 'action') continue;
210
+ if (param.required || includeOptional) {
211
+ const val = generateExample(param);
212
+ if (val !== null && val !== undefined) {
213
+ parts.push(`${param.name}=${encodeURIComponent(String(val))}`);
214
+ }
215
+ }
216
+ }
217
+ return parts.join('&');
218
+ };
219
+
220
+ // Basic example with required params only
221
+ const basicQuery = buildQuery(false);
222
+ examples.basic = {
223
+ description: `Basic ${action} request`,
224
+ query: basicQuery,
225
+ curl: `curl -X GET '${baseUrl}?${basicQuery}'`
226
+ };
227
+
228
+ // Full example with all params
229
+ const fullQuery = buildQuery(true);
230
+ if (fullQuery !== basicQuery) {
231
+ examples.full = {
232
+ description: `${action} with all parameters`,
233
+ query: fullQuery,
234
+ curl: `curl -X GET '${baseUrl}?${fullQuery}'`
235
+ };
236
+ }
237
+
238
+ // If there are enums, generate examples for each enum value
239
+ for (const param of params) {
240
+ if (param.enum && param.enum.length > 1) {
241
+ for (const enumVal of param.enum.slice(0, 3)) { // First 3 enum values
242
+ const enumQuery = basicQuery.replace(
243
+ `${param.name}=${encodeURIComponent(String(generateExample(param)))}`,
244
+ `${param.name}=${encodeURIComponent(enumVal)}`
245
+ );
246
+ // Only add if different from basic
247
+ if (enumQuery !== basicQuery) {
248
+ examples[`${param.name}_${enumVal}`] = {
249
+ description: `${action} with ${param.name}=${enumVal}`,
250
+ query: enumQuery,
251
+ curl: `curl -X GET '${baseUrl}?${enumQuery}'`
252
+ };
253
+ }
254
+ }
255
+ }
256
+ }
257
+
258
+ return examples;
259
+ }
260
+
261
+ /**
262
+ * Format output for registry.json
263
+ */
264
+ function formatForRegistry(parsed, apiId = 'api') {
265
+ const endpoints = {};
266
+
267
+ for (const [action, schema] of Object.entries(parsed.schemas)) {
268
+ const params = schema.params.map(p => ({
269
+ name: p.name,
270
+ type: p.type,
271
+ required: p.required,
272
+ description: p.description || `The ${p.name} parameter`,
273
+ default: p.default,
274
+ enum: p.enum,
275
+ min: p.min,
276
+ max: p.max,
277
+ example: String(generateExample(p))
278
+ })).filter(p => p.name !== 'action'); // Filter out the action param itself
279
+
280
+ endpoints[action] = {
281
+ method: 'GET', // Default, could be enhanced
282
+ description: `${action.charAt(0).toUpperCase() + action.slice(1).replace(/_/g, ' ')} action`,
283
+ params: params,
284
+ examples: generateExamples(action, params, apiId)
285
+ };
286
+ }
287
+
288
+ return {
289
+ actions: parsed.actions,
290
+ endpoints: endpoints
291
+ };
292
+ }
293
+
294
+ // Main execution
295
+ if (require.main === module) {
296
+ const args = process.argv.slice(2);
297
+
298
+ if (args.length === 0) {
299
+ console.error('Usage: node extract-schema-docs.cjs <schema-file-path> [api-id]');
300
+ console.error(' api-id: Optional API identifier for generating curl examples (e.g., "unsplash")');
301
+ process.exit(1);
302
+ }
303
+
304
+ const schemaPath = args[0];
305
+ const apiId = args[1] || path.basename(schemaPath, '.ts');
306
+
307
+ if (!fs.existsSync(schemaPath)) {
308
+ console.error(`File not found: ${schemaPath}`);
309
+ process.exit(1);
310
+ }
311
+
312
+ try {
313
+ const parsed = parseZodSchema(schemaPath);
314
+ const formatted = formatForRegistry(parsed, apiId);
315
+ console.log(JSON.stringify(formatted, null, 2));
316
+ } catch (error) {
317
+ console.error('Error parsing schema:', error.message);
318
+ process.exit(1);
319
+ }
320
+ }
321
+
322
+ module.exports = { parseZodSchema, formatForRegistry, generateExample, generateExamples };
@@ -1,21 +1,37 @@
1
- ## Hustle API Development Workflow (v3.7.0)
1
+ ## Hustle API Development Workflow (v4.0.0)
2
2
 
3
- This project uses **@hustle-together/api-dev-tools** for interview-driven, research-first API development.
3
+ This project uses **@hustle-together/api-dev-tools** for interview-driven, research-first development.
4
+
5
+ ### Project Context
6
+
7
+ <!-- INSTALLER: Replace these with actual project values -->
8
+ **Tech Stack:** [Framework] + [Language] + [Database]
9
+ **UI Library:** [UI framework or component library]
10
+ **Testing:** [Test framework] + [E2E framework]
11
+
12
+ ### Existing Elements
13
+
14
+ <!-- AUTO-POPULATED: Updated by registry hooks -->
15
+ **APIs:** (check `.claude/registry.json`)
16
+ **Components:** (check `.claude/registry.json`)
17
+ **Pages:** (check `.claude/registry.json`)
4
18
 
5
19
  ### Available Commands
6
20
 
7
21
  | Command | Purpose |
8
22
  | ---------------------------------- | ------------------------------------- |
9
- | `/hustle-api-create [endpoint]` | Complete 13-phase workflow |
10
- | `/hustle-api-interview [endpoint]` | Questions FROM research findings |
11
- | `/hustle-api-research [library]` | Adaptive propose-approve research |
12
- | `/hustle-api-verify [endpoint]` | Re-research and verify implementation |
13
- | `/hustle-api-env [endpoint]` | Check API keys |
14
- | `/hustle-api-status [endpoint]` | Track progress |
15
- | `/hustle-api-continue [endpoint]` | Resume interrupted workflow |
16
- | `/hustle-api-sessions` | Browse saved session logs |
17
-
18
- ### 13-Phase Flow
23
+ | `/hustle-build [description]` | Orchestrated multi-workflow build |
24
+ | `/api-create [endpoint]` | Complete 14-phase API workflow |
25
+ | `/hustle-ui-create [component]` | Component with Storybook |
26
+ | `/hustle-ui-create-page [page]` | Page with Playwright E2E |
27
+ | `/hustle-combine [name]` | Combine multiple APIs |
28
+ | `/api-research [library]` | Adaptive propose-approve research |
29
+ | `/api-interview [endpoint]` | Questions FROM research findings |
30
+ | `/api-verify [endpoint]` | Re-research and verify implementation |
31
+ | `/api-env [endpoint]` | Check API keys |
32
+ | `/api-status [endpoint]` | Track progress |
33
+
34
+ ### 14-Phase Flow
19
35
 
20
36
  ```
21
37
  Phase 1: DISAMBIGUATION - Clarify ambiguous terms before research
@@ -28,18 +44,20 @@ Phase 7: ENVIRONMENT - Verify API keys exist
28
44
  Phase 8: TDD RED - Write failing tests from schema
29
45
  Phase 9: TDD GREEN - Minimal implementation to pass tests
30
46
  Phase 10: VERIFY - Re-research docs, compare to implementation
31
- Phase 11: TDD REFACTOR - Clean up code while tests pass
32
- Phase 12: DOCUMENTATION - Update manifests, cache research
33
- Phase 13: COMPLETION - Final verification, commit
47
+ Phase 11: CODE REVIEW - AI review (bugs, security, performance)
48
+ Phase 12: TDD REFACTOR - Fix review issues + clean up code
49
+ Phase 13: DOCUMENTATION - Update manifests, cache research
50
+ Phase 14: COMPLETION - Final verification, commit
34
51
  ```
35
52
 
36
53
  ### Key Principles
37
54
 
38
- 1. **Loop Until Green** - Every verification phase loops back if not successful
55
+ 1. **Research-First** - Never write code from memory, always verify docs
39
56
  2. **Questions FROM Research** - Never use generic template questions
40
- 3. **Adaptive Research** - Propose searches based on context, not shotgun
57
+ 3. **Loop Until Green** - Every verification phase loops back if not successful
41
58
  4. **7-Turn Re-grounding** - Context injected every 7 turns to prevent dilution
42
59
  5. **Verify After Green** - Re-research to catch memory-based implementation errors
60
+ 6. **Registry Awareness** - Don't recreate existing elements
43
61
 
44
62
  ### State Tracking
45
63
 
@@ -49,7 +67,17 @@ All progress is tracked in `.claude/api-dev-state.json`:
49
67
  - Interview decisions (injected during implementation)
50
68
  - Research sources with freshness tracking
51
69
  - Turn count for re-grounding
52
- - Multi-API support with active endpoint pointer
70
+ - Deferred features list
71
+ - Test run history
72
+
73
+ ### Registry
74
+
75
+ `.claude/registry.json` tracks all created elements:
76
+
77
+ - APIs with endpoints, schemas, and examples
78
+ - Components with props and variants
79
+ - Pages with routes and data requirements
80
+ - Combined APIs with orchestration patterns
53
81
 
54
82
  ### Research Cache
55
83
 
@@ -59,61 +87,58 @@ Research is cached in `.claude/research/` with 7-day freshness:
59
87
  - `[api-name]/CURRENT.md` - Latest research
60
88
  - `[api-name]/sources.json` - Research sources
61
89
  - `[api-name]/interview.json` - Interview decisions
62
- - `[api-name]/schema.json` - Schema snapshot
63
90
  - Stale research (>7 days) triggers re-research prompt
64
91
 
65
- ### Hooks (25 Total - Automatic Enforcement)
66
-
67
- | Hook | Event | Action |
68
- | ---------------------------------- | ---------------- | ------------------------------------ |
69
- | `session-startup.py` | SessionStart | Inject state context |
70
- | `detect-interruption.py` | SessionStart | Detect interrupted workflows |
71
- | `enforce-external-research.py` | UserPromptSubmit | Require research first |
72
- | `enforce-disambiguation.py` | PreToolUse | Phase 1 enforcement |
73
- | `enforce-scope.py` | PreToolUse | Phase 2 enforcement |
74
- | `enforce-research.py` | PreToolUse | Phase 3 enforcement |
75
- | `enforce-interview.py` | PreToolUse | Phase 4 - inject decisions |
76
- | `enforce-deep-research.py` | PreToolUse | Phase 5 enforcement |
77
- | `enforce-schema.py` | PreToolUse | Phase 6 enforcement |
78
- | `enforce-environment.py` | PreToolUse | Phase 7 enforcement |
79
- | `enforce-tdd-red.py` | PreToolUse | Phase 8 enforcement |
80
- | `verify-implementation.py` | PreToolUse | Phase 9 helper |
81
- | `enforce-verify.py` | PreToolUse | Phase 10 enforcement |
82
- | `enforce-refactor.py` | PreToolUse | Phase 11 enforcement |
83
- | `enforce-documentation.py` | PreToolUse | Phase 12 enforcement |
84
- | `enforce-questions-sourced.py` | PreToolUse | Validate questions from research |
85
- | `enforce-schema-from-interview.py` | PreToolUse | Validate schema from interview |
86
- | `track-tool-use.py` | PostToolUse | Log research, count turns |
87
- | `periodic-reground.py` | PostToolUse | Re-inject context every 7 turns |
88
- | `track-scope-coverage.py` | PostToolUse | Track implemented vs deferred |
89
- | `verify-after-green.py` | PostToolUse | Trigger Phase 10 after tests pass |
90
- | `cache-research.py` | PostToolUse | Create research cache files |
91
- | `generate-manifest-entry.py` | PostToolUse | Auto-generate API documentation |
92
- | `api-workflow-check.py` | Stop | Block if incomplete, generate output |
93
- | `session-logger.py` | Stop | Save session to api-sessions |
94
-
95
- ### Auto-Generated Documentation
96
-
97
- When Phase 12 completes, `generate-manifest-entry.py` automatically creates:
98
-
99
- - **Comprehensive curl examples** (minimal, full, auth, enum variations, boundary values)
100
- - **Complete test cases** (success, validation, required fields, types, boundaries, arrays)
101
- - **Parameter documentation** with all possible values
102
- - **Ready-to-use entries** for `api-tests-manifest.json`
92
+ ### Re-grounding System
93
+
94
+ Every 7 turns, the system injects a reminder with:
95
+
96
+ - Current endpoint and phase progress
97
+ - Key interview decisions
98
+ - Existing registry elements (don't recreate)
99
+ - Deferred features (don't re-suggest)
100
+ - Last test status (GREEN/RED)
101
+ - Brand guide status
102
+ - Research freshness warnings
103
+ - Orchestrator progress (if in /hustle-build)
104
+
105
+ See: [docs/REGROUNDING.md](./docs/REGROUNDING.md)
106
+
107
+ ### Brand Guide
108
+
109
+ If `.claude/BRAND_GUIDE.md` exists:
110
+
111
+ - All UI components use brand colors/fonts
112
+ - Enforce hook checks before component creation
113
+ - Re-grounding reminds about brand guide
114
+
115
+ ### Hooks (45+ Automatic Enforcement)
116
+
117
+ | Category | Hooks | Purpose |
118
+ | -------- | ----- | ------- |
119
+ | SessionStart | 4 | Inject state, detect interruptions, check updates |
120
+ | UserPromptSubmit | 1 | Require research before API questions |
121
+ | PreToolUse | 22 | Phase enforcement, schema validation |
122
+ | PostToolUse | 12 | Tracking, re-grounding, registry updates |
123
+ | Stop | 2 | Workflow completion, session logging |
103
124
 
104
125
  ### Usage
105
126
 
106
127
  ```bash
107
- # Full automated workflow
108
- /hustle-api-create my-endpoint
128
+ # Orchestrated build (recommended for features)
129
+ /hustle-build dashboard with user stats and activity charts
109
130
 
110
- # Manual step-by-step
111
- /hustle-api-research [library]
112
- /hustle-api-interview [endpoint]
113
- /hustle-api-env [endpoint]
131
+ # Individual workflows
132
+ /api-create stripe-checkout
133
+ /hustle-ui-create StatCard
134
+ /hustle-ui-create-page Dashboard
135
+
136
+ # TDD cycle
114
137
  /red
115
138
  /green
116
- /hustle-api-verify [endpoint]
117
139
  /refactor
140
+
141
+ # Git
118
142
  /commit
143
+ /pr
119
144
  ```