autom8-cli 0.3.0

CLI automation tool for orchestrating Claude-powered development
Documentation
# CLAUDE.md - AI Agent Guide for autom8

## Project Overview

**autom8** is a Rust CLI tool for orchestrating Claude-powered development. It bridges the gap between product requirements (specs) and working code by driving Claude through iterative implementation of user stories.

**Core workflow:** Define features as structured user stories with acceptance criteria → autom8 orchestrates Claude to implement each story → Reviews for quality → Commits changes → Creates GitHub PRs.

## Quick Reference

```bash
# Build and run
cargo build
cargo run -- <command>

# Testing (must pass before PR)
cargo test --all-features
cargo fmt --check
cargo clippy -- -D warnings

# Common commands
cargo run -- run spec.json         # Run implementation from spec
cargo run -- status                # Check current run status
cargo run -- resume                # Resume interrupted run
cargo run -- list                  # List available specs

# Multi-session commands (worktree mode)
cargo run -- run --worktree        # Run in a dedicated worktree
cargo run -- status --all          # Show all sessions for project
cargo run -- resume --session ID   # Resume specific session
cargo run -- clean --worktrees     # Clean up sessions and worktrees
```

## Architecture

```
CLI (main.rs)
Commands (commands/) - command handlers
Runner (runner.rs) - orchestration loop
State Machine (state.rs) - state management
Display Adapter (display.rs) - abstraction
    ├→ CliDisplay (output/)
    └→ TuiDisplay (tui/)
Domain Logic
    ├→ Spec (spec.rs) - user stories
    ├→ Config (config.rs) - settings
    ├→ Git (git.rs) - git operations
    ├→ GitHub (gh/) - PR management
    └→ Claude (claude/) - LLM integration

UI Layer (ui/) - standalone monitoring interfaces
    ├→ GUI (gui/) - Native desktop GUI using eframe/egui
    ├→ TUI (tui/) - Terminal UI using ratatui
    └→ Shared (shared/) - Common types and data loading
```

## Key Files and Modules

| File/Module | LOC | Purpose |
|-------------|-----|---------|
| `main.rs` | ~2,350 | CLI entry point, command parsing (clap) |
| `commands/` | ~4,800 | Command handlers (14 files: run, status, resume, clean, etc.) |
| `runner.rs` | ~3,900 | Main orchestration loop, state transitions, worktree context |
| `state.rs` | ~4,450 | State machine (12 states), session management, metadata |
| `worktree.rs` | ~1,650 | Git worktree operations, session ID generation |
| `claude/` | ~3,400 | Claude CLI integration (9 files: runner, stream, types, etc.) |
| `gh/` | ~1,850 | GitHub CLI integration (8 files: pr, detection, context, etc.) |
| `config.rs` | ~3,650 | TOML config, validation, defaults, worktree settings |
| `output/` | ~2,100 | CLI formatting (10 files: banner, messages, status, etc.) |
| `progress.rs` | ~2,200 | Spinners, progress bars, breadcrumbs |
| `spec.rs` | ~430 | Spec/UserStory structs, JSON serialization |
| `git.rs` | ~1,350 | Git command wrappers |
| `prompts.rs` | ~1,250 | Claude system prompts |
| `ui/` | ~24,050 | UI modules (see UI Directory Structure below) |

### UI Directory Structure

The `ui/` module provides standalone monitoring interfaces for viewing autom8 activity.

```
ui/
├── mod.rs              (~15 LOC)   - Module exports
├── gui/                (~17,830 LOC) - Native desktop GUI (eframe/egui)
│   ├── app.rs          (~14,730 LOC) - Main app, session cards, views, state
│   ├── components.rs   (~870 LOC)  - Reusable UI components, text truncation
│   ├── config.rs       (~600 LOC)  - Config tab types and edit logic
│   ├── modal.rs        (~590 LOC)  - Modal dialog component
│   ├── theme.rs        (~490 LOC)  - Colors, spacing, shadows, visuals
│   ├── typography.rs   (~290 LOC)  - Font sizes, weights, helpers
│   └── animation.rs    (~260 LOC)  - Decorative particle animations
├── tui/                (~4,700 LOC) - Terminal UI (ratatui/crossterm)
│   ├── app.rs          (~4,560 LOC) - Main app, views, event loop
│   └── views.rs        (~120 LOC)  - View enum definitions
└── shared/             (~1,520 LOC) - Framework-agnostic shared logic
    └── mod.rs          (~1,520 LOC) - Status types, data loading, formatting
```

**GUI (`gui/`)**: Native desktop application built with eframe/egui. Provides a warm, Claude-inspired aesthetic with session monitoring, run history, config editing, and project overview. Key features:
- Session cards with output display (clipped viewport, text truncation)
- Rising particle animations
- Modal dialogs for confirmations
- Responsive layout with sidebar navigation

**TUI (`tui/`)**: Terminal-based interface using ratatui. Keyboard-navigable dashboard showing active runs, project list, and run history.

