-
Notifications
You must be signed in to change notification settings - Fork 0
Spec Driven Development
Status: ✅ Complete
Last Updated: December 3, 2025
Spec-Driven Development is a systematic approach to building software where you define what you want to build (requirements), how you'll build it (design), and the tasks to execute (implementation plan) before writing code. This guide explains how to use RiceCoder's spec system to develop features methodically and ensure correctness.
A spec is a formal specification document that defines a feature or system in three phases:
- Requirements - What you want to build (user stories and acceptance criteria)
- Design - How you'll build it (architecture, data models, algorithms)
- Tasks - Implementation plan (concrete coding tasks with dependencies)
Specs bridge the gap between ideas and implementation, ensuring alignment before you write code.
Benefits of Spec-Driven Development:
- Clarity: Define requirements before design; design before implementation
- Alignment: Ensure stakeholders agree on what's being built
- Traceability: Every task traces back to requirements; every requirement traces to discovery
- Quality: Acceptance criteria define success; implementation is complete when all criteria are met
- Efficiency: Catch misunderstandings early, before writing code
- Documentation: Specs serve as living documentation of your system
Use specs for:
- New features (anything more than a bug fix)
- Architecture changes
- Major refactoring
- New projects
- Feature enhancements
Don't use specs for:
- Bug fixes (fix directly)
- Small refactoring (refactor directly)
- Performance optimizations (optimize directly)
Each spec has three components, organized in .agent/specs/{feature-name}/:
.agent/specs/my-feature/
├── requirements.md # What to build
├── design.md # How to build it
└── tasks.md # Implementation tasks
File: requirements.md
Purpose: Define what you want to build using user stories and acceptance criteria
Structure:
# Feature Name - Requirements
## Introduction
Brief description of the feature
## Glossary
Define domain-specific terms
## Requirements
### Requirement 1: [Feature Name]
**User Story**: As a [role], I want [feature], so that [benefit]
#### Acceptance Criteria
1. WHEN [condition] THEN [expected outcome]
2. WHEN [condition] THEN [expected outcome]
3. ...Key Elements:
- User Story: Describes who wants what and why
- Acceptance Criteria: Specific, testable conditions that define success
- Glossary: Defines domain terms to avoid ambiguity
Example:
### Requirement 1: Add Task to List
**User Story**: As a user, I want to add new tasks to my todo list, so that I can capture things I need to do.
#### Acceptance Criteria
1. WHEN a user types a task description and presses Enter THEN the system SHALL create a new task and add it to the list
2. WHEN a user attempts to add an empty task THEN the system SHALL prevent the addition and maintain the current state
3. WHEN a new task is added THEN the system SHALL persist the task to local storage immediatelyFile: design.md
Purpose: Define how you'll build the feature to satisfy requirements
Structure:
# Feature Name - Design
## Overview
High-level description of the design
## Architecture
System architecture and component organization
## Components and Interfaces
Detailed component descriptions
## Data Models
Data structures and relationships
## Correctness Properties
Formal properties that must hold true
## Error Handling
How errors are handled
## Testing Strategy
Unit and property-based testing approachKey Elements:
- Architecture: How components fit together
- Data Models: What data structures you'll use
- Algorithms: How key logic works
- Error Handling: What happens when things go wrong
- Correctness Properties: Formal statements about what must be true
Example:
## Architecture
```text
┌─────────────────┐
│ UI Layer │
└────────┬────────┘
│
┌────────▼────────┐
│ Application │
│ Layer │
└────────┬────────┘
│
┌────────▼────────┐
│ Domain Layer │
└─────────────────┘pub struct Task {
pub id: String,
pub description: String,
pub completed: bool,
pub created_at: DateTime,
}For any task list, adding a valid task should increase the list length by one.
Validates: Requirement 1.1
### 3. Tasks Document
**File**: `tasks.md`
**Purpose**: Break design into concrete implementation tasks
**Structure**:
```markdown
# Feature Name - Implementation Plan
- [ ] 1. Set up project structure
- Create directory structure
- Set up testing framework
- _Requirements: 1.1_
- [ ] 2. Implement core logic
- [ ] 2.1 Implement data model
- [ ] 2.2 Implement business logic
- [ ]* 2.3 Write unit tests
- [ ] 3. Integrate with UI
- [ ] 3.1 Create UI components
- [ ] 3.2 Wire up event handlers
Key Elements:
- Hierarchical structure: Parent tasks with sub-tasks
- Dependencies: Clear ordering of tasks
- Requirements traceability: Each task references requirements
-
Optional tasks: Marked with
*for testing and documentation
The complete workflow for spec-driven development:
- Identify the feature: What do you want to build?
- Write user stories: Who wants it and why?
- Define acceptance criteria: What does success look like?
- Get approval: Ensure stakeholders agree
Time: 20-40% of spec time
Deliverable: requirements.md
- Understand requirements: What must be built?
- Design architecture: How will components fit together?
- Define data models: What data structures will you use?
- Plan algorithms: How will key logic work?
- Get approval: Ensure design satisfies requirements
Time: 30% of spec time
Deliverable: design.md
- Break down design: What concrete tasks are needed?
- Order tasks: What depends on what?
- Define exit criteria: How do you know each task is done?
- Get approval: Ensure tasks cover all requirements
Time: 15% of spec time
Deliverable: tasks.md
- Implement tasks: Write code according to design
- Validate each task: Ensure exit criteria are met
- Run acceptance tests: Verify requirements are satisfied
- Get approval: Feature is complete
Time: Varies
Deliverable: Working code
rice spec create my-featureThis creates:
.agent/specs/my-feature/
├── requirements.md
├── design.md
└── tasks.md
Edit .agent/specs/my-feature/requirements.md:
# My Feature - Requirements
## Introduction
This feature allows users to [do something useful].
## Glossary
- **User**: A person using the system
- **Feature**: A capability of the system
## Requirements
### Requirement 1: Core Functionality
**User Story**: As a user, I want to [do something], so that [I get benefit].
#### Acceptance Criteria
1. WHEN [condition] THEN [expected outcome]
2. WHEN [condition] THEN [expected outcome]Edit .agent/specs/my-feature/design.md:
# My Feature - Design
## Overview
This feature is implemented using [architecture pattern].
## Architecture
[Describe how components fit together]
## Data Models
[Define data structures]
## Correctness Properties
### Property 1: [Property name]
*For any* [input], [property should hold].
**Validates: Requirement 1.1**Edit .agent/specs/my-feature/tasks.md:
# My Feature - Implementation Plan
- [ ] 1. Set up project structure
- Create directories
- Set up testing
- _Requirements: 1.1_
- [ ] 2. Implement core logic
- [ ] 2.1 Implement data model
- [ ] 2.2 Implement business logic
- [ ]* 2.3 Write unit testsrice gen --spec my-featureRiceCoder will:
- Read your specification
- Analyze your project
- Generate implementation code
- Show a diff for review
- Ask for approval
Apply changes? (y/n): y
Your code is generated and applied!
Good:
As a developer, I want to generate code from specifications, so that I can implement features systematically.
Bad:
The system should generate code.
Why: Good user stories explain who, what, and why. This provides context for design decisions.
Good:
WHEN a user adds a task with a non-empty description THEN the task SHALL appear in the list
Bad:
The system should handle tasks properly.
Why: Testable criteria define success objectively. You know when you're done.
Good:
WHEN a user clicks the delete button THEN the task SHALL be removed from the list
Bad:
Users can delete tasks.
Why: WHEN/THEN format is precise and testable. It describes specific scenarios.
Good:
Property: Adding a task increases list length by one
*For any* task list and valid task, adding the task should result in list length increasing by exactly one.
Bad:
Tasks should be added correctly.
Why: Correctness properties are formal statements that can be tested with property-based testing.
Good: One requirement per user story
Bad: Multiple unrelated requirements in one story
Why: Focused requirements are easier to design and implement.
Good: Complete design before writing code
Bad: Start coding, then figure out design
Why: Design phase catches issues early, before you've written code.
Good: Every task references requirements; every requirement references discovery
Bad: Tasks that don't connect to requirements
Why: Traceability ensures nothing is missed and scope is clear.
Good: Stakeholders approve requirements, then design, then tasks
Bad: Write everything, then ask for approval
Why: Early approval prevents rework and ensures alignment.
# Add Task Feature - Requirements
## Introduction
Users need to add new tasks to their todo list to capture things they need to do.
## Glossary
- **Task**: An item on the todo list with a description
- **Todo List**: A collection of tasks
## Requirements
### Requirement 1: Add Task to List
**User Story**: As a user, I want to add new tasks to my todo list, so that I can capture things I need to do.
#### Acceptance Criteria
1. WHEN a user types a task description and presses Enter THEN the system SHALL create a new task and add it to the list
2. WHEN a user attempts to add an empty task THEN the system SHALL prevent the addition and maintain the current state
3. WHEN a new task is added THEN the system SHALL persist the task to local storage immediately# Add Task Feature - Design
## Overview
Tasks are added through a text input field. When the user presses Enter, the task is created, added to the list, and persisted.
## Data Models
### Task
```rust
pub struct Task {
pub id: String,
pub description: String,
pub completed: bool,
pub created_at: DateTime,
}For any task list and valid task description, adding the task should increase the list length by one.
Validates: Requirement 1.1
For any empty or whitespace-only string, attempting to add it as a task should fail and leave the list unchanged.
Validates: Requirement 1.2
For any task added to the list, querying local storage should return the same task.
Validates: Requirement 1.3
#### Step 3: Tasks
```markdown
# Add Task Feature - Implementation Plan
- [ ] 1. Set up project structure
- Create src/models/task.rs for Task struct
- Create src/storage/mod.rs for persistence
- Set up testing framework
- _Requirements: 1.1, 1.2, 1.3_
- [ ] 2. Implement data model
- [ ] 2.1 Define Task struct with id, description, completed, created_at
- [ ] 2.2 Implement Task validation (non-empty description)
- [ ]* 2.3 Write unit tests for Task model
- [ ] 3. Implement storage
- [ ] 3.1 Implement local storage interface
- [ ] 3.2 Implement save_task function
- [ ]* 3.3 Write unit tests for storage
- [ ] 4. Implement UI
- [ ] 4.1 Create input field component
- [ ] 4.2 Wire up Enter key handler
- [ ] 4.3 Call add_task on Enter
- [ ]* 4.4 Write integration tests
- [ ] 5. Checkpoint - Ensure all tests pass
- Ensure all tests pass, ask the user if questions arise.
rice gen --spec add-taskReview the generated code, approve it, and start implementing tasks.
┌─────────────────────────────────────────────────────────────┐
│ Spec-Driven Development │
└─────────────────────────────────────────────────────────────┘
1. Create Requirements
├─ Write user stories
├─ Define acceptance criteria
└─ Get approval ✓
2. Create Design
├─ Design architecture
├─ Define data models
├─ Plan algorithms
└─ Get approval ✓
3. Create Tasks
├─ Break down design
├─ Order tasks
├─ Define exit criteria
└─ Get approval ✓
4. Execute Tasks
├─ Implement task 1
├─ Validate task 1
├─ Implement task 2
├─ Validate task 2
└─ ... repeat until complete
5. Validate Against Requirements
├─ Run acceptance tests
├─ Verify all criteria met
└─ Get approval ✓
6. Feature Complete!
### Requirement 1: User Authentication
**User Story**: As a user, I want to log in, so that I can access my account.
### Requirement 2: User Profile
**User Story**: As a user, I want to view my profile, so that I can see my information.
### Requirement 3: User Settings
**User Story**: As a user, I want to change my settings, so that I can customize my experience.Each requirement becomes a separate section in design and tasks.
- [ ] 1. Core functionality (required)
- [ ] 1.1 Implement core logic
- [ ] 1.2 Implement basic UI
- [ ]* 2. Advanced features (optional)
- [ ]* 2.1 Implement caching
- [ ]* 2.2 Implement analyticsOptional tasks are marked with * and can be skipped for MVP.
- [ ] 1. Set up database
- [ ] 1.1 Create schema
- [ ] 1.2 Create migrations
- [ ] 2. Implement API (depends on 1)
- [ ] 2.1 Create endpoints
- [ ] 2.2 Add validation
- [ ] 3. Implement UI (depends on 2)
- [ ] 3.1 Create components
- [ ] 3.2 Wire up API callsTasks are ordered so dependencies are satisfied.
Solution: Start with user stories. Ask:
- Who is the user?
- What do they want to do?
- Why do they want to do it?
Then define acceptance criteria by asking:
- What conditions must be true for this to work?
- What should happen in each case?
Solution: Add more detail:
- Draw architecture diagrams
- Define data structures explicitly
- Describe algorithms step-by-step
- List error cases and how they're handled
Solution: Group related tasks:
- Create parent tasks for logical groupings
- Keep individual tasks focused and small
- Aim for tasks that take 1-4 hours
Solution: Treat specs as living documents:
- Update requirements when they change
- Update design to match new requirements
- Update tasks accordingly
- Get approval for changes before implementing
Solution: Validate against requirements:
- Does the design satisfy all acceptance criteria?
- Are all error cases handled?
- Are data models sufficient?
- Can you implement the design?
If you can't answer yes to all, refine the design.
Create template specs for common patterns:
rice spec create --template feature my-featureShare specs with team members:
# Export spec
rice spec export my-feature > my-feature.md
# Share and get feedback
# Then update based on feedbackLearn from existing specs in your project:
rice spec list
rice spec show existing-featureSpecs serve as documentation:
- Requirements explain what the system does
- Design explains how it works
- Tasks explain how to build it
Don't try to get specs perfect on first try:
- Write rough requirements
- Get feedback
- Refine design
- Get feedback
- Create tasks
- Start implementing
Iteration is normal and expected.
- Quick Start Guide - Get started with RiceCoder
- CLI Commands - All available commands
- Configuration Guide - Configure RiceCoder
- Troubleshooting Guide - Common issues and solutions
Last updated: December 3, 2025