Skip to content

Interview-driven API development workflow for Claude Code - Automates research, testing, and documentation

License

Notifications You must be signed in to change notification settings

hustle-together/api-dev-tools

Repository files navigation

API Development Tools for Claude Code v3.6.0

Interview-driven, research-first API development with 100% phase enforcement

┌────────────────────────────────────────────────────────────────┐
│ ❯ npx @hustle-together/api-dev-tools --scope=project           │
│                                                                │
│ 🚀 Installing API Development Tools v3.6.0...                  │
│                                                                │
│ ✅ Found Python 3.12.0                                         │
│ 📦 Installing commands: 24 slash commands                      │
│ 🔒 Installing hooks: 18 enforcement hooks                      │
│ ⚙️  Configuring settings.json                                  │
│ 📊 Creating api-dev-state.json                                 │
│ 📚 Setting up research cache                                   │
│ 🔌 Configuring MCP servers: context7, github                   │
│                                                                │
│ ═══════════════════════════════════════════════════════════    │
│ 🎉 API Development Tools installed successfully!               │
│ ═══════════════════════════════════════════════════════════    │
│                                                                │
│ Quick Start: /api-create my-endpoint                           │
└────────────────────────────────────────────────────────────────┘

What Problem Does This Solve?

LLMs have predictable failure modes when building APIs:

  1. Wrong Documentation - Uses training data instead of current docs
  2. Memory-Based Implementation - Forgets research by implementation time
  3. Self-Answering Questions - Asks itself questions instead of the user
  4. Context Dilution - Loses focus in long sessions
  5. Skipped Steps - Jumps to implementation without proper research

This package enforces a 12-phase workflow with Python hooks that BLOCK progress until each phase is complete with explicit user approval.


Complete Workflow Simulation

Here's exactly what happens when you run /api-create brandfetch:

