GitHub - r-via/evolve: Self-improving evolution loop for any project, powered by Claude. · GitHub
Skip to content
r-viaPublic

About

Self-improving evolution loop for any project, powered by Claude.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Repository files navigation

evolve logo

evolve

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.

Methodology — AGILE, propelled by BMAD

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.

Engineering practices — TDD and DDD

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 (pytest by 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% across evolve/ (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 in SPEC.md (Round, US, Improvement, Convergence, Memory, Backlog, Verdict, …) maps to a single named type in evolve/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.md as its own convergence target.

Installation

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"

Usage

# 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.

Examples

# 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!"; fi

Configuration

Evolve 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 settings

TUI preview

Evolve 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.

Writing specs for evolve

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:

Be specific and verifiable

# 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."

Include command examples

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"

Describe the architecture

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 |

State test expectations

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."

Keep it current

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).

Split user docs from the spec on large projects

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 preview
  • SPEC.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.

Requirements

  • Python 3.10+
  • claude-agent-sdk: pip install claude-agent-sdk
  • rich (optional): pip install rich — for the modern TUI
  • cairosvg (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:

Model Best for
claude-opus-4-6 (default) Maximum capability, complex projects
claude-sonnet-4-20250514 Faster iterations, simpler projects

Future directions

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.

Checked by Anatoly

About

Self-improving evolution loop for any project, powered by Claude.

Resources

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages