Self-improving evolution loop for any project, powered by Claude.
Point it at any git repo with a spec file → it reads the spec (by default
README.md, or any file via --spec), iteratively fixes bugs and implements
improvements one at a time, and stops when the project fully matches its spec.
Evolve runs an AGILE loop end-to-end: each round is a sprint that drafts
one user story, implements it, reviews it, and updates the backlog
(improvements.md) — incremental delivery with explicit acceptance criteria,
definition of done, and adversarial review at every step.
The role separation is propelled by the BMAD (Breakthrough Method for Agile-driven Development) persona model. Each phase of a round is run by a distinct named persona with its own mandate, prompt, and tool surface:
| Persona | Role | Phase |
|---|---|---|
| Winston | Architect | Drafts the technical pattern + integration points for a new US |
| John | Product Manager | Validates user value, priority, and explicit non-goals |
| Amelia | Developer | Implements the US — code, tests, COMMIT_MSG |
| Zara | Adversarial Reviewer | Four-pass attack on the round's diff (regression, AC, SPEC, drift) |
| Mira | Memory Curator | Triages memory.md between rounds (KEEP / ARCHIVE / DELETE) |
| Sid | SPEC Archivist | Extracts stable SPEC sections to SPEC/archive/ to keep SPEC.md lean |
Persona separation closes the self-assessment conflict of interest: the agent
that drafted a US is not the agent that reviews it, and the agent that
implements it is not the one that decides whether improvements.md should
mark it done. See agents/ for each persona definition and
SPEC.md § "Multi-call round architecture" for the orchestration
contract.
AGILE / BMAD describe how rounds are run. Two engineering practices describe how the code itself is shaped inside each round:
- TDD (Test-Driven Development). Every implement round (Amelia)
produces tests alongside the code change. The pre-check + post-check
gates around every round (
pytestby default, configurable via--check) make a passing test suite a hard precondition for round success — Phase 1 of the system prompt also forces the agent to fix any failing test before touching the round's nominal target. Coverage target: 95% acrossevolve/(see SPEC.md § "Test coverage target"). - DDD (Domain-Driven Design). Evolve's source tree under
evolve/follows a layered architecture (domain/,application/,infrastructure/,interfaces/) with bounded contexts (orchestration, authoring, memory & SPEC lifecycle, cost & budget, operator interface) and a ubiquitous language: every concept named inSPEC.md(Round, US, Improvement, Convergence, Memory, Backlog, Verdict, …) maps to a single named type inevolve/domain/. A CI-enforced import-graph linter rejects any inward-violating edge — same mechanism that enforces the 500-line-per-file cap. See SPEC.md § "Source code layout — Domain-Driven Design (DDD)" for the layout, dependency rule, and migration plan.
Together these four — AGILE, BMAD, TDD, DDD — give evolve its discipline: agile flow, BMAD roles, TDD correctness, DDD structure.
Looking for internals? This README is the user-facing guide — install, quickstart, examples. The full behavioral contract (phases, gates, convergence rules, every CLI flag in depth, memory discipline, retry continuity, frame capture, etc.) lives in SPEC.md. Evolve uses
SPEC.mdas its own convergence target.
Install evolve as a Python package:
pip install .The Rich TUI and frame-capture (cairosvg) are bundled by default —
no extras needed.
For development (adds pytest + pytest-cov):
pip install -e ".[dev]"After installation, the evolve command is available globally:
evolve start ~/projects/my-tool --check "pytest"You can also run directly without installing:
python -m evolve start ~/projects/my-tool --check "pytest"# Initialize a config file for your project
evolve init <project-dir>
# Evolve a project (README.md = spec by default, or use --spec)
evolve start <project-dir> [--rounds 10] [--check "pytest"] [--timeout 300] [--model claude-opus-4-6] [--allow-installs] [--json] [--spec SPEC.md]
# Preview what the agent would do (read-only, no file changes)
evolve start <project-dir> --dry-run [--check "pytest"]
# Validate spec compliance without evolving (pass/fail per spec claim)
evolve start <project-dir> --validate [--check "pytest"]
# Resume an interrupted session
evolve start <project-dir> --resume
# Autonomous forever mode (runs on a separate branch)
evolve start <project-dir> --forever [--check "pytest"]
# Check evolution status
evolve status <project-dir>
# Show evolution timeline across all sessions
evolve history <project-dir>
# Clean up old session directories
evolve clean <project-dir> [--keep 5]See SPEC.md for the full behavior of every flag.
# Evolve a Python project, verify with pytest
evolve start ~/projects/my-tool --check "pytest" --rounds 20
# Evolve a Node project, verify with npm test
evolve start ~/projects/my-app --check "npm test"
# Evolve a Rust project
evolve start ~/projects/my-cli --check "cargo test"
# Evolve without a check command (opus runs commands manually)
evolve start ~/projects/my-lib
# Allow installing new packages
evolve start ~/projects/my-tool --check "pytest" --allow-installs
# Use a different model
evolve start ~/projects/my-tool --check "pytest" --model claude-sonnet-4-20250514
# Dry run — see what the agent would change without modifying files
evolve start ~/projects/my-tool --check "pytest" --dry-run
# Validate — check spec compliance without modifying files
evolve start ~/projects/my-tool --check "pytest" --validate
# Resume after interruption (continues from last completed round)
evolve start ~/projects/my-tool --check "pytest" --resume
# Autonomous forever mode — evolves indefinitely on a separate branch
evolve start ~/projects/my-tool --check "pytest" --forever
# Fully autonomous forever mode — also allows installing new dependencies
evolve start ~/projects/my-tool --check "pytest" --forever --allow-installs
# JSON output for CI/CD pipelines
evolve start ~/projects/my-tool --check "pytest" --json
# Use a custom spec file instead of README.md
evolve start ~/projects/my-tool --check "pytest" --spec SPEC.md
evolve start ~/projects/my-tool --check "pytest" --spec docs/specification.md
# Initialize a config file with sensible defaults
evolve init ~/projects/my-tool
# Show evolution history across all sessions
evolve history ~/projects/my-tool
# Clean up old sessions, keeping the 5 most recent
evolve clean ~/projects/my-tool --keep 5
# CI/CD: run from project root and check the exit code
# (0 = converged, 1 = max rounds reached, 2 = error — see SPEC.md § Exit codes)
evolve start . --check "pytest" --rounds 20
if [ $? -eq 0 ]; then echo "Converged!"; fiEvolve supports project-level configuration via evolve.toml or
pyproject.toml. This eliminates the need to repeat CLI flags on every run.
Create an evolve.toml in your project root:
# evolve.toml
check = "pytest"
rounds = 20
timeout = 300
model = "claude-opus-4-6"
allow_installs = false # let the agent install new packages for [needs-package] items
spec = "README.md" # path to the spec file (default: README.md)
[hooks]
on_round_end = "echo 'Round complete'"
on_converged = "curl -s -X POST https://hooks.slack.com/services/YOUR/WEBHOOK/URL -d '{\"text\": \"evolve converged!\"}'"
on_error = "notify-send 'evolve encountered an error'"Or add an [tool.evolve] section to your existing pyproject.toml:
[tool.evolve]
check = "pytest"
rounds = 20
timeout = 300
[tool.evolve.hooks]
on_converged = "curl -s -X POST https://your-webhook-url"Settings resolve in this order (first wins): CLI flags → environment
variables → evolve.toml → pyproject.toml [tool.evolve] → defaults. Full
field list and semantics in
SPEC.md § Config resolution.
Every config field also has an environment-variable form (useful for CI
secrets and sandboxed shells). The most common one is EVOLVE_MODEL:
EVOLVE_MODEL=claude-sonnet-4-20250514 evolve start ~/projects/my-tool --check "pytest"Other env var examples — point at an alternate spec file via EVOLVE_SPEC:
EVOLVE_SPEC=SPEC.md evolve start ~/projects/my-tool --check "pytest"Allow the agent to install new packages via EVOLVE_ALLOW_INSTALLS (same
effect as the --allow-installs flag; unlocks [needs-package] items):
EVOLVE_ALLOW_INSTALLS=1 evolve start ~/projects/my-tool --check "pytest"Opt into TUI frame capture via EVOLVE_CAPTURE_FRAMES (same effect as
capture_frames = true in evolve.toml or --capture-frames; snapshots
the rendered TUI as PNGs into runs/<session>/frames/ for party-mode
visual context — see
SPEC.md § Frame capture):
EVOLVE_CAPTURE_FRAMES=1 evolve start ~/projects/my-tool --check "pytest"Hook commands (configured under [hooks] in evolve.toml, see example
above) receive runtime context via three environment variables that
evolve sets automatically before executing each hook: EVOLVE_SESSION
(the current session id, e.g. 20260324_160000), EVOLVE_ROUND (the
current round number), and EVOLVE_STATUS (the round outcome —
running, converged, error, etc.). Hooks can read them to emit
contextual notifications:
# evolve.toml
[hooks]
on_round_end = 'echo "Round $EVOLVE_ROUND of session $EVOLVE_SESSION: $EVOLVE_STATUS"'See SPEC.md § Hook execution for the full contract.
Scaffold a config file quickly:
evolve init ~/projects/my-tool
# Creates ~/projects/my-tool/evolve.toml with default settingsEvolve features a modern terminal UI powered by rich:
╭──────────────────── evolve ─────────────────────╮
│ EVOLUTION ROUND 3/10 │
│ TARGET: [functional] Add input validation │
│ PROGRESS: ██████░░░░ 5/9 improvements done │
╰─────────────────────────────────────────────────╯
[check] pytest ─────────────────────────────────
✓ 42 passed · 0 failed · 1.2s
[agent] Claude opus working...
[opus] Read → src/parser.py
[opus] Edit → src/parser.py (edit)
[opus] Bash → pytest tests/test_parser.py
[opus] Edit → runs/improvements.md (edit)
[verify] pytest ────────────────────────────────
✓ 43 passed · 0 failed · 1.3s
[git] feat(parser): add input validation → pushed
Progress: 6 done, 3 remaining
On completion:
╭──────────── Evolution Complete ─────────────╮
│ ✅ CONVERGED in 8 rounds (12m 34s) │
│ │
│ 6 improvements completed │
│ 2 bugs fixed │
│ 47 tests passing │
│ │
│ Report: runs/20260325/evolution_report.md │
╰──────────────────────────────────────────────╯
The TUI falls back to plain text when rich is not installed, and to
structured JSON events when --json is passed. It can optionally capture
visual frames (PNG) for party mode to reason about. Full details —
TUIProtocol, frame capture pipeline, JSON event schema — in
SPEC.md § TUI.
Evolve treats your spec file (README.md by default, or whatever --spec
points at) as the source of truth. The quality of your spec directly affects
how well evolve can converge your project. Guidelines:
# Good — evolve can verify this
"The CLI returns exit code 0 on success and exit code 1 on failure."
"Tests target 80% coverage minimum."
# Vague — evolve can't objectively verify this
"The CLI has good error handling."
"The code is well-tested."Evolve can literally run examples from your spec to verify they work:
# Good — testable commands
$ my-tool parse input.json --format csv
$ my-tool validate schema.json
# Vague — not testable
"my-tool supports various input formats"Architectural descriptions help the agent make consistent design decisions:
# Good — clear structure
| Module | Responsibility |
|--------|---------------|
| cli.py | Argument parsing, entry point |
| core.py | Business logic |
| io.py | File I/O, serialization |Explicit test targets give the agent a clear convergence criterion:
# Good — measurable
"The project targets 80% test coverage minimum."
"All public functions have type annotations and docstrings."The spec should describe what the project should be, not what it was. Update it when requirements change — evolve's spec freshness gate picks that up automatically on the next round and rebuilds the improvement backlog from the updated spec (see SPEC.md § Convergence).
Evolve projects tend to grow two audiences: users (need a friendly introduction) and the agent (needs a dense, exhaustive contract). When your README crosses ~800 lines, consider splitting:
README.md— user-facing docs, install, quickstart, examples, TUI previewSPEC.md— the formal contract; what evolve converges to
Run with --spec SPEC.md (or set spec = "SPEC.md" in evolve.toml).
Convergence becomes tractable because the agent only has to verify a stable,
scoped contract, not an ever-growing mix of docs and claims. Evolve itself
follows this pattern — see the SPEC.md in this repository.
- Python 3.10+
claude-agent-sdk:pip install claude-agent-sdkrich(optional):pip install rich— for the modern TUIcairosvg(optional):pip install ".[vision]"— for TUI frame capture- Git repository
- Claude Code CLI installed and authenticated
Evolve works with any Claude model supported by the Agent SDK. Recommended:
These are under consideration for future evolution cycles:
- Multi-repo evolution — evolve multiple related projects in coordination
- Spec drift detection — detect when code drifts from the spec over time and auto-fix
- Parallel analysis — run read-only analysis in parallel before sequential implementation
- GitHub App / hosted service — managed evolution service for teams
📖 For the full specification — every phase, every gate, every flag, the memory discipline, retry continuity, frame capture, party mode, CI/CD, exit codes, and the module architecture — see SPEC.md.

