Skip to main content
Use HarnessFreeBenchmark when the Benchmark must run its upstream-defined inference or interaction protocol. This can be a response-generation workflow, multi-role interaction with a user simulator, or a domain state machine. Keep scoring in evaluate() even when the official runner packages generation and evaluation as one pipeline. Choose the execution owner by the evaluation contract. Reuse a Harness when its agent loop preserves that contract; keep a dedicated upstream runner in the Benchmark when adapting it to a generic loop would change the protocol, termination conditions, or trajectory semantics. A workflow’s stages alone do not determine whether it needs an external Harness.

How It Differs from an Ordinary Benchmark

HarnessFreeBenchmark inherits every BaseBenchmark contract and additionally requires run_task():
Use none as the Harness ID in the run command:
Here, none means there is no external Harness. It does not require evaluation_environment_mode to be none; Benchmark-driven execution can still use reuse or fresh evaluation.

Implement run_task()

The following excerpt shows only what differs from BaseBenchmark. Assume prepare_task() has written the upstream runner request into the task Environment and stored its public paths under official_runner in PreparedTask.metadata:
This excerpt cannot run by itself because data loading, task preparation, and the upstream runner depend on the actual protocol. It demonstrates the ownership boundary: the runtime manages the Environment lifecycle and error flow, while run_task() runs the Benchmark-specific loop and translates its output into RunResult.

Keep Execution and Scoring Separate

Even if the upstream runner already produces a reward, let evaluate() translate it into the final verdict instead of scoring inside run_task(). This preserves the runtime’s distinction between execution and evaluation failures:
If another command must run to obtain the reward, execute the verifier through the env passed to evaluate() and classify a verifier crash as EVAL_ERROR. See Evaluation Modes and Artifacts for the Environment lifecycle and Results and Aggregation for status composition.

Responsibility Boundaries

  • prepare_task() places the upstream runner, data, and request material in the Environment; repeating it during a retry must not corrupt task state.
  • run_task() owns the Benchmark-specific inference or interaction protocol, Model-call orchestration, and trajectory conversion, but it must not create or close the Environment itself.
  • Declare submission preparation commands through TaskSpec.artifact_collect; without commands, runtime collects existing files directly.
  • evaluate() interprets runner output or invokes the official verifier while preserving any existing execution error.
  • Pass credentials for the Model, simulator Model, or judge Model through existing Model-configuration boundaries; they must never enter results, logs, or publishable metadata.
For a complete production implementation, inspect TauBenchBenchmark. It uses the none Harness, starts the upstream interaction runner in run_task(), and evaluates in the same task Environment through reuse mode.