بنقرة واحدة
compare-tasks
Compare how two harbor benchmark runs performed on a single shared task
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Compare how two harbor benchmark runs performed on a single shared task
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | compare_tasks |
| description | Compare how two harbor benchmark runs performed on a single shared task |
Use when given two harbor run names and a task name, and the goal is to understand why the two runs differ on that task — not just that they differ.
RUN_A: harbor run name (e.g. sonnet46-full)RUN_B: harbor run name (e.g. pi-sonnet46-full)TASK: bare task name (e.g. extract-elf, not terminal-bench/extract-elf)RUNS_DIR: defaults to evals/harbor/runs/ relative to the repo rootHarbor 0.8 names trial dirs <task>__<random-suffix> (e.g.
extract-elf__bU3GHs4), not <task>.1. The suffix is unique per trial,
so don't guess it — discover it from disk:
TRIAL_A_DIR=$(ls -d "$RUNS_DIR/$RUN_A/${TASK}__"*/ 2>/dev/null | head -1)
TRIAL_B_DIR=$(ls -d "$RUNS_DIR/$RUN_B/${TASK}__"*/ 2>/dev/null | head -1)
If either is empty, that run didn't include this task — stop and say so.
(ls "$RUNS_DIR/$RUN_A/" shows what's there.)
If you want to confirm the match, every result.json carries task_name
and trial_name:
jq '{task_name, trial_name}' "$TRIAL_A_DIR/result.json"
Pull these fields from each trial's result.json. The actual shape (harbor
0.8 TrialResult):
jq '{
reward: (.verifier_result.rewards.reward // null),
rewards_all: .verifier_result.rewards,
duration_seconds: ((.finished_at | fromdateiso8601) - (.started_at | fromdateiso8601)),
input_tokens: .agent_result.n_input_tokens,
cache_tokens: .agent_result.n_cache_tokens,
output_tokens: .agent_result.n_output_tokens,
cost_usd: .agent_result.cost_usd,
error_type: .exception_info.exception_type,
error_message: (.exception_info.exception_message // "" | split("\n")[0])
}' "$TRIAL_A_DIR/result.json"
Derive status from those:
pass if reward >= 1.0partial if reward > 0 (and < 1)fail if reward == 0timeout if reward is 0/null and error_type contains "timeout"error if reward is 0/null and error_type is set (non-timeout)no-reward if neither verifier_result.rewards nor exception_info is setReward wins over errors: harbor can record an AgentTimeoutError after the
verifier already scored a pass (the agent finished the work then the harness
timed out during teardown, or it timed out after writing the correct answer).
If we got points, count them. See reporter.trial_status for the canonical
rule.
Several agent_result fields are commonly null for older GooseBinaryAgent
runs (notably n_cache_tokens, n_output_tokens, cost_usd). Don't treat
that as a failure — just omit those facts from the comparison if missing on
either side. The reporter has fallbacks that read goose's complete event
from agent/goose.txt; you don't normally need to replicate them here.
The task definitions are NOT in the harbor Python package. They are plain
text files on disk, in harbor's dataset cache. Do not run find / or
pip show harbor — that is the wrong direction.
Find the task directory (works on Linux and macOS):
TASK_DIR=$(
ls -d ~/.cache/harbor/datasets/terminal-bench__terminal-bench-2__*/tasks/"$TASK"/ 2>/dev/null \
|| ls -d ~/Library/Caches/harbor/datasets/terminal-bench__terminal-bench-2__*/tasks/"$TASK"/ 2>/dev/null
)
echo "$TASK_DIR"
ls "$TASK_DIR"
If both lookups return empty, the dataset hasn't been downloaded yet — bail out and report that, rather than guessing.
Inside, you care about three files:
instruction.md — exactly what the agent was asked to dotests/test_outputs.py (or sometimes run-tests.sh) — what the verifier
actually checks, line by linesolution/solution.sh — the reference correct answerWithout all three you can't tell whether a wrong answer was a misread, a shallow bug, or a verifier surprise. Quote the assertion that failed when you describe a failure — paraphrasing is how wrong conclusions sneak in.
Two sources, prefer the first when present:
$TRIAL_DIR/agent/trajectory.json — harbor's ATIF format, one entry per
agent step. jq '.steps[] | {step_id, source, message, tool_calls: [.tool_calls[]?.function_name]}'
gives a compact view. Recent goose runs (after the populate_context_post_run
fix) have this; older GooseBinaryAgent runs may not.$TRIAL_DIR/agent/<harness>.txt — raw stream-json or log. The filename
matches the harness: goose.txt, pi.txt, opencode.txt,
claude-code.txt. ls "$TRIAL_DIR/agent/" to find it.Skim, don't quote in full. For each agent identify:
$TRIAL_DIR/verifier/ typically contains:
test-stdout.txt — the verifier's full stdout (assertion failures, pytest
output, etc.). This is usually the most diagnostic file.reward.txt — the scalar reward as a string.ctrf.json — structured test results in CTRF format, useful if you want
per-assertion pass/fail without grepping stdout.tail -50 "$TRIAL_DIR/verifier/test-stdout.txt"
This is often more diagnostic than the agent log — it tells you exactly which assertion failed and what the agent's output was at that point.
Output markdown with these sections in order:
nm -n so its addresses matched the verifier's
ground truth, A's script used PIE-relocated virtual addresses which the
verifier doesn't normalize".ls -d to discover the <task>__<suffix> trial directoriesjq for result.json$TRIAL_DIR/agent/ and $TRIAL_DIR/verifier/~/.cache/harbor/datasets/...)No Python imports, no harbor package required. Everything you need is on
disk as JSON / text files.