Spec-Driven Development
The single most effective way to improve the quality of AI-generated code is to write better specifications. When you give an AI a clear, detailed spec, you get better results. When you give it a vague prompt, you get code that may or may not do what you need.
Why Specs Matter for AI
AI coding tools are incredibly responsive to input quality. A well-written specification:
- Reduces ambiguity — the AI knows exactly what to build
- Defines constraints — security, performance, and architectural requirements are explicit
- Provides context — the AI understands how the code fits into your larger system
- Enables verification — you can check if the output meets the requirements
- Creates documentation — the spec itself becomes living documentation
The Spec-Driven Workflow
Idea
↓
Requirements.md
↓
Architecture.md
↓
Tasks.md
↓
AI-assisted implementation
↓
Human review
↓
Testing
↓
Deployment
1. Requirements Document
Start by writing a clear requirements document. This doesn't need to be formal — just clear.
# User Authentication Requirements
## Overview
Implement email/password authentication for a SaaS application.
## Functional Requirements
- Users can register with email and password
- Users can log in with email and password
- Users can reset their password via email
- Users can log out
- Session expires after 24 hours
## Security Requirements
- Passwords must be hashed using bcrypt
- Rate limiting: max 5 login attempts per minute per IP
- CSRF protection on all authentication forms
- HTTPS required for all authentication endpoints
- Password minimum: 8 characters, at least 1 number and 1 special character
## Data Requirements
- Store users in PostgreSQL
- Email must be unique and validated
- Store password reset tokens with 1-hour expiration
- Log all authentication attempts (success and failure)
2. Architecture Document
Define how the solution fits into your existing system.
# Authentication Architecture
## Components
- AuthController: handles HTTP requests
- AuthService: business logic for authentication
- UserRepository: database access for user data
- SessionManager: handles session creation and validation
- RateLimiter: prevents brute force attacks
## Data Flow
1. User submits login form → AuthController
2. AuthController validates input → passes to AuthService
3. AuthService checks RateLimiter → queries UserRepository
4. AuthService verifies password → creates Session
5. Session stored in Redis with 24h TTL
6. Response returned with session cookie
## Dependencies
- Laravel Sanctum for session management
- Redis for rate limiting and session storage
- PostgreSQL for user data
3. Task Decomposition
Break the work into small, implementable tasks.
## Tasks
### Task 1: User Registration
- [ ] Create User model with validation rules
- [ ] Implement registration endpoint (POST /api/register)
- [ ] Hash password with bcrypt before storage
- [ ] Send email verification (optional)
- [ ] Return user data + session token
### Task 2: User Login
- [ ] Implement login endpoint (POST /api/login)
- [ ] Validate credentials against database
- [ ] Implement rate limiting
- [ ] Create session on successful login
- [ ] Return session token
### Task 3: Password Reset
- [ ] Implement forgot password endpoint (POST /api/forgot-password)
- [ ] Generate and store reset token
- [ ] Send password reset email
- [ ] Implement reset password endpoint (POST /api/reset-password)
- [ ] Expire token after use or 1 hour
4. AI-Assisted Implementation
Now feed each task to your AI tool with the full context:
Implement Task 1: User Registration
Context:
- Laravel 11 application with Sanctum
- PostgreSQL database
- Requirements: bcrypt hashing, email validation, rate limiting
- Architecture: AuthController → AuthService → UserRepository
Please implement:
1. User model with validation rules
2. Registration endpoint
3. Password hashing
4. Session creation
5. Error handling
5. Human Review
Review the generated code against your spec:
- Does it meet all functional requirements?
- Are security requirements implemented correctly?
- Does it follow your project's coding standards?
- Are there any edge cases not handled?
- Is error handling comprehensive?
6. Testing
Write tests that verify the spec:
public function test_user_can_register_with_valid_data()
{
$response = $this->post('/api/register', [
'email' => 'test@example.com',
'password' => 'SecureP@ss1',
'password_confirmation' => 'SecureP@ss1',
]);
$response->assertStatus(201);
$this->assertDatabaseHas('users', [
'email' => 'test@example.com',
]);
}
public function test_registration_fails_with_weak_password()
{
$response = $this->post('/api/register', [
'email' => 'test@example.com',
'password' => 'weak',
'password_confirmation' => 'weak',
]);
$response->assertStatus(422);
$response->assertJsonValidationErrors('password');
}
7. Deployment
Deploy with confidence because you know exactly what the code does and have verified it against your spec.
Benefits of Spec-Driven Development
| Benefit | Why It Matters |
|---|---|
| Better AI output | Clear specs produce more accurate code |
| Faster iteration | Less back-and-forth fixing misunderstandings |
| Built-in documentation | Specs serve as living documentation |
| Easier review | Compare output directly against requirements |
| Reduced risk | Security and architecture constraints are explicit |
| Team alignment | Everyone understands what's being built |
Templates
Here are templates you can use for your own projects:
Better specs produce better AI-generated code. The time you invest in writing clear specifications pays for itself many times over in reduced debugging, fewer security issues, and faster development.