This template provides a starting structure for autonomous agent loops with persistent state tracking.
.project/
├── prd.md # Product Requirements Document
├── constraints.md # Technical and business constraints
├── state.json # Current state (modified by agent)
├── decisions.md # Decision log (modified by agent)
├── attempts/ # Failed attempts archive
│ └── YYYY-MM-DD_HH-MM/
│ ├── diff.patch
│ └── notes.md
└── completed.json # Success markers
prd.md - Requirements Specification# Feature: User Notification System
## Summary
Users should receive email notifications when their order status changes.
## Acceptance Criteria
- [ ] Email sent when order status changes to "shipped"
- [ ] Email sent when order status changes to "delivered"
- [ ] Email includes order details and tracking link
- [ ] Users can opt out of notifications in settings
- [ ] Failed emails are retried 3 times with exponential backoff
## Out of Scope
- SMS notifications
- Push notifications
- Marketing emails
## Technical Notes
- Use existing email service (Resend)
- Store notification preferences in user_settings table
- Add notification_log table for audit
constraints.md - Technical Constraints# Technical Constraints
## Stack
- Backend: FastAPI
- Database: PostgreSQL + SQLAlchemy
- Email: Resend API
- Background tasks: Celery + Redis
## Must Follow
- Use existing user_settings model
- Follow logging standards (app.logging.get_logger)
- All DB changes via migrations (alembic)
- Tests for all new functions
## Must NOT
- Create new database connections
- Use deprecated send_email() function
- Modify order model directly
- Add new Celery queue (use existing 'notifications' queue)
## Performance
- Max 100 emails per minute (Resend limit)
- Track retry attempts to avoid infinite loops
state.json - Current State (Agent Modifies This){
"status": "in_progress",
"current_task": "Add notification preference fields to user_settings",
"phase": "implementation",
"started_at": "2024-01-15T10:30:00Z",
"last_updated": "2024-01-15T11:45:00Z",
"context": {
"files_modified": ["app/models/user_settings.py", "app/schemas/user.py"],
"files_created": [],
"tests_passing": true,
"lint_clean": false
},
"next_steps": [
"Fix lint errors in app/models/user_settings.py",
"Create notification service",
"Add tests for notification service"
]
}
decisions.md - Decision Log# Decision Log
## 2024-01-15 10:32 - Started Implementation
**Agent:** Claude
**Decision:** Start with user_settings model modification
**Rationale:** Foundation for notification preferences
## 2024-01-15 10:45 - Model Updated
**Decision:** Add `notification_preferences` JSON column instead of separate table
**Rationale:**
- Fewer migrations
- Flexible schema for future notification types
- Consistent with existing user_settings pattern
**Files Changed:** app/models/user_settings.py
## 2024-01-15 11:20 - Service Architecture
**Decision:** Create `NotificationService` class vs direct Celery task calls
**Rationale:**
- Easier testing
- Better separation of concerns
- Consistent with existing service pattern (OrderService, UserService)
attempts/ - Failed Attempts Archiveattempts/
└── 2024-01-15_09-30/
├── diff.patch # What was tried
└── notes.md # Why it failed
# Attempt: 2024-01-15 09:30
## Goal
Send email directly from order status update handler
## Approach
- Import send_notification in app/services/order.py
- Call directly in update_order_status()
## Why It Failed
- Circular dependency: order.py imports notification.py imports order.py
- Tests failed with ImportError
- Lint errors due to import cycle
## Lessons Learned
- Create separate notification_service.py instead
- Use Celery task to avoid direct dependency
- Need to restructure imports
completed.json - Success Markers{
"completed_at": "2024-01-15T14:30:00Z",
"summary": "Successfully implemented notification system",
"files_changed": {
"modified": [
"app/models/user_settings.py",
"app/schemas/user.py",
"app/services/order.py"
],
"created": [
"app/services/notification.py",
"app/tasks/notifications.py",
"tests/test_notification.py"
]
},
"tests": {
"unit": "12 tests, all passing",
"integration": "3 tests, all passing"
},
"manual_verification": "Emails sent successfully in staging environment"
}
Copy this template directory to your project:
cp -r exercises/ralph_template/.project your-project/
Edit prd.md with your feature requirements
Edit constraints.md with your project’s technical constraints
Initialize state.json:
{
"status": "ready",
"current_task": null,
"phase": "planning",
"started_at": null
}
Start the agent:
Ask the agent to read .project/prd.md and .project/constraints.md,
then implement the feature step by step, updating state.json as
it progresses.
# Check current status
cat .project/state.json | jq '.status, .current_task, .phase'
# View decisions log
tail -f .project/decisions.md
# Check for failed attempts
ls -la .project/attempts/
Agent creates a new attempt folder with:
Agent does git checkout . to clean state
Agent reads previous attempts to avoid repeating mistakes
Agent updates approach and tries again
The loop should automatically stop when:
prd.md are checkedstate.json has status: “completed”completed.json is populatedCreate a .project/ directory for a simple feature:
prd.md for: “Add user avatar upload feature”constraints.md for your demo appstate.json