Skip to main content

Evaluate the harness

Start with the contracts that make an agent run trustworthy: ordered events, bounded context, tool authorization, cancellation, durable history and process boundaries. The evaluation environment runs the existing Rust implementations and fixtures. It uses Python's standard library and has no model API dependency.

Run locally​

Use a Linux checkout with the repository's Rust toolchain and system build dependencies installed. See Development for setup. Run as a normal user; several filesystem and execution tests exercise ownership.

# Discover contracts without compiling anything.
python3 evals/harness/run.py --list

# Run all deterministic contract groups serially.
python3 evals/harness/run.py

# Short feedback loop after a protocol or context change.
python3 evals/harness/run.py --suite wire --suite context

# Require cached Cargo dependencies and prohibit Cargo network access.
python3 evals/harness/run.py --offline

# Preserve the complete existing CI test gate and collect the same report.
python3 evals/harness/run.py --workspace

Cargo uses --locked; the initial dependency download can require network access. No command above invokes a model or provider. Every Cargo invocation uses scripts/serialize-cargo.sh, and every Rust test binary uses one test thread. Set CORTEXFS_CARGO_LOCK to one shared lock path when using multiple worktrees. The runner does not install dependencies or change provider settings.

Results go to a new directory below target/harness-eval/. Each run writes report.json, a readable report.md, and a raw log for each Cargo invocation. Use --output /path/to/new-directory to choose a location. Existing directories are refused so a later run cannot overwrite earlier evidence. The report records the Git revision, dirty worktree state, manifest digest, toolchain, exact commands, test counts and exit status. Keep the entire directory when sharing evidence.

The default timeout is 3,600 seconds per Cargo invocation, including compile time and lock wait. Use --timeout 6600 for a cold workspace build. A timeout or interrupt terminates the invocation's process group and retains a failed report. Durations measure the test/build command; they are not agent inference latency. While waiting, the runner prints elapsed time and raw-log byte count every 30 seconds.

Exit codes: 0 means all selected contracts have passing evidence; 1 means a test, timeout, compilation, or required-evidence failure; 2 means invalid setup or arguments; 130 means interrupted execution. A failed invocation stops later groups, which remain explicitly not_run in the report. Partial selections are labelled selected, never presented as a full harness evaluation.

What the fixtures prove​

The manifest at evals/harness/suites.json maps each contract to its canonical Rust fixture files and required test names. Each required test must be observed as ok. A renamed, missing or ignored required test fails the contract, even if Cargo exits successfully. An invocation with zero passing tests also fails.

GroupExercised behaviorBoundary
wireInitial/continuation envelope framing, observation identity and size, ordered streamed events and commandsRuntime client and real Unix-stream fixtures
contextTiny UTF-8 byte bounds, output reservation, latest observation retention, unchanged raw historyContext crate
authorityCombined policy/mount/identity checks, symlink rejection, prompt text cannot grant tool authorityHost authorization mechanism
cancellationChild authority attenuation; cancellation appends durable facts without erasing historyOwned child lifecycle
recordingTerminal facts affect only their run; replay/idempotency; tool success and denial become observationsDurable session recorder
ownershipBoth cancellation/completion orderings, concurrent finishers, fault rollback preserves replacementsReceipt-bound session operations
socketsActual socket reads, peer rejection before mutation, idle timeout, cancellation index checksOne-request v1 socket service
aliasesExact broker target, legacy compatibility, owner checks and path rejectionFUSE projection methods; no mounted filesystem required
sendersTelegram/Discord/Slack actor identity; default-deny routesChannel event adapters
routingRejected users never dispatch; allowed users retain distinct sessionsHost bridge
scheduleDelegated work selects the installed executor, requires its create authority, materializes handoffs and derives completion from child resultsSchedule validation, materialization and completion
sdkInstalled Agent and Tool SDK executables complete two declared native tool calls; canonical CLI failures and oversized inputInstaller, SDK processes and host tool loop

Fixtures stay with their Rust modules. Adding a contract means extending those tests and registering evidence in the manifest, rather than implementing a second agent loop inside the evaluator. Runner regression tests check failure reporting, zero-test rejection, missing coverage and process cleanup:

python3 -m unittest discover -s evals/harness -p 'test_*.py' -v

CI uses --workspace with the same --locked --workspace --all-targets --all-features gate as before. Workspace mode adds --no-fail-fast to collect results from later test binaries after a failure while retaining a failing exit status. Format, source-budget, Clippy and documentation gates remain separate. CI uploads the evidence even when tests fail.

Evidence limits​

Passing these contracts does not measure model reasoning, coding task success, cost, tokens, TTFT, p95 latency or peak RSS. There is no aggregate "intelligence" score. The groups have different responsibilities; combining their counts into a leaderboard would obscure failures.

The focused profile does not establish mounted FUSE behavior, systemd/cgroup enforcement, full kernel sandbox isolation or persistent concurrent interaction v2 behavior. V2 type validation alone cannot establish a deployed v2 service. Some existing workspace tests contain platform-conditional branches; a libtest ok cannot reveal a branch that returned early. Read the linked fixture sources and raw logs when evaluating that broader evidence. The required contract tests are selected from concrete assertions at implemented boundaries.

Optional live evaluation​

Run a live evaluation separately on a disposable configured deployment after the deterministic contracts pass. Use the current harness replacement boundaries, provider registry, route and secret configuration. Keep the user-selected provider and model explicit. Do not bypass the mounted agent with a direct vendor SDK call or treat debug/echo as model-quality evidence.

For the local lightweight fixture, explicitly install smollm2:135m before configuring its provider and route. If it is unavailable, stop with that fact; do not silently substitute another model. A paid configured-provider run needs the user's explicit authorization. The deterministic runner never triggers it.

Use a dedicated evaluation agent with the necessary tool policy and a disposable workspace. Submit through the normal client, for example:

ctx --root /ctx agent send evaluator --session eval-001 \
"Read input.txt, double its integer, write output.txt, then read output.txt to verify."
ctx --root /ctx agent send evaluator --session eval-001 \
"Continue from the previous result and explain which tool observations verified it."

These examples require an already configured evaluator agent and input fixture. The client uses the canonical Agent socket; file-queue clients retain the normal same-directory atomic *.req.json submission and outbox/audit semantics. Check the output file independently and inspect the durable session history; a final answer that merely claims success is insufficient evidence.

Record pinned source/package revisions, provider/model and generation settings, input fixture hash, task oracle, tool schemas, policy, concurrency, step/token budgets, timeout, every attempted run (including failures), tool/model counts and raw events. Retain private traces locally and redact secrets before sharing. Cancellation and recovery experiments belong on that disposable deployment. Comparisons with another harness need identical tasks, tools and budgets plus repeated measurements and reported uncertainty; this environment makes no comparative performance or quality claim.

Replacing the legacy benchmark​

The old inspect_benchmark/ Inspect/Pi runners, datasets and Python dependency lockfile, non-equivalent protocol timing example and generated performance card were removed. They are recoverable from Git history. The replacement has no Inspect, cloud SDK or separate scoring dependency. All existing Rust correctness tests remain, and the 2026-09-05 validation report remains historical evidence, with its original limitations and failed experiments intact.