| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Name | Name | Last commit date | ||
|---|---|---|---|---|
An agent-agnostic, evaluator-driven outer loop for repeatedly improving a repository, prompt, workflow, generator, or other computable artifact with Claude Code, Codex CLI, Hermes, or any compatible headless CLI agent.
EvoFlow turns a one-shot coding agent into an experimental search process:
select a parent
-> create an isolated child branch and worktree
-> let a CLI agent modify the solution and its future improvement procedure
-> validate the result with an external evaluator
-> keep the candidate and its lineage in an archive
-> repeat
Important
EvoFlow is universal at the orchestration layer, not at the quality-definition layer. Every real use case still needs a task-specific evaluator that can tell the system whether one candidate is better than another.
Warning
EvoFlow executes untrusted, model-generated code and commands. Run unattended experiments only inside a disposable container or VM with restricted credentials, network access, CPU, memory, process count, and disk usage. The Python runner is not an operating-system sandbox.
npx skills add laruss/recursive-task-optimizerThe skills CLI installs the skill into whichever agents it detects - Claude Code, Codex, Cursor, Gemini CLI, OpenCode, and many others. Add -g to install at user level instead of into the current project:
npx skills add laruss/recursive-task-optimizer -gThe installed directory holds SKILL.md, references/, and scripts/evoflow.py. Point EVOFLOW at the runner and verify it:
export EVOFLOW="$HOME/.claude/skills/recursive-task-optimizer/scripts/evoflow.py"
python3 "$EVOFLOW" self-testInstallation is optional. The runner is a single dependency-free script, so a clone works just as well:
git clone https://github.com/laruss/recursive-task-optimizer
export EVOFLOW="$PWD/recursive-task-optimizer/skills/recursive-task-optimizer/scripts/evoflow.py"Every python3 "$EVOFLOW" ... command below assumes one of these two setups. See references/native-install.md for manual installation into a specific agent.
This project is an independent, constrained implementation inspired by the HyperAgents research project:
The paper introduces self-referential agents that combine task-solving behavior with a modifiable meta-level procedure for generating future improvements. It instantiates this idea as DGM-Hyperagents (DGM-H), which repeatedly selects parents, creates modified descendants, evaluates them, and accumulates an archive of useful stepping stones.
EvoFlow adapts those ideas to a portable CLI workflow. It is not a port, benchmark reproduction, or drop-in replacement for the official HyperAgents repository. No source files from the upstream repository are included here.
This repository has two complementary layers:
The skill layer is optional at runtime. You can install the skill with the skills CLI, ask an agent to read SKILL.md, or call scripts/evoflow.py directly.
Think of EvoFlow as an automated research laboratory:
A normal retry loop asks an agent to improve the same result again and again. EvoFlow also lets descendants improve the procedure used to generate later improvements, while retaining multiple branches instead of replacing everything with the latest attempt.
Each candidate inherits four things from its parent:
candidate repository
├── project files and artifacts
└── .hyperflow/genome/
├── TASK.md
├── META.md
└── MEMORY.md
The agent can modify the actual solution: source code, prompts, templates, orchestration logic, configuration, tests, documentation generators, or other allowed files.
The agent can rewrite META.md. The runner loads this file into the prompt used to create future descendants. A better META.md can change how later generations:
This is the practical metacognitive part of EvoFlow: the candidate can improve not only the solution, but also the inherited procedure that produces subsequent candidates.
MEMORY.md carries concise, reusable findings across descendants. Full logs and metrics stay in the immutable run archive, so memory does not need to grow without bound.
Valid lower-scoring candidates are not automatically discarded. They remain available as alternative stepping stones. Parent selection can therefore branch from earlier candidates rather than following one greedy chain forever.
flowchart TB
O[Stable objective and run configuration]
A[Candidate archive]
S[Parent selection]
W[Disposable Git worktree and child branch]
subgraph C[Mutable candidate]
R[Solution files]
T[TASK.md]
M[META.md]
D[MEMORY.md]
end
G[CLI mutation agent]
P[Protected-path and size checks]
Q[Optional gate: tests, lint, typecheck]
E[External validation evaluator]
H[Immutable logs, metrics, lineage, and report]
O --> S
A --> S
S --> W
W --> C
C --> G
G --> C
C --> P
P --> Q
Q --> E
E --> H
H --> A
The mutable candidate and the trusted outer loop are intentionally separated.
Subject to your allow-list and limits, a candidate can modify:
The following control surfaces are protected from candidate modification:
.hyperflow/config.toml
.hyperflow/evaluator.py
.hyperflow/state/**
.hyperflow/runtime/**
Additional paths can be protected in the configuration. The evaluator, archive, selection policy, safety rules, and held-out test remain outside the candidate's control.
This is a deliberate difference from a fully self-referential research system. EvoFlow keeps the operational boundary fixed so runs are easier to audit, compare, reproduce, and execute with different CLI providers.
EvoFlow works best when the work can be represented as repository changes and evaluated repeatedly.
Examples include:
For repeated agent work, the target should be the procedure that handles a class of inputs, not one hand-picked answer. For example, optimize a report generator over 50 validation cases rather than optimizing one report until a judge likes it.
Use EvoFlow when all of the following are true:
It is usually a poor fit when:
The EvoFlow runner itself has no third-party Python dependencies.
python3 "$EVOFLOW" self-testThe self-test creates an isolated temporary repository, evaluates a seed, generates several descendants with a mock agent, resumes the run, executes a final test, and exports the best patch.
Choose an adapter preset:
python3 "$EVOFLOW" init \
--project /path/to/target-repository \
--adapter claudeAvailable presets:
claude
codex
hermes
generic
Initialization creates:
.hyperflow/
├── config.toml
├── evaluator.py
└── genome/
├── TASK.md
├── META.md
└── MEMORY.md
Edit these files before the first run:
.hyperflow/config.toml
.hyperflow/genome/TASK.md
.hyperflow/evaluator.py
Replace the evaluator placeholder and remove the HYPERFLOW_EVALUATOR_TODO marker.
Run the project in a disposable environment. Restrict credentials, network access, CPU, memory, process count, disk usage, and writable mounts.
Only after doing that, set:
[safety]
acknowledge_untrusted_code = true
allow_network = falseallow_network = false is a policy signal included in the agent prompt. It does not create a firewall. Enforce network restrictions outside EvoFlow.
cd /path/to/target-repository
git add .hyperflow .gitignore
git commit -m "chore: configure EvoFlow"EvoFlow requires a clean working tree before starting or resuming a run.
python3 "$EVOFLOW" doctor \
--project /path/to/target-repository
python3 "$EVOFLOW" run \
--project /path/to/target-repository \
--iterations 12python3 "$EVOFLOW" status \
--project /path/to/target-repository
python3 "$EVOFLOW" best \
--project /path/to/target-repository \
--jsonNo candidate is merged automatically. Review the branch, diff, logs, metrics, dependencies, and held-out performance before promotion.
The immutable run objective lives in .hyperflow/config.toml:
name = "parser-accuracy"
objective = """
Maximize parser correctness on the validation suite while preserving the public API,
keeping p95 latency below 50 ms, and introducing no new high-severity vulnerabilities.
"""
iterations = 20
seed = 42
selection = "score_child_prop"
higher_is_better = trueWrite the objective in terms of observable behavior. Avoid goals such as "make the project better" because the agent and evaluator cannot infer a stable optimization target from them.
The objective is snapshotted at run creation and remains fixed during resume. Start a new run when you change the objective, evaluator, agent command, or safety policy.
TASK.md describes the work contract visible to the mutation agent:
# Task contract
## Goal
Increase correctness on the parser validation set.
## Required deliverable
Modify the implementation and add legitimate regression tests when useful.
## Constraints
- Preserve the public API.
- Do not modify benchmark fixtures or the evaluator.
- Keep p95 latency below 50 ms.
- Avoid unrelated refactors.
## Validation notes
Validation reports correctness, timeout rate, and p95 latency.A candidate may clarify useful execution details in TASK.md, but it must not redefine the fixed objective to make the task easier.
META.md is the inherited mutation procedure. The default version tells descendants to inspect evidence, form one concrete hypothesis, make real changes, run checks, and update memory.
A later descendant might improve it with domain-specific strategy, for example:
1. Cluster failed validation cases by parser stage and error signature.
2. Select one high-frequency cluster that has not been attempted in the current lineage.
3. Reproduce it with the smallest local regression case.
4. Fix the root cause without special-casing validation file names or expected outputs.
5. Compare correctness and latency against the parent.
6. Record why the hypothesis worked or failed in MEMORY.md.Because descendants inherit the updated file, this change affects future search behavior rather than only the current patch.
Keep memory compact and durable:
# Durable lineage memory
- The tokenizer incorrectly treats escaped delimiters as separators.
- A regex-only fix improved simple cases but regressed nested input.
- The next useful direction is a stateful scan with a bounded allocation budget.Do not copy complete logs, prompts, or benchmark output into memory. Those already live in the run archive.
The evaluator is the center of the flow. If it measures the wrong thing, EvoFlow will efficiently optimize the wrong thing.
The evaluator command must write a JSON object to {result_file}:
{
"score": 0.934,
"metrics": {
"correctness": 0.97,
"p95_ms": 42.1,
"memory_mb": 118.0
},
"summary": "97/100 cases; p95 42.1 ms",
"eligible": true
}Rules:
A minimal evaluator can look like this:
#!/usr/bin/env python3
from __future__ import annotations
import argparse
import json
import subprocess
from pathlib import Path
def evaluate(workspace: Path) -> dict:
completed = subprocess.run(
["python3", "-m", "pytest", "-q"],
cwd=workspace,
text=True,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
timeout=300,
check=False,
)
passed = completed.returncode == 0
return {
"score": 1.0 if passed else 0.0,
"metrics": {"tests_passed": int(passed)},
"summary": "test suite passed" if passed else "test suite failed",
"eligible": passed,
}
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--workspace", required=True)
parser.add_argument("--output", required=True)
parser.add_argument("--mode", default="validation")
args = parser.parse_args()
payload = evaluate(Path(args.workspace).resolve())
output = Path(args.output).resolve()
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
if __name__ == "__main__":
main()For meaningful search, use a continuous or multi-level score when possible. A binary pass/fail signal gives the archive very little information.
Use gate_command for cheap binary prerequisites such as unit tests, lint, or type checking:
[evaluation]
gate_command = ["bash", "-lc", "npm test && npm run typecheck"]
gate_timeout_seconds = 900Use the evaluator for the richer comparison signal: correctness rate, latency, token use, cost, judge scores, robustness, or other domain metrics.
EvoFlow does not import a provider SDK. It launches an argv array in the candidate worktree and captures stdout, stderr, exit code, duration, and file changes.
The CLI must:
python3 "$EVOFLOW" init --project /path/to/project --adapter claudeThe generated preset uses non-interactive claude -p, stdin, explicit tools, and JSON output. Review the command against the version installed in your environment.
Claude Code documentation:
python3 "$EVOFLOW" init --project /path/to/project --adapter codexThe generated preset uses codex exec and instructs Codex to read the generated prompt file before editing the current repository.
Codex documentation:
python3 "$EVOFLOW" init --project /path/to/project --adapter hermesThe generated preset uses Hermes non-interactively with a query file. Review any automatic-approval option carefully and run it only inside a sandbox.
Hermes documentation:
Use the generic adapter and configure an argv array:
[agent]
adapter = "generic"
prompt_mode = "file"
command = [
"my-agent",
"run",
"--non-interactive",
"--prompt-file", "{prompt_file}"
]
timeout_seconds = 3600
require_zero_exit = true
inherit_environment = false
pass_env = ["MY_AGENT_API_KEY"]Or send the complete prompt through stdin:
[agent]
adapter = "generic"
prompt_mode = "stdin"
command = ["my-agent", "--non-interactive"]Available placeholders include:
{prompt_file}
{workspace}
{candidate_id}
{parent_id}
{run_dir}
{project}
{mode}
Prefer argv arrays over shell interpolation. If a shell is unavoidable, invoke it explicitly and keep all interpolated input under your control.
An empty mutable list means every non-protected path may be changed:
[paths]
mutable = []For tighter experiments, use an allow-list:
[paths]
mutable = [
"src/**",
"tests/regression/**",
".hyperflow/genome/**"
]
protected = [
".hyperflow/config.toml",
".hyperflow/evaluator.py",
".hyperflow/state/**",
".hyperflow/runtime/**",
".gitignore"
]Also configure change budgets:
[limits]
max_changed_files = 50
max_diff_bytes = 500000
max_genome_bytes = 100000The runner checks the full diff relative to the parent commit, including commits created by the agent itself.
For generation g0007, EvoFlow performs the following sequence:
A failed generation is recorded for auditability. Failed branches are removed by default unless configured otherwise.
Configure selection in .hyperflow/config.toml:
selection = "score_child_prop"Available strategies:
Set higher_is_better = false for metrics that should be minimized, such as latency or error count.
Each run is stored under:
.hyperflow/state/runs/<run-id>/
├── manifest.json
├── config.snapshot.toml
├── archive.jsonl
├── report.md
├── prompts/
├── logs/
├── results/
└── final-tests/
Important artifacts:
The run configuration is snapshotted at creation. Resume uses the snapshot rather than silently adopting edited control files.
# Initialize control files
python3 "$EVOFLOW" init --project /path/to/project --adapter claude
# Validate configuration, Git state, evaluator, adapter, and safety prerequisites
python3 "$EVOFLOW" doctor --project /path/to/project
# Start a run
python3 "$EVOFLOW" run --project /path/to/project --iterations 12
# Resume an existing run to a total budget of 30 generations
python3 "$EVOFLOW" run \
--project /path/to/project \
--run-id <run-id> \
--resume \
--iterations 30
# Print the latest report
python3 "$EVOFLOW" status --project /path/to/project
# Show the best validation candidate
python3 "$EVOFLOW" best --project /path/to/project --json
# Export a binary-capable Git patch
python3 "$EVOFLOW" export \
--project /path/to/project \
--candidate best \
--output best.patch
# Run a private held-out evaluator
python3 "$EVOFLOW" final-test \
--project /path/to/project \
--candidate best \
--final-config /secure/final.toml
# Remove leftover worktrees
python3 "$EVOFLOW" clean --project /path/to/project
# Remove leftover worktrees and candidate branches for a run
python3 "$EVOFLOW" clean \
--project /path/to/project \
--run-id <run-id> \
--delete-branchesValidation feedback is used repeatedly during search, so candidates can overfit to it. Select the candidate using validation results, then run a private final evaluator exactly as a final check.
Keep the final evaluator and data outside the candidate repository:
# /secure/final.toml
[final]
command = [
"python3",
"/secure/private_final_evaluator.py",
"--workspace", "{workspace}",
"--output", "{result_file}",
"--mode", "test"
]
timeout_seconds = 3600Run it with:
python3 "$EVOFLOW" final-test \
--project /path/to/project \
--candidate best \
--final-config /secure/final.tomlFinal-test results are stored separately and are not fed back into parent selection. Do not continue the same search after inspecting private test feedback; doing so turns the private set into another validation set.
Native skill installation is optional. It improves discovery and lets an agent configure or operate EvoFlow using SKILL.md and the bundled references.
The skills CLI covers every supported agent in one command and is the recommended route:
npx skills add laruss/recursive-task-optimizer # into the current project
npx skills add laruss/recursive-task-optimizer -g # at user level
npx skills add laruss/recursive-task-optimizer -a codex # into one specific agentThe manual equivalents below copy the same directory by hand.
Project-local installation:
mkdir -p /path/to/project/.claude/skills
cp -R /path/to/recursive-task-optimizer/skills/recursive-task-optimizer \
/path/to/project/.claude/skills/recursive-task-optimizerUser-level installation:
mkdir -p ~/.claude/skills
cp -R /path/to/recursive-task-optimizer/skills/recursive-task-optimizer \
~/.claude/skills/recursive-task-optimizerInvoke it with natural language or:
/recursive-task-optimizer Configure an evaluator-driven loop for this repository using Claude Code.
export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
mkdir -p "$CODEX_HOME/skills"
cp -R /path/to/recursive-task-optimizer/skills/recursive-task-optimizer \
"$CODEX_HOME/skills/recursive-task-optimizer"Restart Codex after installation, then ask it to use the recursive-task-optimizer skill.
mkdir -p ~/.hermes/skills
cp -R /path/to/recursive-task-optimizer/skills/recursive-task-optimizer \
~/.hermes/skills/recursive-task-optimizer
hermes skills listInvoke it with:
hermes chat -q "/recursive-task-optimizer Configure EvoFlow for the current repository."Point the agent at the entrypoint explicitly:
Read /opt/recursive-task-optimizer/SKILL.md and use it to configure EvoFlow for the current repository.
Or skip the skill layer and run the Python runner directly.
EvoFlow provides application-level safeguards, not host isolation.
The runner provides:
The runner cannot reliably prevent:
For unattended runs:
Read references/safety.md before enabling unattended execution.
When optimizing an agent or generator, evaluate it over a set of cases:
validation cases
├── case-001
├── case-002
├── ...
└── case-100
For every case, run the candidate with the same model, tool policy, token budget, time limit, and environment. Aggregate success rate, cost, latency, tool errors, formatting correctness, or judge scores.
This evaluates the procedure, not one memorized output.
An LLM judge can be useful for writing, design, architecture, and other partially subjective tasks, but stabilize it:
EvoFlow carries over these high-level ideas from the paper and public repository:
EvoFlow intentionally differs in these ways:
These constraints trade some research openness for portability, reproducibility, and operational auditability.
recursive-task-optimizer/
├── README.md
├── LICENSE
├── NOTICE.md
├── agents/
│ └── openai.yaml
└── skills/
└── recursive-task-optimizer/ # the installable skill
├── SKILL.md
├── LICENSE
├── scripts/
│ ├── evoflow.py
│ └── mock_agent.py
└── references/
├── adapters.md
├── evaluator-contract.md
├── examples.md
├── native-install.md
├── protocol.md
├── research-basis.md
├── safety.md
└── setup.md
The main README is self-contained. More detailed references are bundled with the skill:
After changing the runner:
python3 -m py_compile skills/recursive-task-optimizer/scripts/*.py
python3 "$EVOFLOW" self-testThe self-test should finish with:
SELF-TEST PASSED
When comparing providers, create separate runs from the same base commit with the same objective, evaluator, seed, generation budget, model budget, and isolation policy. Compare held-out performance, validation-to-test gap, cost, duration, failure rate, and lineage diversity rather than validation score alone.
When referring to the original research, cite the HyperAgents paper rather than this implementation:
@misc{zhang2026hyperagents,
title={Hyperagents},
author={Jenny Zhang and Bingchen Zhao and Wannan Yang and Jakob Foerster and Jeff Clune and Minqi Jiang and Sam Devlin and Tatiana Shavrina},
year={2026},
eprint={2603.19461},
archivePrefix={arXiv},
primaryClass={cs.AI},
url={https://arxiv.org/abs/2603.19461}
}Original sources:
The original EvoFlow code in this repository is provided under the MIT License.
The HyperAgents paper, official repository, datasets, models, trademarks, and related materials remain subject to their own terms. See NOTICE.md and references/research-basis.md.
| Back | FazBrowse Home | New Git URL |