Experiment fields
models
description
adapter
model
reasoningEffort
judge
flags
labels
{ line: "codex", memory: "mempal" }).
Values are string | number (validated at parse time). The line between labels and flags is “does it change what happens in the attempt”:
labels are not passed to ctx / t (the agent and eval cannot see them) and do not take part in the comparability configuration (changing them does not invalidate existing results);
they are only projected verbatim into the snapshot’s ExperimentRunInfo.labels for report dimensions (label() / numericLabel())
to group by. The default report recognizes the line key: when any Experiment in the group declares it, scatter points are grouped by line and connected.
See docs/feature/experiments/library.md “labels”.
attempts
--attempts overrides it.
earlyExit
attempts run in full to measure the complete pass rate).
Turn it on explicitly to save cost when you only want to know whether it can pass.
evals
"*" for all, a string array matched by id prefix, or a custom predicate (which receives each discovered and fanned-out
read-only EvalDescriptor, with no path / execution fields exposed); omitted is equivalent to "*". The predicate is evaluated once per
candidate eval of this invocation, and the result becomes the in-memory selectedEvalIds plan, not a filter called repeatedly at runtime
(see docs/feature/eval/library.md “EvalDescriptor” and docs/feature/experiments/library.md
“evals: iterate discovery results, choose your own”).
timeoutMs
sandbox
sandboxCache
plugins
defineExperiment().
sandboxReuse
sharedState
budget
estimatedCostUSD of finished attempts; that value is
computed from the model, token usage, and the runtime/config pricing table, independent of the
observed usage.costUSD reported by the Provider / Adapter, which does not drive the budget. Once the estimate reaches the limit, the Experiment’s remaining
attempts that have not started are skipped and run:budgetExceeded is reported once (attempts already in flight still finish).
maxConcurrency
maxConcurrency: 1 guarantees attempts run one by one in eval order),
or to slow down an Experiment that hits provider limits. A concurrency permit shares the attempt’s lifetime: it is held from before Sandbox creation until
after and Sandbox destruction finish, and any wait along the way (including turn retry backoff) keeps holding it.
maxConcurrency: 1 is therefore a strict critical section that the next attempt of the same Experiment cannot enter early.
It does not span Invocations; for shared external state across Invocations, declare sharedState.
before
after and agent / sandbox hooks in the same file read them from the closure;
the runner does not mediate values. If before throws, every Attempt of this Experiment gets an errored Verdict
(code "experiment-setup-failed", phase "experiment.before"); other Experiments in the batch are unaffected.
The function body does not enter the fingerprint; after changing hook logic, use --rerun all to explicitly rerun everything.
See docs/feature/experiments/architecture.md “Experiment-level lifecycle”.
after
experiment-teardown-failed) and does not change the Verdict.