The test suite that checks whether memory carries over between sessions and between agents.
BrainBench is a test suite for agent memory. It replays scripted conversations against nexusbrain and checks four things: whether memory speaks up when it should, whether what it volunteers is relevant, whether facts from a conversation get stored correctly, and whether a decision made in one agent tool is remembered in another.
It runs on your machine in an in-memory database, with no API keys and no model calls, so every run of the same code gives the same numbers. Use it to check that a change did not make memory worse, or to grade your own conversations.
evals/brainbench/fixtures and evals/brainbench/gold, relative to the folder you run the command in. Otherwise pass --fixtures and --gold.A fixture is a scripted conversation, plus any pages and facts that should already be in memory. Its gold file, kept separately, records what should happen on each turn. Keeping gold separate means the code being tested never sees the answers.
Every fixture is replayed through each harness seam: openclaw, claude-code and codex. A seam is the point where memory is injected into an agent tool. openclaw rows are marked production because they use the shipped integration. claude-code and codex rows are marked contract because they test the same nexusbrain pieces through the shape that integration will use.
| Suite | Question it answers | Main metrics |
|---|---|---|
know-to-ask | Does memory surface on its own when it should, and stay quiet when it should not? | know_to_ask_failure_rate, false_fire_rate |
push | When memory volunteers context, is it the right context? | push_precision, push_recall |
write-back | Do facts from a conversation get stored, with correct provenance? | write_back_fidelity, provenance_accuracy |
continuity | Is a decision recorded in one harness recalled in another? | continuity_rate |
About 15% of fixtures are marked holdout: true. They are left out of normal runs so nobody can tune the code against them, and scored only when you pass --include-holdout.
nexusbrain eval brainbenchYou should seeA markdown scoreboard starting # BrainBench scoreboard, a line with the fixtures hash, holdout excluded (gate mode) and deterministic (hermetic), then one table row per harness and suite. The exit code is 0.
--harness and --suite take a comma-separated list or all.
nexusbrain eval brainbench --harness openclaw --suite know-to-ask,pushYou should seeThe same scoreboard with only the rows you asked for.
--out writes the full JSON result to a file. --json prints JSON on stdout instead of the scoreboard.
nexusbrain eval brainbench --json --out results/bb.jsonYou should see[eval brainbench] result written: results/bb.json on stderr, and a JSON object with receipt, cells, turn_rows, seed_failures and _meta.metric_glossary.
| Flag | What it does |
|---|---|
--fixtures DIR | Fixture folder. Default evals/brainbench/fixtures. |
--gold DIR | Gold folder. Default evals/brainbench/gold. |
--harness a,b | all | Harness seams to grade. Default all. |
--suite a,b | all | Suites to run. Default all. |
--include-holdout | Score holdout fixtures too. |
--json | Print the JSON result instead of the scoreboard. |
--out FILE | Write the full JSON result to a file. |
--compare BASE [CURRENT] | Gate against a saved baseline. With two files, compares them without running. |
--update-baseline [FILE] | Save this run as the baseline. Default evals/brainbench/baselines/main.json. |
--justification "reason" | Recorded in the baseline you write. Required when you accept a regression. |
--allow-regression "reason" | Let a single run pass despite a regression. The reason is recorded. |
--llm | Use the real model extractor in the write-back suite. Needs a configured chat model. |
--budget-usd N | Spend cap for --llm. Default 5. |
--seed N | Recorded in the receipt. Default 42. The run is deterministic, so nothing uses it yet. |
Each row is one harness and one suite. failed/gold shows how many gold items failed out of how many were checked. A metric that does not apply to that suite shows a dash. Rates run from 0 to 1.
| Metric | Meaning | Good direction |
|---|---|---|
know_to_ask_failure_rate | Of the turns where memory should have surfaced something unprompted, the share where nothing relevant was injected. | Lower |
false_fire_rate | Of the turns where memory should have stayed silent, the share where it injected anyway. | Lower |
push_precision | Of everything memory volunteered, the share that was relevant. Counted per injected pointer. | Higher |
push_recall | Of everything that should have been volunteered, the share that was. Pointer limits cap this on purpose. | Higher |
write_back_fidelity | Of the facts stated in a conversation, the share that survived the real storage pipeline and can be found with the right entity. | Higher |
provenance_accuracy | Of the stored facts, the share with the correct source tag, session id and origin page. | Higher |
continuity_rate | Of decisions recorded in one session, the share recalled when a different harness asks later. | Higher |
extraction_recall | With --llm only: the share of gold facts the real extractor found and stored. | Higher |
extraction_precision | With --llm only: the share of extracted facts that match a gold fact. | Higher |
source_isolation_violations | Count of injected pointers that belong to a source other than the active one. This is a data leak. | Must be 0 |
avg_injected_tokens | Estimated tokens of volunteered context per turn (characters divided by 4). Reported, not gated. | Judgment call |
Any source_isolation_violations above 0 fails the gate, whatever the baseline says.
A baseline is a saved copy of the metrics from a run. When you compare against it with the same fixtures, any gold item that newly fails, any gated metric that moves the wrong way, or any source isolation violation counts as a regression.
nexusbrain eval brainbench --compare evals/brainbench/baselines/main.jsonYou should seeThe scoreboard followed by ## Gate: PASS (same-hash), or ## Gate: REGRESSION with a table of each breach: cell, metric, baseline value, current value and detail.
0 means pass, 1 means regression, 2 means an error, an inconclusive result or a usage mistake.
nexusbrain eval brainbench --update-baseline --justification "push recall traded for precision"You should see[eval brainbench] baseline written: evals/brainbench/baselines/main.json. Commit the file so reviewers see the change.
justification.nexusbrain eval brainbench --compare base.json current.json.Fixture files end in .fixture.json and gold files end in .gold.json. They are matched by fixture_id, which must be kebab-case. The schemas are in evals/brainbench/schema/.
A fixture needs schema_version: 1, fixture_id, suites and turns. Each turn needs turn_id, role (user or assistant) and text. Write-back fixtures and continuity writers need a ts timestamp on every turn. A continuity pair has one writer and one reader sharing a pair_id.
Never put a gold key inside a fixture turn. That is a validation error.
nexusbrain eval brainbench --fixtures my-bench/fixtures --gold my-bench/gold --json --out result.jsonYou should see[eval brainbench] result written: result.json. The result follows evals/brainbench/schema/result.schema.json.
Use invented names, dates within 2024 to 2026, and placeholder amounts like $X. Do not base a scenario on a real situation with the names swapped.
eval brainbench: run failed: brainbench: cannot read fixtures dir evals/brainbench/fixtures.You are not in the root of the nexusbrain source tree. Change to that folder, or pass --fixtures DIR and --gold DIR.
eval brainbench: no fixtures found in <dir>.The folder has no files ending in .fixture.json. Check the path.
the harness/suite filters matched zero fixtures.No fixture belongs to the suites you picked. Widen --suite or --harness, or check the suites field in your fixtures.
eval brainbench: fixture validation: ....A fixture or gold file breaks the schema. The message names the file and the problem, such as fixture_id must be a kebab-case string or unknown suite.
SEED FAILURES and exit code 2.Some fixtures could not be loaded into the test database, so the whole run is invalid. Fix the fixture ids listed under the message and run again.
--llm requires a configured chat model.Configure a chat model (for example with nexusbrain models), or drop --llm to use the default deterministic mode.