Skip to main content

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

BenefitWhy It Matters
Better AI outputClear specs produce more accurate code
Faster iterationLess back-and-forth fixing misunderstandings
Built-in documentationSpecs serve as living documentation
Easier reviewCompare output directly against requirements
Reduced riskSecurity and architecture constraints are explicit
Team alignmentEveryone 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.