New users were confused about which files they write vs. which Ralph manages, and how PROMPT.md, specs/, and fix_plan.md relate to each other. Added: - docs/user-guide/ with quick start tutorial, file reference, and requirements writing guide - examples/simple-cli-tool/ showing minimal Ralph configuration - examples/rest-api/ demonstrating when to use specs/ - README section explaining Ralph files and their relationships Also documents specs/stdlib/ purpose for reusable patterns.
7.7 KiB
Writing Effective Requirements
Ralph works best when it understands what you want. This guide shows you how to write clear requirements in PROMPT.md, when to use specs/, and how fix_plan.md evolves during development.
PROMPT.md: Good vs Bad Examples
Bad Example
# Project
Make a good API for managing stuff. Use best practices.
Should be fast and work well.
Problems:
- What "stuff"? Too vague.
- What are "best practices"? Claude will guess.
- "Fast" and "work well" aren't measurable.
Good Example
# Ralph Development Instructions
## Context
You are Ralph, building a REST API for a pet adoption shelter.
The API manages animals, adopters, and adoption records.
## Technology Stack
- Python 3.11+ with FastAPI
- PostgreSQL with SQLAlchemy (async)
- pytest for testing
- Pydantic for validation
## Key Principles
- RESTful endpoints following standard conventions
- All endpoints require authentication except GET /animals
- Soft delete for all entities (is_deleted flag, not actual deletion)
- Pagination on all list endpoints (default 20, max 100)
## Data Entities
- Animal: name, species, breed, age, status (available/adopted/pending)
- Adopter: name, email, phone, approved (boolean)
- Adoption: animal_id, adopter_id, date, status
## Quality Standards
- Every endpoint needs at least one happy-path test
- Input validation with clear error messages
- OpenAPI documentation for all endpoints
Why this works:
- Clear domain (pet adoption shelter)
- Specific technology choices
- Measurable constraints (pagination limits)
- Concrete data model
- Defined quality bar
fix_plan.md: Task Writing
The Goldilocks Principle
Tasks should be not too big, not too small.
Too big (Ralph doesn't know where to start):
- [ ] Build the entire authentication system
Too small (wastes loop iterations):
- [ ] Create the auth folder
- [ ] Create the auth/__init__.py file
- [ ] Create the auth/routes.py file
Just right (one loop of meaningful work):
- [ ] Create auth routes with POST /login and POST /logout endpoints
- [ ] Add JWT token generation and validation middleware
- [ ] Create refresh token endpoint POST /auth/refresh
Task Structure Template
# Fix Plan - [Project Name]
## Priority 1: [Foundation/Critical Path]
- [ ] [Specific, actionable task]
- [ ] [Another specific task]
## Priority 2: [Core Features]
- [ ] [Feature task]
- [ ] [Feature task]
## Priority 3: [Polish/Nice-to-have]
- [ ] [Enhancement]
- [ ] [Documentation]
## Discovered
<!-- Ralph adds tasks it discovers here -->
How fix_plan.md Evolves
Initial state (you write this):
## Priority 1: Database
- [ ] Set up database models for Animal, Adopter, Adoption
## Priority 2: API
- [ ] Create CRUD endpoints for animals
After Loop 1 (Ralph updates):
## Priority 1: Database
- [x] Set up database models for Animal, Adopter, Adoption
## Priority 2: API
- [ ] Create CRUD endpoints for animals
## Discovered
- [ ] Add database migration with Alembic
- [ ] Create pytest fixtures for test database
After Loop 3:
## Priority 1: Database
- [x] Set up database models for Animal, Adopter, Adoption
## Priority 2: API
- [x] Create CRUD endpoints for animals
- [ ] Create CRUD endpoints for adopters
## Discovered
- [x] Add database migration with Alembic
- [x] Create pytest fixtures for test database
- [ ] Add pagination to GET /animals endpoint
Ralph adds tasks it discovers and checks them off as it works. You can:
- Reorder tasks by moving them to different priority sections
- Delete tasks that are no longer relevant
- Add new tasks anytime
When to Use specs/
Use specs/ for complex features
PROMPT.md says:
Add a matching algorithm that suggests animals to adopters.
This is too vague. Create .ralph/specs/matching-algorithm.md:
# Animal Matching Algorithm
## Inputs
- Adopter preferences: species, max_age, size_preference
- Available animals list
## Algorithm
1. Filter by species (required match)
2. Score by age preference (0-100 points)
- Within range: 100 points
- Within 2 years: 50 points
- Outside: 0 points
3. Score by size preference (0-50 points)
4. Return top 5 by total score
## Output Format
```json
[
{"animal_id": 1, "score": 145, "reasons": ["species match", "age within preference"]},
{"animal_id": 3, "score": 120, "reasons": ["species match"]}
]
Edge Cases
- No matches: return empty array
- Tie scores: sort by animal.created_at (oldest first)
**Then in fix_plan.md**:
```markdown
- [ ] Implement matching algorithm per specs/matching-algorithm.md
Use specs/stdlib/ for conventions
When you want consistency across the project, document it:
.ralph/specs/stdlib/error-responses.md:
# Error Response Standard
All API errors return this structure:
```json
{
"error": {
"code": "ANIMAL_NOT_FOUND",
"message": "No animal with ID 42 exists",
"field": null,
"details": {}
}
}
Error Codes
| Code | HTTP Status | When |
|---|---|---|
| VALIDATION_ERROR | 400 | Invalid input |
| NOT_FOUND | 404 | Resource doesn't exist |
| ALREADY_ADOPTED | 409 | Animal not available |
| UNAUTHORIZED | 401 | Missing/invalid token |
### Don't use specs/ for everything
**Overkill** - You don't need specs/ for:
```markdown
# User Password Requirements
Passwords must be at least 8 characters.
Just put it in PROMPT.md:
## Authentication
- Passwords: minimum 8 characters, at least one number
- JWT tokens expire after 1 hour
Common Mistakes
Mistake 1: Assuming Claude knows your preferences
Bad:
Use standard authentication.
Good:
Use JWT authentication with 1-hour token expiry.
Refresh tokens last 7 days and rotate on use.
Mistake 2: Mixing implementation with requirements
Bad (in PROMPT.md):
Create a file called auth.py and add these imports:
import jwt
from datetime import datetime
Good (in PROMPT.md):
Use JWT for authentication. Tokens should expire after 1 hour.
Let Ralph figure out the implementation details.
Mistake 3: Over-specifying tests
Bad:
- [ ] Write test_create_animal_success
- [ ] Write test_create_animal_invalid_species
- [ ] Write test_create_animal_missing_name
- [ ] Write test_create_animal_negative_age
Good:
- [ ] Write tests for animal creation (success and validation errors)
Ralph knows how to write tests. Tell it what to test, not how.
Mistake 4: Forgetting the "why"
Bad:
Add a 100ms delay to all API responses.
Good:
Add a 100ms delay to all API responses (required for rate limiting compliance with external payment API).
When Ralph understands why, it makes better decisions.
Checklist: Before Running Ralph
Before ralph --monitor, verify:
- PROMPT.md has clear context - Does Ralph know what it's building?
- Technology stack is specified - Did you pick the frameworks?
- Key constraints are documented - Auth approach? API conventions?
- fix_plan.md has specific tasks - Can Ralph start on task 1 immediately?
- Complex features have specs/ - Is anything too vague for PROMPT.md?
If you can answer "yes" to these, Ralph will do good work.
Quick Reference
| Need to... | Put it in... |
|---|---|
| Set project vision and principles | PROMPT.md |
| Define technology stack | PROMPT.md |
| List specific implementation tasks | fix_plan.md |
| Document complex feature requirements | specs/feature-name.md |
| Establish coding conventions | specs/stdlib/convention-name.md |
| Configure Ralph behavior | .ralphrc |