Skip to main content
All configuration lives on one frozen HarnessConfig object. Build it from the environment (most knobs have a HARNESS_* variable) with explicit overrides winning:
repair_model is required. Harness.create() raises ValueError unless you set it (or HARNESS_REPAIR_MODEL), because the repair agent makes its own model calls and no billable default is ever selected for you. The one exception is observe_only=True, which evaluates and journals without mutating anything.
Not every field has an environment variable. Set the rest programmatically: thresholds (a per-metric threshold map), the per-tier metric tuples, and the fine-grained gate knobs. Derived workspace paths (rules.md, rules/, rules.jsonl, scope_metadata.json, mailbox/, journal.jsonl, …) are computed from HARNESS_ROOT and cannot be overridden individually.

Workspace & CLI

The repair agent

The repair agent is package-owned: PandaProbe supplies the prompt, the capability set, and the episode lifecycle. You supply the model and its bounds.
Repair model calls go through PandaProbe’s official LiteLLM wrapper, so the provider credentials for repair_model must be present in the environment — separate from the PANDAPROBE_* platform credentials below.

The trigger

The trajectory gate

A Tier-1 metric breaches on the shape of its series, never on its absolute value.
Long-horizon tasks want a larger gate_window; short interactive turns want a smaller one. Read your Tier-1 score distribution from calibration before moving gate_target or gate_drop.

Evaluation & polling

Thresholds

Metrics deliberately have no built-in per-metric threshold table: they all sit at 0.5, and the platform reports its own threshold in each score’s metadata, which the evaluator prefers when no local override exists. A table of identical values would only be a second place to spell a metric name. Remember that a Tier-1 metric’s floor is not a breach source at all — its verdict comes from the trajectory gate, so gate_target is the knob that matters there.

Noticing

Cost & sampling

eval_sample_every > 1 and the trajectory gate work against each other: skipping turns thins the series the gate needs to detect a stall. Prefer bounding cost with enable_tier3=false (the default) and max_evals_per_run, which don’t distort the trajectory.

Rules & retrieval

Validation & the closed loop

Where a replay must queue for a shared resource — one environment server, one container, one device — leave replay_env_wait_timeout_s at 0 only if your replay never waits. Otherwise queueing is charged to the execution budget, and the resulting timeout is indistinguishable from a hung agent: the case is recorded as inconclusive evidence about a rule that never actually ran.

Robustness & scale

Useful derived helpers

rules_scope_file() takes a scope already normalized by pandaprobe_harness.workspace.scopes.normalize_scope, because the value becomes a filename. That module also exports GLOBAL_SCOPE, SCOPED_SCOPE, and RESERVED_SCOPES — one definition shared by the store, the mailbox, and the turn hook.

Platform credentials

The pandaprobe subprocess inherits your environment, so the standard SDK/CLI variables apply unchanged: PANDAPROBE_API_KEY, PANDAPROBE_PROJECT_NAME, and PANDAPROBE_ENDPOINT for self-hosting. The harness itself never reads them — authentication is entirely the CLI’s concern. The repair agent is separate: its model calls go through PandaProbe’s LiteLLM wrapper, so whatever provider credentials repair_model needs (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS or Vertex settings) must also be present.