The Runner and Evaluator subsystems form the core execution engine of skill-up. While the Runner handles high-level orchestration (loading configurations, managing multiple iterations, and generating final reports), the Evaluator manages the granular lifecycle of individual test cases, ensuring that environments are prepared, agents are executed, and results are rigorously judged.
The Runner struct is the entry point for executing an evaluation suite. It coordinates the transition from static configuration files to a live execution pipeline.
iteration-N folders and cleaning stale artifacts internal/runner/runner.go71-87parallelism setting from eval.yaml (falling back to documented defaults via the Loader) to determine how many cases the Evaluator should process simultaneously internal/runner/runner.go119result.json, HTML reports, or JUnit XML internal/runner/runner.go175-179 internal/runner/runner.go191-204The following diagram illustrates how the Runner bridges the CLI/Config space into the execution pipeline.
Runner to Evaluator Bridge
Sources: internal/runner/runner.go95-180 internal/runner/runner.go71-87 internal/runner/runner.go119-133
The Evaluator (specifically defaultEvaluator) implements the logic for executing a set of CaseConfig objects. It manages a worker pool based on the configured concurrency using a semaphore channel internal/evaluator/evaluator.go209-234
Each case follows a strict sequence of stages within the executeCase function internal/evaluator/evaluator.go332-511:
runtime.Runtime is created (e.g., Docker, OpenSandbox, or Host) via the runtime.NewRuntime factory internal/evaluator/evaluator.go343-348fixtureRegistry coordinates uploading files, initializing Git repositories, and applying diffs to the workspace. This involves components like repoFixtureUploader and gitInitUploader internal/evaluator/fixtures.go23-40 internal/evaluator/fixtures.go114-147executeMultiTurn to manage session persistence internal/evaluator/multiturn.go72-153must_contain or must_not_contain checks on the agent's final message via runExpectPreCheck internal/evaluator/evaluator.go472-474judge.NewJudge internal/evaluator/evaluator.go477-482collect_artifacts globs are downloaded from the runtime to the local iteration workspace via collectGlobArtifacts internal/evaluator/evaluator.go488-490This diagram maps the internal functions and structs involved in the per-case lifecycle.
Evaluator Internal Pipeline
Sources: internal/evaluator/evaluator.go332-511 internal/evaluator/fixtures.go19-40 internal/evaluator/multiturn.go72-153
If a case defines input.turns, the Evaluator switches to a stateful execution mode via executeMultiTurn internal/evaluator/multiturn.go72-88
turn.capture use regex to extract values from the assistant's response, which are then injected into subsequent turns via {{variable}} templates internal/evaluator/multiturn.go136-148 internal/evaluator/multiturn.go218-245post_condition fails, the evaluator can skip remaining turns or fail the case early via handlePostCondition internal/evaluator/multiturn.go129-134SessionResumer interface to support this flow, specifically the RunTurn method which accepts a sessionID internal/evaluator/multiturn.go79-82 internal/agent/agent.go72-74The Evaluator uses a fixtureRegistry to populate the runtime workspace. Key uploader types include:
repoFixtureUploader: Copies a directory from the skill's fixtures/ folder to the runtime internal/evaluator/fixtures.go23-40gitInitUploader: Runs git init, configures user.name and user.email, and adds remotes internal/evaluator/fixtures.go114-147gitCheckoutUploader: Switches to a specific branch, creating it if the repository is fresh. It uses git switch and includes safety checks to prevent masking typos in branch names internal/evaluator/fixtures.go149-195contextFilesUploader: Injects ad-hoc files defined directly in case.yaml using a temporary file buffer internal/evaluator/fixtures.go42-76The Evaluator tracks the Status of each case to aggregate final metrics internal/evaluator/evaluator.go67-106:
| Status | Meaning |
|---|---|
PASS | Judge returned pass and all expect pre-checks passed. |
FAIL | Logic check failed (e.g., script exited non-zero or LLM judge failed). |
ERROR | System failure (e.g., Docker container failed to start, credential check failed). |
SKIP | Case was skipped via CLI filters or internal conditions (e.g. post_condition failure). |
Sources: internal/evaluator/evaluator.go67-106 internal/evaluator/multiturn.go25-34 internal/evaluator/fixtures.go19-40
| Entity | File Path | Role |
|---|---|---|
Runner | internal/runner/runner.go48-58 | High-level orchestrator; manages iterations, workspace setup, and result reporting. |
Evaluator | internal/evaluator/evaluator.go124-126 | Interface for executing all cases through the evaluation pipeline. |
defaultEvaluator | internal/evaluator/evaluator.go129-148 | Main implementation of the evaluation pipeline; manages concurrency and fixture registry. |
EvalResult | internal/evaluator/evaluator.go67-106 | Container for agent output, grading results, status, and metadata. |
executeCase | internal/evaluator/evaluator.go332-511 | The core method defining the per-case lifecycle (Prep -> Exec -> Judge -> Collect). |
executeMultiTurn | internal/evaluator/multiturn.go72-153 | Orchestrates multi-turn logic, variable capture, and post-condition checks. |
TurnResult | internal/evaluator/multiturn.go37-54 | Holds the outcome of a single conversation turn for multi-turn evaluations. |
Sources: internal/runner/runner.go1-58 internal/evaluator/evaluator.go1-148 internal/evaluator/multiturn.go1-153
Refresh this wiki