Bench Folder

A benchmark is a folder. Four directories, one config, and every one of them means exactly one thing.

my-bench/
├── .bench/             # generated types, run logs, materialized workspaces
├── fixtures/           # author-side inputs — never visible to the agent
├── tests/              # the scenarios
   └── fix-bug.bench.ts
├── workspace/          # the agent's world — copied fresh for every run
├── bench.config.ts     # what varies, and what is measured
├── package.json        # name, version, npm deps
└── README.md           # methodology and limitations

Two things are required: bench.config.ts and at least one file in tests/. A benchmark with no workspace runs against an empty world, which is fine for anything that does not need one.

The split that matters

workspace/ is what the agent sees. fixtures/ is what you see.

That is a guarantee, not a convention. The workspace is copied into a fresh directory for every single run, and the agent is booted with that copy as its root. Rubrics, expected outputs, judge prompts, and setup data live in fixtures/, where the subject cannot reach them.

If fixtures were visible to the agent, two things would break. A model could read the answer key. And a run would come to depend on the benchmark's own directory layout, which means it would stop being reproducible the moment someone reorganised the repo.

Where each concern lives

bench.config.ts declares what varies and what is measured. The matrix, the trial count, the measurement schema, the workspace policy. Data and one optional setup() hook — no scenario logic.

tests/ is what the agent has to do. Ordinary Bun test files, one scenario each. This is where Axon() is booted and where observations are recorded, and it is the file you spend your time in.

The split is the same one agents and cognets use: identity and behaviour never share a file. The config gives observations stable meaning; the tests produce them.

Naming

Test files match tests/**/*.bench.ts by default. The .bench.ts suffix keeps them distinct from the workspace's own test suite — which matters, because a coding benchmark's workspace usually contains real tests the agent is supposed to make pass, and those are data rather than scenarios.

Override the pattern when a benchmark wants a different layout:

export default defineBench<Schema>({
    tests: ["scenarios/**/*.ts"],
})

What is generated

.bench/ is written by axon bench prepare and holds the generated declarations, the extracted measurement schema, run logs, and any retained workspaces.

Commit the declarations; ignore the runs. A fresh scaffold does this for you:

.bench/runs/
.bench/workspace/

Scaffolding one

axon bench init my-bench

Creates the whole structure, ready to prepare. See Your First Benchmark for what to put in it.