Eval capture — NDJSON schema reference
Status: stable from v0.21.0. Schema versioning viaschema_version
on every row; additive changes increment the minor version; removals
are breaking-schema-v2.
Audience: downstream consumers (primarily the sibling
modusbrain-evals repo) that
replay captured real-world queries as a BrainBench-Real fixture.
The pipeline
modusbrain eval export — the consumer contract
\n-terminated line.
stderr receives progress heartbeats. Every line starts with
"schema_version": 1 so a forward-compat parser can fail loudly on
schema v2 instead of silently misparsing.
Typical usage from modusbrain-evals:
Row schema (v1)
Every exported row has this shape. Field order in JSON output is not guaranteed; consumers MUST key by name, not position.Ordering + determinism
listEvalCandidates orders by created_at DESC, id DESC. Same-
millisecond inserts tie on created_at; id DESC is the stable
tiebreaker. Replay tools can consume rows in order and assume:
- no duplicate rows across calls with non-overlapping
--sincewindows - no missed rows across calls that chain
--sincewindows (window end of run 1 is the strict upper bound, not a soft cursor)
Schema versioning promise
- v1 (shipped v0.21.0) — this document. All fields listed above.
- Additive changes increment modusbrain minor version (v0.25.0, v0.23.0 …) and ship with new optional fields. Consumers keyed on known fields ignore unknown keys and keep working.
- Breaking changes (rename, type change, removal) increment
schema_versionto 2. Consumers MUST branch onschema_versionto stay compatible.
eval_capture_failures — companion audit table
Not exported by modusbrain eval export. Surfaced via modusbrain doctor:
db_down | rls_reject | check_violation |
scrubber_exception | other. Cross-process visibility is the whole
point — modusbrain doctor runs in its own process and reads the table
directly, so in-process counters wouldn’t work.
Config + CONTRIBUTOR_MODE
Capture is off by default as of v0.25.0 (was on for everyone in earlier drafts). Two paths to turn it on: Path A — env var (contributor opt-in, the common case):~/.modusbrain/config.json, file-plane only):
eval.capture: truein config → oneval.capture: falsein config → off (overrides CONTRIBUTOR_MODE=1)MODUSBRAIN_CONTRIBUTOR_MODE === '1'→ on- otherwise → off
scrub_pii defaults to true independent of capture. Set
eval.scrub_pii: false to preserve raw query text (only if you control
the brain’s distribution).
modusbrain config set eval.capture false does not work — that
command writes the DB-plane config, and the MCP server reads the
file-plane. Edit the JSON directly or use the env var.