| name | evolve |
| description | Set up and run evolutionary code optimization. Use when asked to "run evolve", "evolutionary optimization", "genetic algorithm", or "explore hyperparameter combinations". |
Evolve Skill
Evolutionary code optimization using genetic algorithms. Explores combinations of ideas to find the best configuration.
Tools
evo_init โ configure session (name, train_command, ideas, metric, direction)
evo_next โ get next individual with genes to implement
evo_eval โ run benchmark, record result, auto-revert changes via git checkout
evo_rethink โ analyze results, add/remove ideas based on what's working
evo_status โ get current session state
evo_sessions โ list/switch sessions
Setup
- Understand the goal. Ask (or infer): What to optimize, which metric, files in scope.
- Create a branch.
git checkout -b evolve/<goal> โ keeps optimization work isolated.
- Read source files deeply. Understand the architecture. How does data flow? Where are the loops? What allocates?
- Profile. Run profiler to see WHERE time is spent. Don't guess.
- Form a hypothesis. Write: "This code is slow because..."
- Create
evo_bench.sh (see below). Must output METRIC name=value lines.
- Write
evo_session.md (see below). Include your hypothesis.
evo_init with ideas that ADDRESS your hypothesis.
- Loop:
evo_next โ implement genes โ evo_eval โ repeat until converged.
Proposing Ideas
The best ideas come from deep understanding, not from trying random variations.
Before proposing ideas:
- Read the source files
- Study the profiling data
- Reason about what the CPU is actually doing
- Write a hypothesis: "This code is slow because..."
Your ideas should address that hypothesis. Don't list "possible optimizations" โ propose changes that fix the root cause you identified.
Binary Ideas (on/off)
For specific changes:
{ name: "use_byteindex", description: "Replace StringScanner with String#byteindex for delimiter search" }
{ name: "cache_parsed_exprs", description: "Cache Expression.parse results keyed by markup string" }
Variant Ideas (discrete choices)
When comparing approaches or tuning parameters:
{ name: "tokenizer", variants: ["stringscanner", "byteindex", "regex_split"] }
{ name: "batch_size", variants: ["16", "64", "256"] }
What Makes a Good Idea
- Addresses your hypothesis โ not a random "this might help"
- Specific โ points to WHERE and WHAT to change
- Testable โ you'll know if it worked or not
What to Avoid
- Listing micro-optimizations because they're easy to think of
- Adding ideas "just in case" without understanding why they'd help
- Copying optimizations from other codebases without understanding if they apply
evo_bench.sh
Bash script (set -euo pipefail) that runs the benchmark and outputs structured metrics. Always create this โ don't rely on existing scripts that may not output parseable metrics.
#!/bin/bash
set -euo pipefail
echo "METRIC time_ms=1234.56"
echo "METRIC memory_mb=512"
Design principles:
- Fast pre-checks โ catch syntax errors in <1s before running full benchmark
- Stable measurements โ disable GC, run multiple iterations, report median
- Multiple metrics โ primary for optimization, secondary for monitoring
- Keep it fast โ every second is multiplied by dozens of evaluations
evo_session.md
Living document so a fresh agent can resume effectively:
# Evolve: <goal>
## Objective
<What we're optimizing and why.>
## Hypothesis
<"This code is slow because...">
## Profiler Findings
<Where is time actually spent? What's the bottleneck?>
## Metrics
- **Primary**: <name> (<unit>, lower/higher is better)
- **Secondary**: <other metrics for monitoring>
## How to Run
`./evo_bench.sh` โ outputs METRIC lines
## Files in Scope
<List files the agent may modify, with brief notes.>
## Off Limits
<What must NOT be touched.>
## What's Working
<Which ideas help? Why do they help?>
## Dead Ends
<What didn't work? WHY didn't it work?>
Update this document after evo_rethink calls to capture learnings.
Loop
evo_init โ creates population of individuals
Loop:
evo_next โ returns individual with genes to implement
(implement ONLY active genes based on descriptions)
evo_eval โ runs evo_bench.sh, records fitness, reverts via git checkout
Every N evals:
evo_rethink โ analyze what's working, refine hypothesis
Until converged:
evo_next โ "๐ฏ Converged! Best config: [genes]"
Gene Implementation
When evo_next returns:
Active (implement these):
- tokenizer = byteindex
_Replace StringScanner with String#byteindex for delimiter search_
- cache_parsed_exprs = ON
_Cache Expression.parse results keyed by markup string_
Inactive (do NOT implement):
~~batch_size~~ = off
Rules:
- Implement ONLY active genes
- For variant genes (
tokenizer = byteindex), implement that specific approach
- For binary genes (ON), implement the described optimization
- Do NOT implement inactive genes
Baseline
When evo_next returns baseline (all genes off):
- Do NOT modify any code
- Just call
evo_eval to measure unmodified performance
Rethink
Call evo_rethink periodically (tool will prompt you). This is the learning loop.
If Ideas Aren't Working
Don't just add more ideas at the same level. Ask:
-
Is my hypothesis wrong?
- Re-read the source files
- Re-run the profiler
- What did I miss?
-
Am I optimizing the wrong thing?
- Is the benchmark representative of production?
- Am I measuring what matters?
-
What would I need to change structurally to get 2x improvement?
- If small changes aren't helping, the architecture may be the bottleneck
- Try something structurally different
Commit Best & Accumulate Wins
When you've found a clear winner, commit it as the new baseline:
evo_rethink({ commit_best: true })
This:
- Shows you the winning genes to implement
- You implement them and
git commit
- This becomes the new baseline for the next era
- Future evals will revert to this commit (not the original)
- You can now propose ideas that build on the committed changes
Use this when:
- One idea dominates (e.g.,
dom_parse_skip gave +50%)
- You want to explore optimizations that depend on that change existing
- You're moving from one optimization level to the next
Don't Thrash
Repeatedly trying variations of the same idea? Stop. Think harder about root cause.
After Rethink
Update evo_session.md:
- Revise hypothesis if needed
- Document WHY things didn't work
- Record insights for future agents
Sessions
Multiple sessions supported:
evo_sessions({ action: "list" })
evo_sessions({ action: "switch", name: "other-session" })
Sessions stored in .pi/evolve/{session-name}/.
Convergence
Keep calling evo_next โ evo_eval until the system tells you to stop.
Don't call evo_stop because results "look good enough" โ let the algorithm determine convergence. evo_stop is for aborting, not finishing.
Evolution stops automatically when:
- No improvement for
convergence_evals evaluations (default: 31)
max_evaluations reached (if set)
When converged, evo_next will:
- Show the winning configuration with improvement percentage
- Save summary to
RESULTS.md
- Instruct you to implement and commit the winner
Then:
- Re-implement the winning genes
- Run tests to verify nothing broke
- Commit with the provided message
When NOT to Use Evolve
Evolve explores combinations of predefined ideas. It's NOT ideal for:
- Pure discovery โ when you don't know what's wrong yet (profile first, form hypothesis)
- Sequential rewrites โ where change B only makes sense after change A is committed (each eval reverts)
For those cases, do manual iterative exploration first, THEN use evolve to optimize within your chosen approach.