codetether-agent 0.1.5

A2A-native AI coding agent for the CodeTether ecosystem
Documentation
# Ralph - Autonomous PRD-Driven Agent Loop

## Overview

Ralph is an autonomous AI agent loop that implements the "ralph pattern" (named after Geoffrey Huntley's approach: `while :; do cat PROMPT.md | llm; done`). It iterates through PRD (Product Requirements Document) user stories, running quality gates after each iteration, and uses RLM (Recursive Language Model) for progress compression when context gets too large.

## Architecture

```
src/ralph/
├── mod.rs           # Module exports
├── types.rs         # PRD structures and state types
└── ralph_loop.rs    # Core autonomous execution loop
```

## Public API

### Types (`types.rs`)

#### `UserStory`
Represents a single user story in the PRD.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserStory {
    pub id: String,                          // Unique identifier (e.g., "US-001")
    pub title: String,                       // Short title
    pub description: String,                 // Full description
    pub acceptance_criteria: Vec<String>,    // Acceptance criteria
    pub passes: bool,                        // Whether this story passes all tests
    pub priority: u8,                        // Story priority (1=highest)
    pub depends_on: Vec<String>,             // Dependencies on other story IDs
    pub complexity: u8,                      // Estimated complexity (1-5)
}
```

#### `Prd`
The full PRD structure.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Prd {
    pub project: String,                     // Project name
    pub feature: String,                     // Feature being implemented
    pub branch_name: String,                 // Git branch name for this PRD
    pub version: String,                     // Version of the PRD format
    pub user_stories: Vec<UserStory>,        // User stories to implement
    pub technical_requirements: Vec<String>, // Technical requirements
    pub quality_checks: QualityChecks,       // Quality checks to run
    pub created_at: String,                  // Created timestamp
    pub updated_at: String,                  // Last updated timestamp
}
```

**Methods on `Prd`:**
- `async fn load(path: &PathBuf) -> anyhow::Result<Self>` - Load a PRD from a JSON file
- `async fn save(&self, path: &PathBuf) -> anyhow::Result<()>` - Save the PRD to a JSON file
- `fn next_story(&self) -> Option<&UserStory>` - Get the next story to work on (not passed, dependencies met)
- `fn passed_count(&self) -> usize` - Get count of passed stories
- `fn is_complete(&self) -> bool` - Check if all stories are complete
- `fn mark_passed(&mut self, story_id: &str)` - Mark a story as passed
- `fn ready_stories(&self) -> Vec<&UserStory>` - Get all stories ready to be worked on
- `fn stages(&self) -> Vec<Vec<&UserStory>>` - Group stories into parallel execution stages based on dependencies

#### `QualityChecks`
Configuration for quality gates.

```rust
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct QualityChecks {
    pub typecheck: Option<String>,  // Command to run type checking
    pub test: Option<String>,       // Command to run tests
    pub lint: Option<String>,       // Command to run linting
    pub build: Option<String>,      // Command to run build
}
```

#### `RalphState`
Ralph execution state.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RalphState {
    pub prd: Prd,                          // The PRD being worked on
    pub current_iteration: usize,          // Current iteration number
    pub max_iterations: usize,             // Maximum allowed iterations
    pub status: RalphStatus,               // Current status
    pub progress_log: Vec<ProgressEntry>,  // Progress log entries
    pub prd_path: PathBuf,                 // Path to the PRD file
    pub working_dir: PathBuf,              // Working directory
}
```

#### `RalphStatus`
Execution status enum.

```rust
pub enum RalphStatus {
    Pending,
    Running,
    Completed,
    MaxIterations,
    Stopped,
    QualityFailed,
}
```

#### `ProgressEntry`
A progress log entry.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProgressEntry {
    pub story_id: String,       // Story ID being worked on
    pub iteration: usize,       // Iteration number
    pub status: String,         // Status of this attempt
    pub learnings: Vec<String>, // What was learned
    pub files_changed: Vec<String>, // Files changed
    pub timestamp: String,      // Timestamp
}
```

#### `RalphConfig`
Configuration for the Ralph loop.

```rust
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RalphConfig {
    pub prd_path: String,                  // Path to prd.json
    pub max_iterations: usize,             // Maximum iterations (default: 10)
    pub progress_path: String,             // Path to progress.txt
    pub auto_commit: bool,                 // Whether to auto-commit changes
    pub quality_checks_enabled: bool,      // Whether to run quality checks
    pub model: Option<String>,             // Model to use for iterations
    pub use_rlm: bool,                     // Whether to use RLM for progress compression
    pub parallel_enabled: bool,            // Enable parallel story execution
    pub max_concurrent_stories: usize,     // Maximum concurrent stories (default: 3)
    pub worktree_enabled: bool,            // Use worktree isolation for parallel execution
}
```

### Core Loop (`ralph_loop.rs`)

#### `RalphLoop`
The main Ralph executor.

```rust
pub struct RalphLoop {
    state: RalphState,
    provider: Arc<dyn Provider>,
    model: String,
    config: RalphConfig,
}
```

**Methods:**

- `async fn new(prd_path: PathBuf, provider: Arc<dyn Provider>, model: String, config: RalphConfig) -> anyhow::Result<Self>`
  - Create a new Ralph loop instance

- `async fn run(&mut self) -> anyhow::Result<RalphState>`
  - Run the Ralph loop until completion or max iterations
  - Returns the final state

- `pub fn status(&self) -> &RalphState`
  - Get current status

- `pub fn status_markdown(&self) -> String`
  - Format status as markdown

#### `create_prd_template`
Creates a sample PRD template.

```rust
pub fn create_prd_template(project: &str, feature: &str) -> Prd
```

## Key Features

### 1. Sequential Execution Mode
The original behavior where stories are processed one at a time:
- Gets the next available story (respecting dependencies)
- Builds a prompt with context
- Calls the LLM with tool access
- Runs quality gates
- Commits changes if successful
- Saves updated PRD

### 2. Parallel Execution Mode
Processes independent stories in parallel using worktree isolation:
- Groups stories into stages based on dependencies
- Creates isolated git worktrees for each story
- Uses semaphore to limit concurrency (default: 3 concurrent)
- Merges successful stories back to main branch
- Handles merge conflicts with a dedicated conflict resolver sub-agent

### 3. Worktree Isolation
For parallel execution:
- Each story gets its own git worktree
- Workspace stub injection for Cargo project isolation
- Automatic cleanup on success or failure
- Keeps worktrees for debugging on failure

### 4. Quality Gates
Configurable quality checks run after each story:
- Type checking (e.g., `cargo check`)
- Linting (e.g., `cargo clippy`)
- Testing (e.g., `cargo test`)
- Building (e.g., `cargo build`)

### 5. Git Integration
- Automatic branch switching
- Auto-commit with conventional commit format: `feat({story_id}): {title}`
- Worktree creation and management
- Merge conflict detection and resolution
- Cleanup of orphaned worktrees/branches

### 6. Progress Tracking
- Persistent progress log in `progress.txt`
- PRD state saved after each story
- Learnings extraction from responses
- Structured progress entries with timestamps

### 7. Conflict Resolution
When parallel stories have merge conflicts:
- Spawns a dedicated conflict resolver sub-agent
- Provides context about both sides of the conflict
- Attempts intelligent resolution
- Completes merge if successful, aborts if not

## Tool Interface

Ralph is also exposed as a tool (`src/tool/ralph.rs`) with the following actions:

### Actions

- **`run`** - Start the Ralph loop with a PRD file
  - Parameters: `prd_path`, `max_iterations`
  - Returns metadata: `all_passed`, `ready_to_merge`, `feature_branch`, `passed`, `total`

- **`status`** - Check progress of current Ralph run
  - Parameters: `prd_path`
  - Returns current progress summary

- **`create-prd`** - Create a new PRD template
  - Parameters: `project`, `feature`, `prd_path`
  - Creates a sample PRD file

## Usage Examples

### CLI Usage
```bash
# Create a PRD template
codetether ralph create-prd --project "MyProject" --feature "New Feature"

# Run Ralph on a PRD
codetether ralph run --prd prd.json --max-iterations 10

# Check status
codetether ralph status --prd prd.json
```

### Tool Usage
```rust
// Create PRD
ralph({action: 'create-prd', project: 'MyProject', feature: 'New Feature'})

// Run Ralph
ralph({action: 'run', prd_path: 'prd.json', max_iterations: 10})

// Check status
ralph({action: 'status', prd_path: 'prd.json'})
```

### Programmatic Usage
```rust
use codetether::ralph::{RalphLoop, RalphConfig, Prd};

// Load PRD
let prd = Prd::load(&PathBuf::from("prd.json")).await?;

// Create config
let config = RalphConfig {
    max_iterations: 10,
    parallel_enabled: true,
    max_concurrent_stories: 3,
    worktree_enabled: true,
    ..Default::default()
};

// Create and run Ralph
let mut ralph = RalphLoop::new(
    PathBuf::from("prd.json"),
    provider,
    model,
    config
).await?;

let state = ralph.run().await?;
```

## PRD JSON Format

```json
{
  "project": "project-name",
  "feature": "Feature Name",
  "branch_name": "feature/feature-name",
  "version": "1.0",
  "user_stories": [
    {
      "id": "US-001",
      "title": "Story title",
      "description": "What to implement",
      "acceptance_criteria": ["Criterion 1", "Criterion 2"],
      "priority": 1,
      "depends_on": [],
      "complexity": 3,
      "passes": false
    }
  ],
  "technical_requirements": [],
  "quality_checks": {
    "typecheck": "cargo check",
    "lint": "cargo clippy",
    "test": "cargo test",
    "build": "cargo build"
  },
  "created_at": "2024-01-01T00:00:00Z",
  "updated_at": "2024-01-01T00:00:00Z"
}
```

## Memory Persistence

Ralph uses file-based memory (not context accumulation):
- `progress.txt` - Agent writes learnings/blockers
- `prd.json` - Tracks pass/fail status for each story
- Git history - Shows what changed per iteration

## Dependencies

- `crate::provider::Provider` - LLM provider for completions
- `crate::swarm::run_agent_loop` - Agent loop for sub-agents
- `crate::tool::ToolRegistry` - Tool registry for agent tools
- `crate::worktree::WorktreeManager` - Git worktree management
- `crate::agent::builtin::build_system_prompt` - System prompt construction

## Integration Points

1. **CLI** (`src/main.rs`) - Direct command-line interface
2. **Tool** (`src/tool/ralph.rs`) - Tool interface for agents
3. **Swarm** (`src/swarm/executor.rs`) - Used in sub-agent instructions
4. **MCP Server** (`src/mcp/server.rs`) - Documented capability