Architecture
This document describes Ralph’s technical architecture. For detailed architectural decisions, see the ARCH.md file in the repository root.
Tech Stack
Language: Python 3.8+ (supports 3.8-3.12)
Testing: pytest with unittest
Build: setuptools (pyproject.toml)
Dependencies: pyyaml>=6.0
Agents: Claude CLI, GitHub Copilot CLI
External Tools: git, gh (GitHub CLI), tree
Overview
Ralph is an autonomous software development agent that iteratively builds projects through a three-phase loop:
Architect - Analyze structure
Planner - Create PRD with tasks
Execute - Implement and verify
State is persisted to .ralph/ directory for resumability, and each task is verified by running tests before marking complete. The system supports extensibility through hooks, custom templates, and plugin modules.
Architectural Patterns
Primary Pattern: Three-Phase Autonomous Agent Loop (Architect -> Planner -> Execute)
Supporting Patterns: - Repository (PRDManager) - Observer/Pub-Sub (HookManager) - Strategy (BaseAgent subclasses) - Factory (agent instantiation) - State Machine (task status transitions)
Key Components
Component |
Description |
|---|---|
|
Command-line argument parsing with 50+ options |
|
Core execution logic coordinating all phases |
|
Event system with 30+ lifecycle events |
|
Abstract BaseAgent class and AgentError dataclass |
|
ClaudeAgent implementation wrapping Claude CLI |
|
GithubAgent implementation wrapping Copilot CLI |
|
Config dataclass and CONF singleton for paths/limits |
|
Centralized Logger class with metaclass-based properties |
|
Shell class for safe subprocess execution |
|
PRDManager for PRD file operations with caching |
|
PromptFormatter and TemplateManager for prompt generation |
For detailed API documentation, see API Reference.
SOLID Principles Assessment
Principle |
Status |
Notes |
|---|---|---|
Single Responsibility |
Good |
Clear module boundaries; each class has focused purpose. Large modules (orchestrator.py, hooks.py) are documented as technical debt. |
Open/Closed |
Good |
BaseAgent allows extending with new agents without modifying existing code. Hook and template systems enable extensions. |
Liskov Substitution |
Good |
ClaudeAgent and GithubAgent implement BaseAgent interface identically; can substitute without client changes. |
Interface Segregation |
Good |
Minimal interfaces; BaseAgent exposes only essential abstract methods. Configuration uses focused dataclass. |
Dependency Inversion |
Good |
Logger and Config passed to agents via setters; modules depend on abstractions. No circular imports. |
API Boundaries & Integration Points
External Integrations
Claude CLI - LLM queries
GitHub Copilot CLI - LLM queries
GitHub CLI - Issue management
git - Version control
Internal Interfaces
BaseAgent - Agent abstraction
HookManager - Event system
PRDManager - PRD persistence
TemplateManager - Prompt templates
Data Formats
JSON - PRD, hook payloads
Markdown - Templates
YAML - Frontmatter
Protocols
CLI subprocess communication (stdin/stdout)
File-based state persistence
Error Handling & Logging
Error Strategy
Structured AgentError dataclass captures:
Exception type
Message
Stack trace
Timestamp
Agent name
Task ID
Features:
Retry with exponential backoff (configurable max retries)
Failed tasks marked as
failedbut execution continues
Logging Approach
Centralized Logger class with metaclass-based properties:
Console output (with color/emoji)
File output (ralph_log.txt)
JSON/NDJSON output modes
Log Levels
debug(10)info(20)warn(30)error(40)
Verbosity flags: -v (verbose), -vv (very verbose), -vvv (debug)
Security Considerations
Authentication
Delegates to CLI tools (claude, gh auth). No built-in auth mechanism.
Input Validation
Argparse for CLI args
JSON schema validation for PRD (optional)
UTF-8 encoding validation for files
Path traversal prevention via pathlib
Secrets Management
Environment variables for CLI tool configuration
Log redaction via
--redactpatternsNo hard-coded secrets
Potential Concerns
shell=Trueexecution risk (acceptable for local tool)Temp file exposure for Copilot prompts
Log files may contain sensitive data without access control
Testing Conventions
Layout
All tests live under tests/ with one file per feature/concern (e.g., test_orchestrator.py, test_cli_arguments.py). Place new cases in the file that matches the primary module under test; if none exists, create test_<feature>.py with a clear name.
Naming
Use test_<area>.py filenames, Test* classes, and test_* methods following pytest style. Prefer descriptive method names over comments.
Multi-Feature Tests
If a test spans multiple components, place it with the dominant behavior under test (usually the orchestrator or CLI). Reference shared helpers for setup and mocks.
Feedback and Updates
If the testing doc is unclear or gaps are found, open a GitHub issue titled [Testing Docs] <summary> and assign it to the current PRD branch owner/maintainer.