A dead-simple, Codex-native autoresearch harness.
Let Codex optimize anything you can measure — settings, code, algorithms — by running an autonomous loop of propose → evaluate → judge → keep-or-discard.
./research examples/leduc_settings_tuning --max-turns 1
There are three approaches to autonomous LLM-driven optimization. Each makes different tradeoffs.
karpathy/autoresearch is the original idea: give an LLM a benchmark and tell it to make the number go down. The LLM does everything — proposes changes, runs the benchmark, decides whether to keep. Beautifully minimal. One conversation, one loop.
Strength: Zero setup. One prompt, one script, start optimizing.
Limitation: The LLM is judge and jury in its own case. No structured verdicts, no durable memory across context resets, no separation between the "try things" brain and the "decide if it worked" brain. When the context window fills up, you start over.
pi-autoresearch takes the Karpathy idea and adds real infrastructure: a pi extension with run_experiment / log_experiment tools, an autoresearch.jsonl log that survives restarts, a confidence scorer based on MAD, a live dashboard widget. The agent writes autoresearch.sh and loops autonomously.
Strength: Works for any optimization target in minutes. Confidence scoring catches noise. The agent-as-tool-user model is natural and fast for simple benchmarks.
Limitation: The same agent that proposes changes also decides whether to keep them. There's no schema-enforced verdict, no explicit acceptance basis, no structured hypothesis tracking. The benchmark script is agent-authored and agent-mutable. Memory is a markdown file the agent updates by hand. Works great for "make this test faster" — but when the evaluation costs real money, takes 10 minutes, or requires domain-specific judgment, you want more structure.
This repo takes a different architectural position: the LLM is a controlled subprocess, not the loop driver.
A Python runner orchestrates the loop. Each turn spawns two separate Codex CLI processes:
- Worker turn — Codex proposes changes and writes a structured hypothesis
- Judge turn — a separate Codex process evaluates the evidence and returns a schema-validated JSON verdict
The runner owns everything else: Git integration, evaluation, durable memory, winner advancement, and crash recovery.
| Karpathy | Pi autoresearch | codex-autoresearcher | |
|---|---|---|---|
| Who proposes | The LLM | The LLM agent | A spawned Codex worker process |
| Who judges | The same LLM | The same agent | A separate Codex judge process with a JSON schema |
| Who owns the loop | The LLM | The agent (via tools) | A Python runner (runner.py) |
| Verdict format | Prose | keep/discard flag | Schema-validated JSON with acceptance_basis |
| Hypothesis tracking | None | Markdown notes | Structured hypothesis.statement + hypothesis.reasoning per attempt |
| Evaluation | Agent-authored script | Agent-authored autoresearch.sh |
Human-authored static evaluate.sh |
| Memory | Context window | autoresearch.jsonl + markdown |
journal.jsonl + current_winner.json + per-attempt artifacts |
| Git integration | None | Auto-commit/revert | Runner-managed commits with worker-authored messages |
| Resume | Start over | Read markdown + jsonl | Deterministic from files; no prose needed |
| Multi-experiment | No | One per branch | Multiple isolated experiments per project |
| External projects | No | workingDir override |
git_repo_path + project_root with cross-repo context |
| Screening | No | Optional checks.sh |
Optional screen.sh as a fast pre-evaluation gate |
| Bug-fix keeps | Not a concept | Agent judgment | First-class: non_regression_bug_fix acceptance basis |
| Setup time | Minutes | Minutes | Longer — you author an experiment contract |
| Sweet spot | Quick experiments | Any measurable benchmark | Complex, expensive, or multi-metric optimization campaigns |
When to use which:
- Karpathy — You want to try something in 5 minutes and don't care about rigor
- Pi autoresearch — You want an autonomous loop with real tooling for straightforward benchmarks
- codex-autoresearcher — You want structured judgment, hypothesis tracking, durable forensics, and the ability to run expensive evaluations where the LLM shouldn't be trusted to judge its own work
One run looks like this:
- Load an experiment directory
- Require
current_winner_settings.yaml(fail loud if missing) - Require
git_repo_pathto be clean - Bootstrap
current_winner.jsonif missing by runningevaluate.sh - Compose a worker prompt from templates + experiment context + journal memory
- Spawn Codex as the worker — it edits files and writes
worker_turn.json - Optionally run
screen.shas a fast pre-evaluation gate - Run
evaluate.shto measure the candidate - Compose a judge prompt with all the evidence
- Spawn Codex as the judge — it returns a schema-validated JSON verdict
- On
keep: commit the changes, advance the winner - On
discard/crash: restore files from Git - Append the result to
journal.jsonl - Continue until stopped
git clone https://github.com/aelaguiz/codex-autoresearcher.git
cd codex-autoresearcher
uv syncThe example experiment needs its own Git repo for the harness to manage:
cd examples/leduc_settings_tuning
git init && git add . && git commit -m "initial state"
cd ../.../research examples/leduc_settings_tuning --max-turns 1./research examples/leduc_settings_tuning./research logs./research --tail-log examples/leduc_settings_tuningexamples/leduc_settings_tuning/
experiment.yaml # the experiment contract
goal_prompt.md # what Codex should optimize
judge_prompt.md # how success is judged
evaluate.sh # the static evaluator
current_winner_settings.yaml # current best settings
current_winner.json # measured result of the current winner
leduc_settings.yaml # the editable candidate settings file
journal.jsonl # append-only durable memory (runtime)
runner.log # human-readable event stream (runtime)
artifacts/ # per-attempt outputs (runtime)
experiment.yaml — Machine-readable contract: project root, Git repo, Codex settings, metrics, timeouts, writable surface, commands.
goal_prompt.md — Fills the "here is your goal" section of the worker prompt.
judge_prompt.md — Fills the "how success is judged" section of both worker and judge prompts.
evaluate.sh — The only evaluator. Static experiment infrastructure. Reads a settings file, writes metrics.json. Used for both current winner bootstrap and candidate evaluation.
current_winner_settings.yaml — Required. The settings that define the current best candidate.
current_winner.json — The measured result of the current winner. Bootstrapped automatically if missing.
journal.jsonl — Append-only durable attempt history. Survives across runs until you delete it.
runner.log — Human-readable live event stream. Not a source of truth.
version: 1
id: my_experiment
name: "My optimization experiment"
project_root: /path/to/your/project
git_repo_path: /path/to/your/project
codex:
bin: codex
profile: yolo
model: o4-mini
reasoning_effort: low
timeouts:
codex_turn_timeout_seconds: 900
evaluation_timeout_seconds: 180
objective:
primary_metric:
name: my_metric
direction: lower # or higher
secondary_metrics:
- name: other_metric
direction: higher
current_winner:
output: current_winner.json
settings_file: current_winner_settings.yaml
optimization_surface:
settings_files:
- /path/to/your/project/settings.yaml
levers_and_ideas:
- thread count
- algorithm selection
writable_paths:
- /path/to/your/project/settings.yaml
- /path/to/your/project/src/ # for code-editing experiments
commands:
screen: ./screen.sh # optional fast pre-check
evaluate: ./evaluate.shgit_repo_path— The Git repo owning the editable files. Must be clean before the runner starts.writable_paths— Explicit allowed mutation surface. Can include settings files, source directories, or both.timeouts— Required. No defaults. Both Codex turn and evaluation timeouts must be explicit.commands.screen— Optional. A fast pre-evaluation gate that can reject bad candidates cheaply.
# Current winner bootstrap:
./evaluate.sh current_winner_settings.yaml current_winner.json
# Candidate evaluation:
./evaluate.sh /path/to/candidate_settings.yaml artifacts/attempt_0007/metrics.json- Accept a settings file path as the first argument
- Accept an output JSON path as the second argument
- Write the output file with
primaryMetricandsecondaryMetrics - Exit
0on success, nonzero on failure
The judge returns schema-validated JSON with:
status:keep,discard, orcrashacceptance_basis:metric_improvement,non_regression_bug_fix,non_regression_code_quality,not_good_enough,metric_regression,evaluation_timeout,evaluation_failed,invalid_or_missing_evidencesummary: Short explanationprimary_metricandsecondary_metrics: The measured valuesconclusion: Hypothesis resolution with structured reasoning
The explicit acceptance_basis is what makes bug-fix keeps, code-quality keeps, and metric-improvement keeps all first-class — with no ambiguity about why a candidate was accepted.
- Create a new directory with the required files
- Point
project_rootandgit_repo_pathat your project - Write an
evaluate.shthat reads settings and produces metrics - Define the writable surface in
experiment.yaml - Write
goal_prompt.mdandjudge_prompt.md - Create
current_winner_settings.yamlwith your starting configuration - Run:
./research your_experiment_dir --max-turns 1
The shipped examples/leduc_settings_tuning/ is a complete working reference.
# The main command:
./research <experiment_dir> [--max-turns N]
# TTY → full-screen Textual UI
# Non-TTY → plain log lines to stdout- Stop: press
qin the UI, or Ctrl-C once for clean stop, twice for hard interrupt - Resume: just run the same command again — it picks up from durable files
--max-turns: for bounded testing; counts completed judged turns only
codex-autoresearcher/
src/codex_research/
cli.py # CLI entry point
runner.py # main loop orchestration
experiment.py # experiment loading and validation
codex_cli.py # Codex CLI process management
prompt_compose.py # prompt template filling
judge.py # judge verdict validation
journal.py # append-only memory
metrics.py # metric parsing
git_ops.py # Git commit/restore
dashboard.py # Textual terminal UI
live_logs.py # merged log streaming
schemas.py # typed data models
prompts/
work_prompt.md # worker turn template
judge_prompt.md # judge turn template
judge_verdict.schema.json
examples/
leduc_settings_tuning/ # complete working example
tests/
MIT