**Shared (`shared/`)**: Common types and loading functions used by both GUI and TUI:
- `Status` enum for semantic state mapping
- `SessionData`, `ProjectData`, `RunHistoryEntry` types
- `load_ui_data()`, `load_run_history()` functions
- Time formatting utilities

## State Machine

The runner implements a deterministic state machine:

```
Idle → Initializing → PickingStory → RunningClaude → Reviewing → Correcting → Committing → CreatingPR → Completed
                                          ↑               ↓
                                          └───────────────┘
                                              (on issues)
```

States are defined in `state.rs` as `MachineState` enum. Transitions are explicit and persisted to the session's `state.json` file (see [Directory Structure](#directory-structure) in Worktree Architecture).

## Important Patterns

### 1. Display Adapter (Strategy Pattern)
All output goes through `DisplayAdapter` trait (`display.rs:30`). Never use `println!` directly in `runner.rs`.

```rust
// Good - uses adapter
display.phase_banner("Implementation", BannerColor::Green);

// Bad - direct output
println!("Implementation");
```

### 2. Progress Display Helper
Use `with_progress_display()` (`runner.rs`) for operations that need verbose/spinner handling:

```rust
with_progress_display(
    verbose,
    display,
    || VerboseTimer::new("operation"),
    || ClaudeSpinner::new(),
    || run_operation(),
    |result| map_to_outcome(result),
)
```

### 3. Loop Control
The main loop uses explicit `LoopAction` enum:
```rust
enum LoopAction { Continue, Break }
```

### 4. Error Handling
Use `thiserror` crate. Errors defined in `error.rs`:
```rust
#[derive(Debug, thiserror::Error)]
pub enum Autom8Error {
    #[error("Spec not found: {0}")]
    SpecNotFound(String),
    // ...
}
```

### 5. JSON Serialization
Specs use camelCase serialization:
```rust
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct Spec { ... }
```

## Configuration

**Global config:** `~/.config/autom8/config.toml`
```toml
review = true            # Enable review step
commit = true            # Auto-commit changes
pull_request = true      # Auto-create PR
pull_request_draft = false  # Create PRs as drafts (only applies when pull_request = true)

# Worktree settings (for parallel sessions)
worktree = true               # Enable automatic worktree creation (default)
worktree_path_pattern = "{repo}-wt-{branch}"  # Worktree naming pattern
worktree_cleanup = false      # Remove worktrees after completion
```

**State persistence:** `~/.config/autom8/<project>/sessions/<session-id>/state.json`

## Claude Integration Notes

- Claude CLI subprocess spawning in `claude/runner.rs`
- Outputs newline-delimited JSON; parsed with stream parser (`claude/stream.rs`)
- Work summaries extracted from `<work-summary>` tags (max 500 chars) in `claude/utils.rs`
- Completion signals use `<promise>COMPLETE</promise>` tag
- Error info preserved with exit codes and stderr (`claude/types.rs`)

## Testing

Tests are in `#[cfg(test)]` blocks within modules. Focus areas:
- `runner.rs` - orchestration logic
- `spec.rs` - spec loading/saving

```bash
# Run all tests
cargo test --all-features

# Run specific module tests
cargo test spec::tests
cargo test runner::tests
```

## Code Style

- **Formatting:** `cargo fmt` (enforced by CI)
- **Linting:** `cargo clippy -- -D warnings` (zero warnings)
- **Imports:** Group std, external crates, then local modules
- **Error handling:** Return `Result<T, Autom8Error>`, use `?` operator
- **Documentation:** Doc comments for public API, inline for complex logic

## Common Tasks

### Adding a new CLI command
1. Add variant to `Commands` enum in `main.rs`
2. Create handler file in `commands/` (e.g., `commands/mycommand.rs`)
3. Add module declaration and re-export in `commands/mod.rs`
4. Call the handler from `main()` match statement

### Adding a new state
1. Add variant to `MachineState` enum in `state.rs`
2. Update state transition logic in `runner.rs`
3. Add display handling in `display.rs` and implementations

### Modifying Claude prompts
1. Edit prompts in `prompts.rs`
2. Prompts include detailed instructions and output format examples
3. Test with actual Claude CLI

### Adding display output
1. Add method to `DisplayAdapter` trait (`display.rs`)
2. Implement in `CliDisplay` (add function to appropriate `output/` submodule)
3. Implement in `TuiDisplay` (using `tui/app.rs`)

### Adding GUI features
1. Add shared types to `ui/shared/mod.rs` if needed by both GUI and TUI
2. Update `ui/gui/app.rs` for main application logic
3. Add reusable components to `ui/gui/components.rs`
4. Add colors/spacing to `ui/gui/theme.rs`
5. Add fonts to `ui/gui/typography.rs`
6. For modal dialogs, use `ui/gui/modal.rs`

## File Locations

- **Specs:** `~/.config/autom8/<project>/spec/spec-<feature>.json`
- **Session state:** `~/.config/autom8/<project>/sessions/<session-id>/state.json`
- **Session metadata:** `~/.config/autom8/<project>/sessions/<session-id>/metadata.json`
- **Archived runs:** `~/.config/autom8/<project>/runs/`
- **Global config:** `~/.config/autom8/config.toml`
- **Project config:** `~/.config/autom8/<project>/config.toml`
- **Worktrees:** `<repo-parent>/<repo>-wt-<branch>/` (when `worktree = true`)

## Dependencies (Key)

- `clap` - CLI parsing
- `serde`/`serde_json` - serialization
- `chrono` - datetime handling
- `thiserror` - error types
- `indicatif` - progress/spinners
- `ratatui`/`crossterm` - TUI
- `eframe`/`egui`/`egui_extras` - GUI framework
- `image` - image loading for GUI icons
- `toml` - config parsing

## CI/CD

- **test.yml:** Runs `cargo test --all-features`
- **lint.yml:** Runs `cargo fmt --check` and `cargo clippy`
- **release.yml:** Creates GitHub Release on tag

All checks must pass before merging PRs.

## Gotchas

1. **PR requires commit:** Config validation enforces `pull_request` requires `commit = true`
2. **TUI thread safety:** TUI uses `Arc<Mutex<TuiApp>>` for cross-thread access
3. **Output buffer limit:** TUI caps output at 1,000 lines to prevent memory growth
4. **GUI output clipping:** GUI uses hardware clipping (`painter.with_clip_rect()`) to constrain text within output display areas
5. **GUI output priority:** GUI follows TUI pattern: fresh live output > iteration snippet > status (5-second freshness threshold)
6. **State persistence:** Config snapshot saved at run start; resumed runs use same settings
7. **Branch handling:** Runner auto-creates/checkouts branches from spec's `branch_name`
8. **Branch conflicts:** Two sessions cannot use the same branch simultaneously; autom8 detects this and errors early
9. **Session identity:** In main repo, session ID is `"main"`; in worktrees, it's a hash of the path
10. **Stale sessions:** If a worktree is manually deleted, its session becomes "stale" and won't block new runs
11. **Project identity:** Project name is derived from git repo root, not CWD (ensures all worktrees share config)
12. **State persistence ordering:** In `run()` and `run_from_spec()`, state must NOT be persisted until after worktree context is determined. Saving state before `effective_state_manager` is known creates phantom sessions. Visual transitions (`print_state_transition()`) are fine; only `save()` calls must be deferred.

## Worktree Architecture

autom8 supports running multiple parallel sessions for the same project using git worktrees. This enables concurrent implementation of multiple features.

### Session Identity

Each session is identified by a deterministic session ID:
- **Main repository**: Uses the well-known ID `"main"`
- **Worktrees**: Uses an 8-character hex hash of the worktree's absolute path

Session IDs are filesystem-safe and stable (same path always produces the same ID).

### Directory Structure

```
~/.config/autom8/<project>/
├── config.toml                    # Project-level config
├── spec/                          # Spec files (shared across sessions)
│   └── spec-*.json
├── runs/                          # Archived runs (shared across sessions)
└── sessions/                      # Per-session state
    ├── main/                      # Main repo session
    │   ├── state.json             # Run state
    │   └── metadata.json          # Session metadata
    └── <session-id>/              # Worktree sessions
        ├── state.json
        └── metadata.json
```

### Worktree Modes

**When `worktree = true` (default):**
- Creates dedicated worktree at `<repo-parent>/<repo>-wt-<branch>/`
- Each worktree gets its own session with isolated state
- Multiple specs can run in parallel
- Worktrees can be auto-cleaned after successful completion (`worktree_cleanup = true`)

**When `worktree = false`:**
- Runs on current branch in main repository
- Single session per project
- State stored in `sessions/main/`

### Branch Conflict Detection

Before starting a run, autom8 checks if the branch is already in use:
1. Scans all session metadata files
2. Skips: own session, different branches, non-running sessions, stale sessions
3. Returns `BranchConflict` error if conflict found

A session is considered "stale" if its worktree path no longer exists.

### Key Files

| File | Purpose |
|------|---------|
| `worktree.rs` | Git worktree operations and session ID generation |
| `state.rs` | SessionMetadata struct, StateManager with session support |
| `config.rs` | `worktree`, `worktree_path_pattern`, `worktree_cleanup` fields |
| `runner.rs` | Worktree context setup and lifecycle management |

### Common Worktree Operations

```bash
# Run with worktree mode enabled (CLI override)
autom8 run --worktree --spec spec.json

# Check all sessions for current project
autom8 status --all

# Resume a specific session by ID
autom8 resume --session <id>

# List resumable sessions
autom8 resume --list

# Clean up completed sessions (preserves worktrees)
autom8 clean

# Clean up sessions and their worktrees
autom8 clean --worktrees

# Remove orphaned sessions (worktree deleted but state remains)
autom8 clean --orphaned
```

## Module Exports

`lib.rs` re-exports all public modules. When adding new modules:
1. Declare in `lib.rs`: `pub mod new_module;`
2. Re-export as needed: `pub use new_module::Type;`