┌──────────────────────────────────────────────────────────────────────────────┐
│  ❯ /api-create brandfetch                                                    │
│                                                                              │
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 0: DISAMBIGUATION                                                 │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ I found multiple things matching "brandfetch":                          │ │
│  │                                                                         │ │
│  │   [A] Brandfetch REST API (api.brandfetch.io)                          │ │
│  │   [B] @brandfetch/sdk npm package                                       │ │
│  │   [C] Brandfetch WordPress plugin                                       │ │
│  │                                                                         │ │
│  │ Which interpretation matches your intent?                               │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-disambiguation.py                               │ │
│  │    ├─ Blocks Write/Edit until user selects an option                   │ │
│  │    ├─ Requires: user_question_asked = true                             │ │
│  │    └─ Requires: phase_exit_confirmed = true (user said "yes")          │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User selects: [A] Brandfetch REST API                                       │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 1: SCOPE CONFIRMATION                                             │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ I'll create: /api/v2/brandfetch                                        │ │
│  │                                                                         │ │
│  │ Purpose: Fetch brand assets (logos, colors, fonts) from Brandfetch API │ │
│  │                                                                         │ │
│  │ Is this scope correct? [Yes / No, I need...]                           │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-scope.py                                        │ │
│  │    ├─ Blocks until user confirms scope                                 │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, but also add a logo-only mode"                                  │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 2: INITIAL RESEARCH                                               │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ 🔍 Searching...                                                         │ │
│  │                                                                         │ │
│  │ [Context7] brandfetch → Found SDK documentation                        │ │
│  │ [WebSearch] "Brandfetch API documentation 2025" → Official docs        │ │
│  │ [WebSearch] "Brandfetch API rate limits" → 5 req/sec                   │ │
│  │                                                                         │ │
│  │ ────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ RESEARCH SUMMARY:                                                       │ │
│  │ • Base URL: https://api.brandfetch.io/v2                               │ │
│  │ • Auth: Bearer token (BRANDFETCH_API_KEY)                              │ │
│  │ • Rate limit: 5 requests/second                                        │ │
│  │ • Returns: logos, colors, fonts, images                                │ │
│  │                                                                         │ │
│  │ Proceed to interview? [Yes / Search more first]                        │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-research.py                                     │ │
│  │    ├─ Blocks Write/Edit until research complete                        │ │
│  │    ├─ Requires: sources.length >= 2                                    │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 📝 TRACKED BY: track-tool-use.py                                        │ │
│  │    └─ Logs all WebSearch/Context7 calls to state                       │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, proceed"                                                        │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 3: STRUCTURED INTERVIEW                                           │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ Based on research, I have 5 questions:                                  │ │
│  │                                                                         │ │
│  │ Q1: Which response format do you need?                                  │ │
│  │     [ ] JSON only                                                       │ │
│  │     [x] JSON with asset URLs                                            │ │
│  │     [ ] Include raw base64 assets                                       │ │
│  │                                                                         │ │
│  │ Q2: Caching strategy?                                                   │ │
│  │     [ ] No caching                                                      │ │
│  │     [ ] Short (5 minutes)                                               │ │
│  │     [x] Long (24 hours) - brand data rarely changes                     │ │
│  │                                                                         │ │
│  │ Q3: Error handling approach?                                            │ │
│  │     [ ] Throw errors (caller handles)                                   │ │
│  │     [x] Return error objects { success: false, error: {...} }          │ │
│  │                                                                         │ │
│  │ Q4: Rate limit handling?                                                │ │
│  │     [ ] Client handles retry                                            │ │
│  │     [ ] Server-side retry with backoff                                  │ │
│  │     [x] Expose rate limit headers (X-RateLimit-*)                       │ │
│  │                                                                         │ │
│  │ Q5: Which brand assets to include?                                      │ │
│  │     [x] Logos                                                           │ │
│  │     [x] Colors                                                          │ │
│  │     [ ] Fonts                                                           │ │
│  │     [ ] Images                                                          │ │
│  │                                                                         │ │
│  │ Interview complete? [Yes, these answers are final / Modify answers]    │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-interview.py                                    │ │
│  │    ├─ Blocks until structured_question_count >= 3                      │ │
│  │    ├─ Uses AskUserQuestion tool (Claude's built-in dialog)             │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Generate questions FROM research (not generic templates)         │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User confirms selections                                                    │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 4: DEEP RESEARCH (Adaptive)                                       │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ Based on your selections, I want to research:                           │ │
│  │                                                                         │ │
│  │ [x] "Brandfetch error response format" - for error objects             │ │
│  │ [x] "Brandfetch rate limit headers" - for X-RateLimit-* headers        │ │
│  │ [ ] "Brandfetch font API" - SKIPPED (you don't need fonts)             │ │
│  │                                                                         │ │
│  │ Approve these searches? [Yes / Add more / Skip all]                    │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-deep-research.py                                │ │
│  │    ├─ Blocks if approved_searches not executed                         │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Propose searches based on interview (not shotgun approach)       │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, also add authentication methods"                                │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 5: SCHEMA CREATION                                                │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ Creating Zod schema from research + interview:                          │ │
│  │                                                                         │ │
│  │ // Request Schema                                                       │ │
│  │ const BrandfetchRequest = z.object({                                   │ │
│  │   domain: z.string().min(1),                                           │ │
│  │   mode: z.enum(["full", "logo-only"]).default("full"),                 │ │
│  │   include: z.object({                                                  │ │
│  │     logos: z.boolean().default(true),                                  │ │
│  │     colors: z.boolean().default(true),                                 │ │
│  │   }).optional(),                                                       │ │
│  │ });                                                                    │ │
│  │                                                                         │ │
│  │ // Response Schema (success)                                            │ │
│  │ const BrandfetchResponse = z.object({                                  │ │
│  │   success: z.literal(true),                                            │ │
│  │   data: z.object({                                                     │ │
│  │     logos: z.array(LogoSchema),                                        │ │
│  │     colors: z.array(ColorSchema),                                      │ │
│  │   }),                                                                  │ │
│  │   cached: z.boolean(),                                                 │ │
│  │ });                                                                    │ │
│  │                                                                         │ │
│  │ Schema matches your interview answers? [Yes / Modify]                  │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-schema.py                                       │ │
│  │    ├─ Blocks if schema not shown to user                               │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, looks good"                                                     │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 6: ENVIRONMENT CHECK                                              │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ Checking required API keys:                                             │ │
│  │                                                                         │ │
│  │   ✅ BRANDFETCH_API_KEY          found in .env                         │ │
│  │   ✅ NODE_ENV                     = development                         │ │
│  │                                                                         │ │
│  │ Ready to begin TDD? [Yes / Need to set up keys first]                  │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-environment.py                                  │ │
│  │    ├─ Checks env vars based on endpoint name + interview               │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, ready"                                                          │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 7: TDD RED (Write Failing Tests)                                  │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ TEST MATRIX (from interview decisions):                                 │ │
│  │                                                                         │ │
│  │ ✅ Success Scenarios:                                                   │ │
│  │    • GET with valid domain → 200 + brand data                          │ │
│  │    • mode=logo-only → 200 + logos only                                 │ │
│  │    • Cache hit → 200 + cached: true                                    │ │
│  │                                                                         │ │
│  │ ✅ Error Scenarios (your choice: return objects):                       │ │
│  │    • Invalid domain → 400 + { success: false, error: {...} }           │ │
│  │    • Missing API key → 401 + error object                              │ │
│  │    • Not found → 404 + error object                                    │ │
│  │    • Rate limited → 429 + X-RateLimit-* headers                        │ │
│  │                                                                         │ │
│  │ ✅ Edge Cases:                                                          │ │
│  │    • Empty colors array → 200 + empty array (not error)                │ │
│  │    • Timeout → 504 + error object                                      │ │
│  │                                                                         │ │
│  │ Total: 9 test scenarios                                                 │ │
│  │                                                                         │ │
│  │ Test plan looks good? [Yes, write tests / Add more tests]              │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-tdd-red.py                                      │ │
│  │    ├─ Blocks route.ts if no .test.ts exists                            │ │
│  │    ├─ Requires: test matrix shown to user                              │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Derive test scenarios from interview decisions                   │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, write them"                                                     │
│                                                                              │
│  📝 Creating: src/app/api/v2/brandfetch/__tests__/route.test.ts            │
│  ⏳ Running tests... 0/9 passing (expected - RED phase)                     │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 8: TDD GREEN (Make Tests Pass)                                    │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ 📝 Creating: src/app/api/v2/brandfetch/route.ts                        │ │
│  │                                                                         │ │
│  │ ⏳ Running tests...                                                     │ │
│  │                                                                         │ │
│  │ ✅ GET with valid domain                    PASS                        │ │
│  │ ✅ mode=logo-only                           PASS                        │ │
│  │ ✅ Cache hit                                PASS                        │ │
│  │ ✅ Invalid domain → 400                     PASS                        │ │
│  │ ✅ Missing API key → 401                    PASS                        │ │
│  │ ✅ Not found → 404                          PASS                        │ │
│  │ ✅ Rate limited → 429                       PASS                        │ │
│  │ ✅ Empty colors array                       PASS                        │ │
│  │ ✅ Timeout → 504                            PASS                        │ │
│  │                                                                         │ │
│  │ Tests: 9/9 passing                                                      │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: verify-after-green.py (PostToolUse on Bash)             │ │
│  │    ├─ Detects "pnpm test" or "vitest" in command                       │ │
│  │    ├─ Parses output for pass/fail                                      │ │
│  │    └─ Auto-triggers Phase 9 when all tests pass                        │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Write minimal implementation to pass tests                       │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 9: VERIFY (Re-Research After Green)                               │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ ⚠️  AUTO-TRIGGERED: Tests passed. Now verifying against docs...         │ │
│  │                                                                         │ │
│  │ Re-reading Brandfetch API documentation...                              │ │
│  │                                                                         │ │
│  │ ┌────────────────────────────────────────────────────────────────────┐  │ │
│  │ │ Feature        │ In Docs │ Implemented │ Status                   │  │ │
│  │ ├────────────────┼─────────┼─────────────┼──────────────────────────│  │ │
│  │ │ domain param   │ ✓       │ ✓           │ ✅ Match                 │  │ │
│  │ │ logo formats   │ 4       │ 4           │ ✅ Match                 │  │ │
│  │ │ colors         │ ✓       │ ✓           │ ✅ Match                 │  │ │
│  │ │ include_fonts  │ ✓       │ ✗           │ ⚠️  GAP FOUND            │  │ │
│  │ │ webhook        │ ✓       │ ✗           │ ℹ️  Optional             │  │ │
│  │ └────────────────────────────────────────────────────────────────────┘  │ │
│  │                                                                         │ │
│  │ GAPS FOUND: 1                                                           │ │
│  │   • include_fonts parameter (documented but not implemented)            │ │
│  │                                                                         │ │
│  │ Fix gaps? [Yes, loop back to Phase 7 / Skip - document as omission]    │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-verify.py                                       │ │
│  │    ├─ Blocks refactoring until verification complete                   │ │
│  │    ├─ Requires: gaps_fixed OR documented as omissions                  │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Re-read docs and compare feature-by-feature                      │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Skip - I don't need fonts"                                           │
│                                                                              │
│  📝 Documenting as intentional omission: include_fonts                      │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 10: TDD REFACTOR                                                  │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ Cleaning up implementation while keeping tests green...                 │ │
│  │                                                                         │ │
│  │ • Extracted rate limit logic to helper function                         │ │
│  │ • Added JSDoc comments                                                  │ │
│  │ • Removed dead code                                                     │ │
│  │                                                                         │ │
│  │ Tests: 9/9 still passing                                                │ │
│  │                                                                         │ │
│  │ Refactoring complete? [Yes / Continue refactoring]                     │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-refactor.py                                     │ │
│  │    ├─ Only allows after verify phase complete                          │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 💡 LLM RESPONSIBILITY:                                                  │ │
│  │    └─ Improve code without changing behavior                           │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes"                                                                 │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ PHASE 11: DOCUMENTATION                                                 │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ DOCUMENTATION CHECKLIST:                                                │ │
│  │                                                                         │ │
│  │ ✅ api-tests-manifest.json                                              │ │
│  │    • Added /api/v2/brandfetch entry                                    │ │
│  │    • 9 test scenarios documented                                        │ │
│  │    • Request/response schemas included                                  │ │
│  │                                                                         │ │
│  │ ✅ Research Cache                                                       │ │
│  │    • .claude/research/brandfetch/sources.json                          │ │
│  │    • .claude/research/brandfetch/interview.json                        │ │
│  │                                                                         │ │
│  │ ⏭️  OpenAPI Spec (skipped - internal API)                               │ │
│  │                                                                         │ │
│  │ Documentation complete? [Yes / Need to add something]                  │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
│  ┌─────────────────────────────────────────────────────────────────────────┐ │
│  │ 🔒 ENFORCED BY: enforce-documentation.py                                │ │
│  │    ├─ Blocks completion until documentation updated                    │ │
│  │    ├─ Checks: manifest_updated OR research_cached                      │ │
│  │    └─ Requires: phase_exit_confirmed = true                            │ │
│  │                                                                         │ │
│  │ 🔒 ENFORCED BY: api-workflow-check.py (Stop hook)                       │ │
│  │    └─ Blocks "stop" if required phases not complete                    │ │
│  └─────────────────────────────────────────────────────────────────────────┘ │
│                                                                              │
│  User: "Yes, all done"                                                       │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────────────────────────────┐
│  ╭─────────────────────────────────────────────────────────────────────────╮ │
│  │ ✅ WORKFLOW COMPLETE                                                    │ │
│  │ ─────────────────────────────────────────────────────────────────────── │ │
│  │                                                                         │ │
│  │ /api/v2/brandfetch created successfully!                               │ │
│  │                                                                         │ │
│  │ Files created:                                                          │ │
│  │   • src/app/api/v2/brandfetch/route.ts                                 │ │
│  │   • src/app/api/v2/brandfetch/__tests__/route.test.ts                  │ │
│  │   • src/lib/schemas/brandfetch.ts                                      │ │
│  │                                                                         │ │
│  │ Tests: 9/9 passing                                                      │ │
│  │ Coverage: 100%                                                          │ │
│  │                                                                         │ │
│  │ Interview decisions preserved in:                                       │ │
│  │   • .claude/api-dev-state.json                                         │ │
│  │   • .claude/research/brandfetch/                                       │ │
│  │                                                                         │ │
│  │ Intentional omissions documented:                                       │ │
│  │   • include_fonts parameter                                            │ │
│  │   • webhook support                                                     │ │
│  ╰─────────────────────────────────────────────────────────────────────────╯ │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘

Enforcement vs LLM Responsibility

🔒 ENFORCED (Hooks block progress if not complete)

Phase Hook File What It Enforces
0 enforce-disambiguation.py User must select from options
1 enforce-scope.py User must confirm scope
2 enforce-research.py Minimum 2 sources required
3 enforce-interview.py Minimum 3 structured questions
4 enforce-deep-research.py Approved searches must execute
5 enforce-schema.py Schema must be shown to user
6 enforce-environment.py API keys must be verified
7 enforce-tdd-red.py Test file must exist before route
8 verify-after-green.py Tests must pass (auto-detect)
9 enforce-verify.py Gaps must be fixed or documented
10 enforce-refactor.py Verify phase must be complete
11 enforce-documentation.py Docs must be updated

💡 LLM RESPONSIBILITY (Not enforced, but guided)

Task Guidance
Generate disambiguation options Based on search results
Create interview questions FROM research findings
Propose deep research searches Based on interview answers
Write test scenarios Derived from interview decisions
Compare docs to implementation Feature-by-feature comparison
Refactor code Without changing behavior

🔄 AUTOMATIC (No user action required)

Hook Trigger Action
session-startup.py Session start Inject state context
track-tool-use.py Any tool use Log activity, count turns
periodic-reground.py Every 7 turns Re-inject context summary
verify-after-green.py Tests pass Trigger Phase 9

File Structure

@hustle-together/api-dev-tools v3.6.0
│
├── bin/
│   └── cli.js                         # NPX installer (verifies 18 hooks)
│
├── commands/                          # 24 slash commands
│   ├── api-create.md                  # Main 12-phase workflow
│   ├── api-interview.md               # Structured interview
│   ├── api-research.md                # Adaptive research
│   ├── api-verify.md                  # Manual verification
│   ├── api-env.md                     # Environment check
│   ├── api-status.md                  # Progress tracking
│   ├── red.md, green.md, refactor.md  # TDD commands
│   ├── cycle.md                       # Full TDD cycle
│   ├── commit.md, pr.md               # Git operations
│   └── ... (13 more)
│
├── hooks/                             # 18 Python enforcement hooks
│   │
│   │ # Session lifecycle
│   ├── session-startup.py             # SessionStart → inject context
│   │
│   │ # User prompt processing
│   ├── enforce-external-research.py   # UserPromptSubmit → detect API terms
│   │
│   │ # PreToolUse (Write/Edit) - BLOCKING
│   ├── enforce-disambiguation.py      # Phase 0
│   ├── enforce-scope.py               # Phase 1
│   ├── enforce-research.py            # Phase 2
│   ├── enforce-interview.py           # Phase 3
│   ├── enforce-deep-research.py       # Phase 4
│   ├── enforce-schema.py              # Phase 5
│   ├── enforce-environment.py         # Phase 6
│   ├── enforce-tdd-red.py             # Phase 7
│   ├── verify-implementation.py       # Phase 8 helper
│   ├── enforce-verify.py              # Phase 9
│   ├── enforce-refactor.py            # Phase 10
│   ├── enforce-documentation.py       # Phase 11
│   │
│   │ # PostToolUse - TRACKING
│   ├── track-tool-use.py              # Log all tool usage
│   ├── periodic-reground.py           # Re-inject context every 7 turns
│   ├── verify-after-green.py          # Trigger Phase 9 after tests pass
│   │
│   │ # Stop - BLOCKING
│   └── api-workflow-check.py          # Block completion if incomplete
│
├── templates/
│   ├── api-dev-state.json             # State file (12 phases + phase_exit_confirmed)
│   ├── settings.json                  # Hook registrations
│   ├── research-index.json            # Research freshness tracking
│   └── CLAUDE-SECTION.md              # CLAUDE.md injection
│
├── scripts/
│   ├── generate-test-manifest.ts      # Parse tests → manifest (NO LLM)
│   ├── extract-parameters.ts          # Extract Zod params
│   └── collect-test-results.ts        # Run tests → results
│
└── package.json                       # v3.6.0

State File Structure (v3.6.0)

{
  "version": "3.0.0",
  "endpoint": "brandfetch",
  "session_id": "abc123",
  "turn_count": 47,
  "phases": {
    "disambiguation": {
      "status": "complete",
      "user_question_asked": true,
      "user_selected": "Brandfetch REST API",
      "phase_exit_confirmed": true,
      "last_question_type": "exit_confirmation"
    },
    "scope": {
      "status": "complete",
      "confirmed": true,
      "phase_exit_confirmed": true
    },
    "research_initial": {
      "status": "complete",
      "sources": ["context7", "websearch:brandfetch-api", "websearch:rate-limits"],
      "phase_exit_confirmed": true
    },
    "interview": {
      "status": "complete",
      "structured_question_count": 5,
      "decisions": {
        "response_format": "json_with_urls",
        "caching": "24h",
        "error_handling": "return_objects",
        "rate_limiting": "expose_headers",
        "assets": ["logos", "colors"]
      },
      "phase_exit_confirmed": true
    },
    "research_deep": {
      "status": "complete",
      "proposed_searches": ["error-format", "rate-headers", "auth"],
      "approved_searches": ["error-format", "rate-headers", "auth"],
      "executed_searches": ["error-format", "rate-headers", "auth"],
      "phase_exit_confirmed": true
    },
    "schema_creation": {
      "status": "complete",
      "schema_file": "src/lib/schemas/brandfetch.ts",
      "phase_exit_confirmed": true
    },
    "environment_check": {
      "status": "complete",
      "keys_found": ["BRANDFETCH_API_KEY"],
      "phase_exit_confirmed": true
    },
    "tdd_red": {
      "status": "complete",
      "test_file": "src/app/api/v2/brandfetch/__tests__/route.test.ts",
      "test_count": 9,
      "phase_exit_confirmed": true
    },
    "tdd_green": {
      "status": "complete",
      "all_tests_passing": true
    },
    "verify": {
      "status": "complete",
      "gaps_found": 2,
      "gaps_fixed": 0,
      "intentional_omissions": ["include_fonts", "webhook"],
      "phase_exit_confirmed": true
    },
    "tdd_refactor": {
      "status": "complete",
      "phase_exit_confirmed": true
    },
    "documentation": {
      "status": "complete",
      "manifest_updated": true,
      "research_cached": true,
      "phase_exit_confirmed": true
    }
  },
  "reground_history": [
    { "turn": 7, "phase": "interview" },
    { "turn": 14, "phase": "tdd_red" },
    { "turn": 21, "phase": "tdd_green" }
  ]
}

Installation

# Install in your project
npx @hustle-together/api-dev-tools --scope=project

# Team-wide auto-installation (add to package.json)
{
  "scripts": {
    "postinstall": "npx @hustle-together/api-dev-tools --scope=project"
  }
}

Requirements

  • Node.js 14.0.0+
  • Python 3 (for enforcement hooks)
  • Claude Code CLI tool

What's New in v3.6.0

Exit Code 2 for Stronger Enforcement

Problem: JSON permissionDecision: "deny" blocks actions but Claude may continue normally. We needed a way to force Claude to actively respond to the error.

Solution: All blocking hooks now use sys.exit(2) with stderr messages instead of JSON deny:

# Before (passive - Claude sees reason but may continue)
print(json.dumps({"permissionDecision": "deny", "reason": "..."}))
sys.exit(0)

# After (active - forces Claude into feedback loop)
print("BLOCKED: ...", file=sys.stderr)
sys.exit(2)

Upgraded hooks:

  • enforce-research.py - Forces /api-research before implementation
  • enforce-interview.py - Forces structured interview completion
  • api-workflow-check.py - Forces all phases complete before stopping
  • verify-implementation.py - Forces fix of critical mismatches

From Anthropic's docs:

"Exit code 2 creates a feedback loop directly to Claude. Claude sees your error message. Claude adjusts. Claude tries something different."


What's New in v3.5.0

phase_exit_confirmed Enforcement

Problem: Claude was calling AskUserQuestion but immediately self-answering without waiting for user input.

Solution: Every phase now requires:

  1. An "exit confirmation" question (detected by patterns like "proceed", "ready", "confirm")
  2. An affirmative user response (detected by patterns like "yes", "approve", "looks good")
  3. Both conditions set phase_exit_confirmed = true in state
# In track-tool-use.py
def _detect_question_type(question_text, options):
    """Detects: 'exit_confirmation', 'data_collection', 'clarification'"""
    exit_patterns = ["proceed", "continue", "ready to", "approve", "confirm", ...]

def _is_affirmative_response(response, options):
    """Checks for: 'yes', 'proceed', 'approve', 'confirm', 'ready', ..."""

Links


License

MIT


Made with care for API developers using Claude Code

"Disambiguate, research, interview, verify, repeat"

About

Interview-driven API development workflow for Claude Code - Automates research, testing, and documentation

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •