All 30 experiments, one at a time
GPT-6 Astra made the code changes. The model being trained was a tiny language model that starts from scratch every run and only ever reads English children's stories. Each experiment changes one thing in train.py, trains for three minutes, then takes a test on stories the model hasn't seen. If it beats the best score so far, the change stays; if not, it's reverted. Tap a point to see what it tried and why.
Score lower is better
The score is val_bpb: how "surprised" the model is, on average, by each next bit of those unseen stories. Lower means it guesses better, and what it writes makes more sense.
So this isn't an AI improving itself. GPT-6 Astra didn't change at all. What changed was the tiny model's training recipe, inside a test and a three-minute limit that Karpathy and I set. The biggest win was experiment 2. The original fed 524K tokens into every training step, a setting sized for an H100; on my card that left time for only 40 updates in three minutes. It shrank that number and the score halved on the spot, which is probably the first thing anyone who knows this code would have tried. The other 28 experiments together took off another 0.056.
After that, be careful. Experiments 17, 25 and 26 each improved the score by less than 0.0005, but when it reran its best version unchanged at the end, the score moved by 0.0015 (hit "Zoom in": the blue band is that gap). Those three wins may well be luck, and its own summary says as much: these single-run rankings "should be treated cautiously".
Same opening, before and after
I trained the code from experiment 1 (unchanged) and experiment 26 (the best) for three minutes each, gave both the same opening line and let them keep writing. Two openings, four random seeds each: all 16 samples are here. Each stops at 110 tokens, so most end mid-sentence. Character names are highlighted.
The "before" model turns "she" into "he" halfway through a sentence and fits five or six names into one paragraph. The "after" model sticks with one main character, and the story holds together.
Can I run this on my own PC?
Yes, if you have an NVIDIA GPU. I used the Windows GPU fork of autoresearch. There are community versions for Mac and AMD too, listed in Karpathy's original repo; I haven't tried those. Here's what this run actually took:
- GPU
- RTX 5070 Ti, 16 GB. Memory peaked at 8.2 GB across the 30 experiments; the best version used 7.2 GB.
- Setup
- Install uv and PyTorch, download TinyStories (2.73 million English children's stories, about 670 MB) and train a tokenizer. Ten to fifteen minutes.
- Per experiment
- Three minutes of training plus startup and the test: about 3 min 40 s each (the first one took 5½). All 30 took 118 minutes.
- Researcher
- GPT-6 Astra in Codex, reasoning effort max. I didn't step in once between the start and its final summary.
- Tokens
- 23.3M read, 59K written. At OpenAI's API prices, about $27.
Almost all of that money goes on rereading. Every time it checks a training log, it reads the whole conversation again from the top, so 99.4% of those 23.3 million tokens were cache hits, and at $1 per million they make up $23 of the total. What it actually wrote was 59K tokens, under $3. The same token counts at GPT-6.1 Sol's prices would come to a little over $3, though I haven't run this with Sol and can't say how many tokens it would need. If you sign in to Codex with a ChatGPT account, all of it counts toward your plan's usage instead.
Mia's tips
- The original program.md has the agent do the setup together with you, and it literally says "NEVER STOP". To leave it running on its own, say so in your prompt: do the setup yourself, and stop after this many experiments or this many minutes. I gave it 30 experiments or 150 minutes, and it hit 30 at minute 118.
- I cut each training run from 5 minutes to 3, in
TIME_BUDGETin prepare.py (a file the researcher isn't allowed to touch). With the original setting, each experiment took over six minutes on a home GPU once you add the test; at three minutes, two hours fits exactly 30. - On Windows, Codex runs its commands in PowerShell. One line in the prompt ("use Select-String instead of grep, Get-Content -Tail instead of tail") saves it from figuring that out by trial and error.
- It has only ever read children's stories. Even the best version just writes a decent kids' story, so don't expect it to answer questions.
Using it on your own problem: what the score needs
Nothing about the loop is specific to language models: change one thing, run it, check the score, keep or revert. People are already pointing it at cold emails and circuit parameters. Whether it works for your problem comes down to the score. Mine had these properties, and losing any one of them causes trouble:
- One number, computed by a machine. Here, val_bpb. If a person has to look at each result and judge it, the loop can't turn.
- A result every few minutes. Three minutes of training and under a minute of testing: 30 runs in two hours. If it takes days to find out whether a change helped (did anyone reply to that email?), you get one try a night and the loop stops making sense.
- It can't touch the test. The test lives in prepare.py, the rules forbid editing it, and at the end it checked for itself that the evaluation code still matched the original. The test stories weren't in its training data either. If the test can be edited, or the questions have been seen before, the cheapest "improvement" is memorizing the answers. It's exactly what goes wrong with AI leaderboards.
- Know how much the score wobbles on its own. Running the same code twice moved it by 0.0015. A gain smaller than that needs several runs before you believe it.
- Write down everything else you care about. It only watches the one number. The original rules say memory may grow a little but shouldn't blow up, and that for the same score, simpler code wins. For your problem, the speed, size or features you can't lose belong in program.md too, or it will trade them away for points.
One more thing: it changes one thing at a time and keeps only what helps, feeling its way downhill one step at a time. Gains that only show up when several things change together are easy to miss that way. Its own summary says that with more time it would tune the batch size and learning rate together, and rerun the leading setups with a few different seeds.
The prompt and the full log
The researcher first reads program.md from Karpathy's original repo (its rulebook, which I left alone). The only other thing I gave it is below: do the setup yourself, keep notes on every experiment, stop at the limit. Copy it as is, then change the branch name and the Windows lines to fit your machine.
The instructions I gave the researcher
You are an autonomous machine-learning researcher. This folder is Karpathy's "autoresearch" setup (Windows RTX fork). Read program.md (your rulebook), README.md, prepare.py and train.py first. The human is away. Do the setup yourself without asking anything: - Create and switch to a new git branch `autoresearch/oct27` from the current HEAD. - The data and tokenizer are already prepared in the cache. Do not run prepare.py. - Create results.tsv with this header (tab-separated, 6 columns): commit val_bpb memory_gb status description finished_at (finished_at = local wall-clock time HH:MM when that experiment finished) - Create notes.md. After EVERY experiment append: `## <n>. <short title>` then 1-3 plain-English sentences: what you changed, why you expected it to help, and what happened (numbers). Then run the experiment loop exactly as program.md describes (first run = baseline, unchanged). Notes: - The time budget per run is 3 minutes of training (set in prepare.py, which you must NOT modify). Never touch prepare.py or the evaluation. - This machine is Windows. Use PowerShell equivalents (Select-String instead of grep, Get-Content -Tail instead of tail). Launch runs as `uv run train.py > run.log 2>&1`. - If a run takes longer than 8 minutes, kill it and treat it as a crash. - Do not install packages, do not touch anything outside this folder, no network access needed. Budget (hard stop, overrides "NEVER STOP" in program.md): stop after 30 experiments in total (baseline included) OR when 150 minutes have passed since you started, whichever comes first. Do not pause to ask questions before that. When you stop, make sure the branch tip is the best kept commit, and write summary.md: baseline val_bpb, best val_bpb, how many experiments (keep / discard / crash), the kept changes in order, and 3-5 sentences on what you learned and what you would try next with more time.
All 30 experiments in one table
| # | What it changed | Score | |
|---|---|---|---|
| 1 | Run it unchanged as the baselinebaseline unchanged | 1.0416 | Kept |
| 2 | Feed much less data per step (524K → 33K tokens)total batch 32768 tokens | 0.5250 | Kept |
| 3 | Faster attentionfull causal SDPA without explicit attention masks | 0.5051 | Kept |
| 4 | Turn off activation checkpointingdisable activation checkpointing | 0.4887 | Kept |
| 5 | Smaller model: 8 layers → 6depth 6 width 384 | 0.4761 | Kept |
| 6 | Even smaller: 4 layersdepth 4 width 256 | 0.5003 | Reverted |
| 7 | Halve the learning rate (0.04 → 0.02)matrix learning rate 0.02 | 0.4739 | Kept |
| 8 | Train on short passages (512 tokens)512-token training contexts with scaled device batches | 0.5457 | Reverted |
| 9 | Meet in the middle: 1024 tokens1024-token training contexts with scaled device batches | 0.4846 | Reverted |
| 10 | Halve the data per step againtotal batch 16384 tokens | 0.4789 | Reverted |
| 11 | Double the data per steptotal batch 65536 tokens | 0.4863 | Reverted |
| 12 | Remove the cap on the outputremove output logit softcap | 0.4721 | Kept |
| 13 | More, smaller attention headshead dimension 64 at unchanged width 384 | 0.4748 | Reverted |
| 14 | Keep 6 layers, make them narrowersix layers with width 256 | 0.4742 | Reverted |
| 15 | Same width, back to 8 layerseight layers at width 384 | 0.4818 | Reverted |
| 16 | Re-pick the batch size for the new modelarchitecture-specific runtime autotune cache | 0.4700 | Kept |
| 17 | Start lowering the learning rate earlierwarmdown ratio 0.8 | 0.4698 | Kept |
| 18 | Slower learning for word embeddings (0.6 → 0.2)embedding learning rate 0.2 | 0.4735 | Reverted |
| 19 | Double the output layer's learning rateoutput projection learning rate 0.008 | 0.4706 | Reverted |
| 20 | Halve it insteadoutput projection learning rate 0.002 | 0.4736 | Reverted |
| 21 | Remove weight decaymatrix weight decay 0.0 | 0.4746 | Reverted |
| 22 | Slimmer feed-forward layers (4× → 3×)MLP expansion ratio 3 instead of 4 | 0.4703 | Reverted |
| 23 | Remove query/key normalizationattention without query and key normalization | 0.4752 | Reverted |
| 24 | Turn off the extra value embeddingsdisable auxiliary value embeddings | 0.4776 | Reverted |
| 25 | Learning rate in between (0.03)matrix learning rate 0.03 | 0.4696 | Kept |
| 26 | More precise optimizer bookkeepingfloat32 AdamW moment buffers for all parameters | 0.4692 | Kept |
| 27 | Slower learning for the residual knobsresidual scalar learning rate 0.1 | 0.4718 | Reverted |
| 28 | Position encoding tuned for short rangeRoPE base 1000 | 0.4715 | Reverted |
| 29 | A smooth curve for the cooldowncosine instead of linear cooldown | 0.4742 | Reverted |
| 30 | Rerun the best version, unchangedconfirmation repeat of best kept configuration | 0.4707 | Reverted |














