autoresearch is a deliberately minimal, single-GPU LLM pretraining sandbox built by Andrej Karpathy as a derivative of nanochat. The whole point of the repo is to be edited autonomously by a coding agent (Claude Code, OpenAI Codex, or similar) running an overnight loop of: edit train.py, run a 5-minute experiment, keep or revert based on a single validation metric (val_bpb), and try the next idea.
This guide takes you from a fresh GPU box to a working autonomous research loop. It is intentionally short, because the codebase is intentionally short — two Python files (prepare.py, train.py), one markdown file (program.md) that programs the agent, plus an analysis notebook.
Important
autoresearchis a research toy. There are no model checkpoints, no multi-GPU support, no CLI flags on the training script, and no API. Every "knob" the agent touches is a module-level constant insidetrain.py. If you are looking for a production training framework, look elsewhere.
1. Quick Start
On any single-GPU NVIDIA Linux box with Python 3.10+ and uv installed, four commands stand the project up end-to-end:
git clone https://github.com/karpathy/autoresearch.git
cd autoresearch
uv sync
uv run prepare.py
uv run train.py
The first three commands fetch the repo and install dependencies (PyTorch 2.9.1 on the cu128 index, plus eight other packages). uv run prepare.py downloads 11 Parquet data shards from Hugging Face and trains a BPE tokenizer (~40 s). uv run train.py then trains an 80M-parameter GPT for exactly 5 minutes of steady-state wall-clock time and prints a summary.
Expected tail of the final run:
---
val_bpb: 0.997900
training_seconds: 300.1
total_seconds: 325.9
peak_vram_mb: 45060.2
mfu_percent: 39.80
total_tokens_M: 499.6
num_steps: 953
num_params_M: 50.3
depth: 8
If you see a val_bpb: line at the end, the rig works and you can hand the project off to an autonomous agent (see Section 4).
Tip
The fastest way to confirm a fresh setup is healthy is to run
uv run prepare.py --num-shards 2first. That downloads only the two shards needed to train the tokenizer (~30 s of network), proves your toolchain works, and gives the training run something to read. You can scale up to--num-shards 10afterwards.
Note
Every command in this guide is shown as
uv run <script>.py. That wrapper executes inside the project virtualenv automatically. If you prefer, you cansource .venv/bin/activateonce and drop theuv runprefix.
2. Installation
2.1 Hardware and platform requirements
| Requirement | Detail |
|---|---|
| GPU | A single NVIDIA GPU, Hopper (H100/H200) or Ampere (A100, RTX 30/40 series). The script hardcodes torch.device("cuda"). |
| VRAM | ~44 GB peak at the default config. Smaller cards require batch-size cuts (Section 5.4). |
| Python | >= 3.10 (pinned in .python-version). |
| Disk | ~5 GB for the default 10 training shards plus the pinned validation shard. |
| Network | Outbound HTTPS to huggingface.co (data + FA3 kernels) and pytorch.org (wheels). |
Warning
There is no CPU, MPS, ROCm, or multi-GPU code path in this repository. Running on a Mac, AMD GPU, or Windows-without-CUDA will fail at
torch.cuda.get_device_capability()very early. Use one of the community forks listed in Section 5.5 instead of filing a bug.
2.2 Software stack
pyproject.toml pins the following minimums:
| Package | Minimum | Role |
|---|---|---|
torch |
2.9.1 |
Core framework, pinned (uses pytorch-cu128 index) |
kernels |
>= 0.11.7 |
Pulls Flash Attention 3 from Hugging Face Hub at startup |
pyarrow |
>= 21.0.0 |
Reads Parquet data shards |
tiktoken |
>= 0.11.0 |
Encoding used at runtime |
rustbpe |
>= 0.1.0 |
Trains the BPE tokenizer |
requests |
>= 2.32.0 |
Downloads data shards |
numpy |
>= 2.2.6 |
Numerics |
pandas |
>= 2.3.3 |
Used by analysis.ipynb |
matplotlib |
>= 3.10.8 |
Used by analysis.ipynb |
Important
The PyTorch wheel comes from the
pytorch-cu128index, which means your driver must support CUDA 12.8. Verify withnvidia-smibeforeuv sync. Older drivers will sync successfully but fail atimport torchduringprepare.py.
2.3 Install uv
macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
Windows (PowerShell)
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
Already installed
uv --version
2.4 Clone and install dependencies
git clone https://github.com/karpathy/autoresearch.git
cd autoresearch
uv sync
Expected output (abridged):
Resolved 47 packages in 1.24s
Prepared 9 packages in 3.2s
Installed 47 packages in 11s
uv sync reads pyproject.toml, resolves uv.lock, and creates .venv/ with the CUDA 12.8 PyTorch build.
2.5 Verify the GPU is visible
uv run python -c "import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))"
Expected output:
True NVIDIA H100 80GB HBM3
If this prints False, fix your CUDA driver before continuing — every later command depends on the GPU.
3. Configuration
autoresearch has no configuration files, no environment variables, and no CLI flags on train.py. Configuration lives in two places:
prepare.py— fixed constants that define the evaluation harness (treat as read-only).train.py— module-level hyperparameters near the bottom of the file (intended to be edited).
The agent edits train.py only. program.md (the agent prompt) declares prepare.py off-limits because it owns the metric.
3.1 The two CLI flags that exist (prepare.py only)
| Flag | Type | Default | Effect |
|---|---|---|---|
--num-shards |
int |
10 |
Number of training shards to download. -1 means all 6,542 shards. The validation shard (shard_06542.parquet) is always pinned and always downloaded in addition. |
--download-workers |
int |
8 |
Parallel download workers. Reduce for slow or rate-limited connections. |
3.2 Fixed constants in prepare.py (do not edit)
These are the evaluation harness. The agent's program.md rule set forbids touching them, because changing any of them silently invalidates comparisons across runs.
| Constant | Value | Role |
|---|---|---|
MAX_SEQ_LEN |
2048 |
Context length for both training and eval |
TIME_BUDGET |
300 |
Seconds of steady-state training per experiment |
EVAL_TOKENS |
40 * 524288 (≈21 M) |
Tokens scored by the final evaluate_bpb pass |
VAL_SHARD |
6542 |
Pinned validation shard index |
VOCAB_SIZE |
8192 |
BPE vocabulary, including 4 reserved special tokens |
BASE_URL |
https://huggingface.co/datasets/karpathy/climbmix-400b-shuffle/resolve/main |
Dataset source |
BOS_TOKEN |
<|reserved_0|> |
Beginning-of-sequence token used by the dataloader |
3.3 Hyperparameters in train.py (the knobs the agent turns)
These live in a single block under the comment # Hyperparameters (edit these directly, no CLI flags needed):
| Constant | Default | Effect |
|---|---|---|
DEPTH |
8 |
Number of transformer layers |
ASPECT_RATIO |
64 |
model_dim = DEPTH * ASPECT_RATIO, rounded to a multiple of HEAD_DIM |
HEAD_DIM |
128 |
Per-head dimension. n_head = model_dim // HEAD_DIM |
WINDOW_PATTERN |
"SSSL" |
Per-layer attention window pattern: L=full (2048), S=half (1024). The last layer is always overridden to L. |
TOTAL_BATCH_SIZE |
2**19 (524,288) |
Tokens per optimizer step |
DEVICE_BATCH_SIZE |
128 |
Per-device batch size; reduce on OOM |
EMBEDDING_LR |
0.6 |
AdamW LR for token + value embeddings |
UNEMBEDDING_LR |
0.004 |
AdamW LR for lm_head |
MATRIX_LR |
0.04 |
Muon LR for 2-D matrix params inside transformer blocks |
SCALAR_LR |
0.5 |
AdamW LR for per-layer scalars (x0_lambdas); resid_lambdas uses SCALAR_LR * 0.01 |
WEIGHT_DECAY |
0.2 |
Cautious weight decay for Muon; decays linearly to 0 over training |
ADAM_BETAS |
(0.8, 0.95) |
(beta1, beta2) for AdamW groups |
WARMUP_RATIO |
0.0 |
Fraction of TIME_BUDGET for LR warmup |
WARMDOWN_RATIO |
0.5 |
Fraction of TIME_BUDGET for linear LR cooldown |
FINAL_LR_FRAC |
0.0 |
Final-LR multiplier, relative to initial |
Note
Learning rates are tuned at
n_embd = 768(DEPTH=8,ASPECT_RATIO=64,HEAD_DIM=128). When you change model size,setup_optimizerrescales all AdamW LRs by(model_dim / 768) ** -0.5, and Muon's per-parameter step adds amax(1.0, rows / cols) ** 0.5factor. You generally do not need to compensate by hand.
Tip
Because every knob is a constant, every experiment is fully described by a
git diff. That is the design — it lets the agent (and you) read run history just by reading commit messages.
4. Core Usage
autoresearch runs in two modes:
- Manual — you run
uv run train.py, read the output, hand-edit constants, re-run. Useful for sanity checks. - Autonomous — you point an AI coding agent (Claude Code, OpenAI Codex) at
program.mdand let it iterate overnight.
The autonomous mode is what the project was built for; the manual mode is mostly a debugging tool.
4.1 One-time data and tokenizer prep
Before any training, you need data shards on disk and a trained tokenizer. Both are produced by prepare.py and cached in ~/.cache/autoresearch/:
uv run prepare.py
Default behaviour:
- Download 10 training shards plus
shard_06542.parquet(validation) fromkarpathy/climbmix-400b-shuffle. - Train a BPE tokenizer with
rustbpeon up to 1 GB of training text. - Convert merges into a
tiktoken.Encodingand pickle to~/.cache/autoresearch/tokenizer/tokenizer.pkl. - Compute and save a
token_bytes.ptlookup tensor used for theval_bpbmetric. - Run a tokenizer round-trip sanity check on
"Hello world! Numbers: 123. Unicode: 你好".
Expected output (trimmed):
Cache directory: /home/you/.cache/autoresearch
Data: downloading 11 shards (0 already exist)...
Downloaded shard_00000.parquet
...
Downloaded shard_06542.parquet
Data: 11/11 shards ready at /home/you/.cache/autoresearch/data
Tokenizer: training BPE tokenizer...
Tokenizer: trained in 38.2s, saved to /home/you/.cache/autoresearch/tokenizer/tokenizer.pkl
Tokenizer: building token_bytes lookup...
Tokenizer: saved token_bytes to /home/you/.cache/autoresearch/tokenizer/token_bytes.pt
Tokenizer: sanity check passed (vocab_size=8192)
Done! Ready to train.
Tip
prepare.pyis idempotent. Re-running it skips already-downloaded shards and skips tokenizer training if bothtokenizer.pklandtoken_bytes.ptalready exist. It is safe to re-run after a crash.
Important
tokenizer.pklandtoken_bytes.ptare a pair. If only one is present,prepare.pywill retrain from scratch. Do not delete just one — either keep both or wipe the whole~/.cache/autoresearch/tokenizer/directory.
4.2 Manual training run
After prepare.py succeeds, train manually with:
uv run train.py
The script:
- Loads the tokenizer from
~/.cache/autoresearch/tokenizer/. - Builds a GPT model from the
train.pyconstants (no CLI flags). - Compiles with
torch.compile(dynamic=False)— the first ~10 steps are excluded from the timing budget. - Trains for exactly
TIME_BUDGET = 300seconds of steady-state wall-clock. - Runs
evaluate_bpboverEVAL_TOKENSof the pinned validation shard. - Prints a final summary block.
A typical streaming log:
Vocab size: 8,192
Model config: {'sequence_len': 2048, 'vocab_size': 8192, 'n_layer': 8, 'n_head': 6, 'n_kv_head': 6, 'n_embd': 768, 'window_pattern': 'SSSL'}
Parameter counts:
wte : 6,291,456
value_embeds : 25,165,824
lm_head : 6,291,456
transformer_matrices : 42,467,328
scalars : 16
total : 80,216,080
Estimated FLOPs per token: 6.03e+08
Scaling AdamW LRs by 1/sqrt(768/768) = 1.000000
Time budget: 300s
Gradient accumulation steps: 2
step 00000 (0.0%) | loss: 9.123456 | lrm: 1.00 | dt: 1034ms | tok/sec: 507,123 | mfu: 39.8% | epoch: 1 | remaining: 300s
...
step 00953 (100.0%) | loss: 1.892100 | lrm: 0.00 | ...
---
val_bpb: 0.997900
...
Tip
Redirect the full log to a file with
uv run train.py > run.log 2>&1. Thengrep "^val_bpb:" run.logreads only the metric. This is exactly what the autonomous loop does so the streaming progress lines do not flood the agent's context.
4.3 Autonomous loop
In a checkout you do not mind being mutated, launch your coding agent with permissions disabled (so it can edit train.py and shell-execute without prompting), then say something like:
Hi, have a look at program.md and let's kick off a new experiment! Let's do the setup first.
The agent will read program.md, agree on a run tag (e.g. mar5), create a branch autoresearch/mar5, verify data exists, and start looping. Each loop iteration:
- Inspect git state.
- Edit
train.pywith one experimental idea. git committhe change.uv run train.py > run.log 2>&1.grep "^val_bpb:\|^peak_vram_mb:" run.logto read metrics.- Append a row to
results.tsv(kept untracked). - If
val_bpbimproved (lower is better), advance the branch. Otherwisegit resetand try the next idea.
Expected throughput on an H100: roughly 12 experiments per hour, or about 100 experiments per 8-hour overnight session.
Important
program.mdinstructs the agent never to pause for confirmation once the loop starts. To stop, kill the agent process — it will not stop on its own. This is intentional, so you can leave it running unattended overnight.
Caution
The agent is given autonomous write access to the working tree and shell. It runs
git resetregularly and editstrain.pyfreely. Only run it inside a checkout you are willing to lose. Never aim it at a branch with work you care about.
4.4 The program.md "skill file"
program.md is the human-editable programming surface for the agent. The default program.md shipped with the repo is a minimal baseline — one agent, one loop, one metric. Typical evolutions:
- Tell the agent to focus on a specific region of the search space first.
- Add minimum-improvement thresholds before keeping a change.
- Constrain edits to architecture-only or optimizer-only.
- Spawn parallel agents on different branches (
autoresearch/mar5-gpu0,autoresearch/mar5-gpu1, …) with differentprogram.mdstrategies per GPU.
Note
program.mdis part of the repo. If you change it, commit the change so future runs are reproducible. It is the only file other thantrain.pythat meaningfully drives experimental behaviour.
5. Common Tasks
5.1 Smoke-test a fresh install
uv run prepare.py --num-shards 2
uv run train.py > run.log 2>&1
grep "^val_bpb:" run.log
The smaller --num-shards 2 value still satisfies the len(parquet_files) >= 2 precondition for tokenizer training and shaves several minutes off the first prep. Expected output:
val_bpb: 0.997900
(The exact number depends on your hardware. On slower GPUs you fit fewer steps in 300 s, so val_bpb will be higher.)
5.2 Resume a crashed agent loop
If your agent process exited or was killed mid-experiment on branch autoresearch/mar5:
git checkout autoresearch/mar5
# Restart your agent and re-prompt it with program.md.
results.tsv is intentionally untracked, so it survives git reset/git checkout and your historical log is preserved across restarts.
5.3 Start a fresh tagged run
The branch name autoresearch/<tag> must not already exist. Pick a new tag:
git checkout master
git pull
# Prompt the agent with a new tag, e.g. "mar5b" or "mar5-v2".
5.4 Tune for smaller GPUs
The default config peaks at ~44 GB VRAM. To run on a 12/16/24 GB card:
| Knob | File | Default | Try |
|---|---|---|---|
DEPTH |
train.py |
8 |
4 or 2 |
DEVICE_BATCH_SIZE |
train.py |
128 |
Step down until OOM clears, then back up |
TOTAL_BATCH_SIZE |
train.py |
2**19 |
2**14 or lower (must remain a multiple of DEVICE_BATCH_SIZE * MAX_SEQ_LEN) |
WINDOW_PATTERN |
train.py |
"SSSL" |
"L" for short sequences |
MAX_SEQ_LEN |
prepare.py |
2048 |
512 or 256 (forces full re-prep) |
VOCAB_SIZE |
prepare.py |
8192 |
4096 or smaller (forces full re-prep) |
EVAL_TOKENS |
prepare.py |
40 * 524288 |
Reduce 10–100× so eval finishes quickly |
Warning
Reducing
MAX_SEQ_LENorVOCAB_SIZErequires editingprepare.py, whichprogram.mddeclares off-limits to the agent. Do these edits yourself, manually, before starting the agent. After editingprepare.py, wipe~/.cache/autoresearch/tokenizer/so the new vocab size is rebuilt.
5.5 Switch to a community fork for non-CUDA hardware
The README lists these forks for hardware the upstream repo does not support:
| Fork | Target |
|---|---|
miolini/autoresearch-macos |
macOS |
trevin-creator/autoresearch-mlx |
macOS (MLX backend) |
jsegov/autoresearch-win-rtx |
Windows (consumer RTX) |
andyluo7/autoresearch |
AMD |
There is also an open request (#519) to recognize an Ascend-compatible fork in the README's notable-forks list.
5.6 Compare two experiment branches
Each autoresearch/<tag> branch carries its own untracked results.tsv. To diff them, copy out before switching:
git checkout autoresearch/mar5
cp results.tsv /tmp/mar5.tsv
git checkout autoresearch/mar5b
cp results.tsv /tmp/mar5b.tsv
diff /tmp/mar5.tsv /tmp/mar5b.tsv
For a richer comparison, use analysis.ipynb — pandas and matplotlib are already in the environment from uv sync.
6. Troubleshooting
The training loop prints progress on a single carriage-returning line, so failures usually surface either as a Python traceback or as the literal string FAIL. Below are the failure modes confirmed in the source.
Error: torch.cuda.is_available() returns False
Cause: PyTorch cannot see a CUDA device. Either no GPU is attached, the NVIDIA driver is missing, or the driver is older than what the pinned torch==2.9.1+cu128 wheel requires.
Solution: Install or update the NVIDIA driver. Verify with nvidia-smi. Do not downgrade PyTorch — the Muon and AdamW fused steps rely on torch.compile behaviour from a recent version.
Prevention: Keep your driver current. If you are on a shared cluster, check that CUDA_VISIBLE_DEVICES is not set to the empty string in your shell.
Error: kernel-loading failure inside kernels.get_kernel(...)
Cause: train.py picks varunneal/flash-attention-3 for Hopper ((9, 0)) and kernels-community/flash-attn3 for everything else. If neither builds for your GPU, the import fails.
Solution: Run nvidia-smi --query-gpu=compute_cap --format=csv,noheader. If it reports below sm_80 (Ampere), this repo cannot run on your hardware. Use a fork from Section 5.5 or switch GPUs.
Prevention: This repo targets H100 first, A100 second. Older datacenter GPUs (V100) and pre-Ampere consumer cards (RTX 20-series and earlier) are not supported.
Error: ValueError: Invalid input type: <class '...'>
Cause: Raised at prepare.py:241 (line numbers approximate). Your code called Tokenizer.encode(x) where x is neither str nor list. The dataloader passes lists, so this only appears in custom code that calls tokenizer.encode with a generator, numpy array, or similar.
Solution: Coerce to str or list[str] before passing.
Prevention: Stick to the documented input types.
Error: Tokenizer: need at least 2 data shards (1 train + 1 val). Download more data first.
Cause: prepare.py requires at least 2 parquet files to train. You ran --num-shards 0, or your downloads all failed.
Solution:
uv run prepare.py --num-shards 2
Prevention: Default --num-shards 10 already protects you. Avoid setting it below 2.
Error: AssertionError: No parquet files found. Run prepare.py first.
Cause: train.py opened a dataloader before any data was on disk.
Solution: Run uv run prepare.py before uv run train.py. Required after every fresh checkout or after wiping ~/.cache/autoresearch/.
Prevention: Always run prepare.py first on a new machine. The Quick Start in this guide does this.
Error: download retries exhausted; some shard_NNNNN.parquet files missing
Cause: download_single_shard retries 5 times with exponential backoff (2^attempt seconds — so 2, 4, 8, 16 s between attempts). Hugging Face rate limits or 5xx errors can exhaust those attempts. Issue #215 tracks hardening this further (e.g. checksumming the cached shards).
Solution: Re-run prepare.py; only missing shards are re-fetched. For large jobs, lower the worker count to avoid rate-limit triggers:
uv run prepare.py --num-shards 10 --download-workers 2
Prevention: Use --download-workers 2 for --num-shards -1 (full dataset).
Error: training prints FAIL and exits with code 1
Cause: A guard at the end of each step: if train_loss is NaN or greater than 100, the run prints FAIL and exits. Triggered by numerically unstable hyperparameters (LR far too high, broken normalization, etc.).
Solution: This is the intended behaviour in autonomous mode — the agent reads an empty val_bpb line, marks the experiment as crash, and git resets. If you are running manually, lower the offending LR or revert the change.
Prevention: Make small LR moves; reserve aggressive architecture changes for cases where the baseline is stable.
peak_vram_mb climbs across long runs
Cause: Python's GC is disabled after step 0 (gc.disable() in the training loop) to avoid GC-induced stalls, with a manual gc.collect() every 5,000 steps. At default config, 5-minute runs finish in ~1,000 steps so this never matters — but if you cut batch size dramatically you may run far more steps without ever hitting a manual GC.
Solution: Either raise DEVICE_BATCH_SIZE (fewer steps), or change the (step + 1) % 5000 == 0 condition in train.py to a smaller interval.
Prevention: Don't increase total step count by an order of magnitude without also tightening the manual GC schedule.
mfu_percent very low (< 20%) on H100
Cause: On H100 the expected MFU is roughly 40%. Much lower usually means the FA3 kernel didn't load and attention fell back to a slower path, or torch.compile is recompiling because of dynamic shapes the agent introduced.
Solution: Check the startup log for kernels lines indicating which FA3 backend loaded. If it failed, run uv sync --reinstall and retry. If torch.compile is recompiling repeatedly, find the agent commit that introduced dynamic shapes and revert.
Prevention: Keep tensor shapes static. The fused steps are decorated @torch.compile(dynamic=False, fullgraph=True); do not relax that.
Tokenizer hangs at the sanity-check assertion
Cause: The end of train_tokenizer() does enc.decode(enc.encode_ordinary("Hello world! Numbers: 123. Unicode: 你好")) == .... A hang there usually means rustbpe failed to link or tiktoken failed to import — not a real round-trip failure.
Solution: uv sync --reinstall.
Prevention: Don't mix pip install with uv sync in the same virtualenv.
Issue #35 — "Why not fixed FLOPs budget?"
Status: Open. The chosen design fixes wall-clock time rather than FLOPs, which means slower hardware sees fewer tokens and reaches a higher val_bpb than fast hardware on identical code. Discussion is in the upstream issue; the choice is intentional and tied to the autonomous-loop comparability story (Section 7 FAQ).
7. FAQ
Q: Can I run this on a MacBook or M-series chip?
Not directly. The code hardcodes torch.device("cuda") and Flash Attention 3. Use miolini/autoresearch-macos or trevin-creator/autoresearch-mlx.
Q: Can I run this on AMD?
Not directly. Use andyluo7/autoresearch.
Q: Can I run multiple GPUs?
No. The repo is explicitly single-GPU. The parent nanochat repo supports distributed training; use that if you need DDP/FSDP.
Q: Why is the training time hardcoded to 5 minutes?
So that every experiment uses the same wall-clock budget on a given machine. Tradeoffs between depth, batch size, and step count become directly comparable. The downside is that results are not directly comparable to other people on different hardware — but that is not the goal. The goal is to give an autonomous agent apples-to-apples decisions on your GPU.
Q: Why val_bpb and not val_loss?
Bits-per-byte is independent of vocabulary size. If the agent ever changed VOCAB_SIZE (which prepare.py rules out), cross-entropy in nats would no longer be a fair metric. BPB converts via loss / (ln(2) * total_bytes), which is comparable across tokenizer designs.
Q: Why is prepare.py off-limits to the agent?
Because it owns the metric. It defines evaluate_bpb, the pinned validation shard, and the fixed time budget. Letting the agent edit any of those is letting it improve the metric by changing the metric.
Q: Why does train.py have no CLI flags?
Because the agent's interaction model is "edit source, commit, run". CLI flags would be a second source of truth. Module-level constants mean git diff is the complete description of an experiment.
Q: Can I run two agents in parallel on one GPU?
Not recommended — they would contend for VRAM and torch.compile cache. The intended pattern is one agent per GPU. On a multi-GPU box, give each agent its own checkout (or git worktree) and its own branch tag.
Q: Where are model checkpoints saved?
They aren't. train.py trains for 5 minutes, evaluates, and exits. No checkpoints, no intermediate saves. The agent is optimizing a metric, not producing a deployable model.
Q: The dataset is 6,542 shards. Do I need all of it?
No. With the default 5-minute budget on H100 you process ~500M tokens, which is less than one shard's worth. --num-shards 10 is plenty of headroom. Use --num-shards -1 only when training a much larger model for much longer.
Q: Does the tokenizer need to be retrained per experiment?
No, and you can't — the tokenizer lives in prepare.py, which the agent cannot edit. The tokenizer is a fixed artifact of the eval harness; every experiment sees the same encoding.
Q: Can I commit results.tsv?
You can, but program.md asks the agent to keep it untracked so it survives git reset. If you want to share results, copy the file to a gist or a separate results repo.
Q: Is there a license?
README.md lists MIT at the bottom. Issue #523 (closed) and #395 (closed) tracked the request to add a separate LICENSE file — check the current repo state if you need a file-level licence artefact.
Q: What is WINDOW_PATTERN = "SSSL"?
A per-layer attention window pattern. L is full context (MAX_SEQ_LEN = 2048). S is half (1024). SSSL repeats across layers; the very last layer is always overridden to L so the final readout sees the full context. Changing this is one of the more impactful architecture knobs the agent can turn.
Q: Can the agent modify the optimizer?
Yes. The MuonAdamW class is defined inside train.py, so it is fair game. Optimizer changes are explicitly allowed by program.md.
Q: The agent keeps reverting crashed runs — is that normal?
Yes. Crashes (FAIL, OOM, Python exceptions) are logged with status=crash and reverted. It is only a bug if it happens on every run from the baseline, which means your environment is broken — re-do Section 2.
Q: How do I know my run actually hit the time budget?
Check training_seconds in the summary block. It should be very close to 300.0. Much less means the run exited early (usually FAIL). Much more is unreachable in normal flow because the loop exit condition is total_training_time >= TIME_BUDGET.
Q: Why are the first ~10 steps not counted?
The training loop guards if step > 10 before adding to total_training_time. torch.compile does graph capture and autotuning during those steps, which takes seconds. Excluding them keeps the measured "training time" reflective of steady state, not compilation.
8. Where to Look Next
For internals — how the model, optimizer, and dataloader actually work; how to scale the autonomous loop across multiple GPUs; security considerations for letting an agent edit your code overnight — see the companion karpathy__autoresearch__AdminGuide.md in this directory.