Buckets:
| Name | Size | Uploaded | Xet hash |
|---|---|---|---|
| gpt-oss-20b-terminus2-tb21-full | 971 items | ||
| gpt-oss-20b-terminus2-tb21-smoketest | 15 items | ||
| qwen3_8-27b-fp8-mswea-tb21-full | 977 items | ||
| qwen3_8-27b-fp8-mswea-tb21-smoketest-final | 16 items | ||
| qwen3_8-27b-fp8-mswea-tb21-smoketest-nothink | 15 items | ||
| qwen3_8-27b-fp8-mswea-tb21-smoketest-v3 | 10 items | ||
| qwen3_8-27b-fp8-mswea-tb21-smoketest-v4 | 10 items | ||
| qwen3_8-27b-fp8-mswea-tb21-smoketest-v5 | 10 items | ||
| qwen3_8-27b-fp8-terminus2-smoketest | 10 items | ||
| qwen3_8-27b-fp8-terminus2-smoketest-v2 | 13 items | ||
| qwen3_8-27b-fp8-terminus2-smoketest-v3 | 17 items | ||
| qwen3_8-27b-fp8-terminus2-tb21-full-aborted-15mintimeout | 113 items | ||
| qwen3_8-27b-fp8-terminus2-tb21-full-v2 | 970 items | ||
| qwen3_8-27b-fp8-terminus2-tb21-mopup-final | 34 items | ||
| README.md | 16.6 kB xet | 69eb646a |
Terminal-Bench Harness — Benchmark Runs
1. Launch the model server (HF Jobs)
hf jobs run \
--flavor h200 \
--expose 30000 \
--secrets HF_TOKEN \
--timeout 4h \
--label project=terminal-bench-harness \
--label model=qwen3_8-27b-fp8 \
-d \
lmsysorg/sglang:latest \
sglang serve \
--trust-remote-code \
--model-path Qwen/Qwen3.8-27B-FP8 \
--kv-cache-dtype fp8_e4m3 \
--mem-fraction-static 0.85 \
--attention-backend flashinfer \
--chunked-prefill-size 32768 \
--max-prefill-tokens 32768 \
--reasoning-parser qwen3 \
--tool-call-parser qwen3_coder \
--mamba-full-memory-ratio 3.67 \
--host 0.0.0.0 \
--port 30000 \
--mamba-radix-cache-strategy extra_buffer_lazy \
--mamba-ssm-dtype float32
This exposes an OpenAI-compatible endpoint at https://<job_id>--30000.hf.jobs/v1, reachable with an HF token that has read access to the job's namespace.
2. Run the benchmark (Harbor + terminal-bench 3.0)
Prerequisite: git-lfs must be installed (brew install git-lfs && git lfs install) or task binary fixtures fail to download correctly.
OPENAI_API_KEY="$(hf auth token)" harbor run \
--agent terminus-2 \
--model "openai/Qwen/Qwen3.8-27B-FP8" \
--ak api_base="https://<job_id>--30000.hf.jobs/v1" \
--repo https://huggingface.co/datasets/harborframework/terminal-bench-3.0 \
--include-task-name atrx-vep-crispr \
--n-tasks 1 \
--job-name qwen3_8-27b-fp8-terminus2-smoketest-v3 \
--n-concurrent 1 \
-y
Notes:
OPENAI_API_KEYmust be exported into the shell runningharbor, not passed via--ae(that flag only injects env vars into the sandboxed task container, not the host process making the LLM call).- Drop
--include-task-nameand raise--n-tasksto run more of the dataset.
Result: single-task smoke test (terminal-bench 3.0)
atrx-vep-crispr__DvYyCpF: completed with 0 exceptions, reward 0 (task itself unsolved — it's a 7h expert-time-estimate task). Runtime 3h6m, ~5.68M input / ~681K output tokens.
3. Full run (terminal-bench 2.1, all 89 tasks, HF Sandbox environments)
Running all 89 tasks locally via Docker is impractical (each task's environment container competes for local CPU/RAM). Instead use --env hf-sandbox, which runs each task's environment as its own HF Jobs sandbox instead of a local container — every task in terminal-bench 2.1 already references a prebuilt public docker_image in its task.toml, so no local builds are needed.
OPENAI_API_KEY="$(hf auth token)" harbor run \
--agent terminus-2 \
--model "openai/Qwen/Qwen3.8-27B-FP8" \
--ak api_base="https://<job_id>--30000.hf.jobs/v1" \
--ak reasoning_effort=low \
--repo https://huggingface.co/datasets/harborframework/terminal-bench-2.1 \
--env hf-sandbox \
--ek flavor=cpu-upgrade \
--agent-timeout-multiplier 4 \
--job-name qwen3_8-27b-fp8-terminus2-tb21-full-v2 \
--n-concurrent 3 \
-y
Notes:
--agent-timeout-multiplier 4: this model is a heavy reasoner (burns lots of tokens/time per turn); the terminal-bench default per-task agent timeout (often 900s) is far too tight and causes widespreadAgentTimeoutError. 4x (60 min/task) balances fairness against runtime.--ak reasoning_effort=low: keeps the model's thinking budget in check so it doesn't blow through the timeout on easy tasks.--n-concurrent: at8, ~70% of trials errored out withSandboxError/InternalServerError/ReadTimeout(HF Sandbox infra strain, not model failures). Dropping to3brought the error rate down substantially. Lower is more reliable but slower.- Mop up leftover infra errors without re-running everything:
Repeat as needed; each pass only touches the filtered trials, everything else is preserved.# first, if you changed --n-concurrent, also edit it in the job's config.json (and lock.json to match) before resuming OPENAI_API_KEY="$(hf auth token)" harbor job resume \ -p jobs/<job-name> \ --filter-error-type SandboxError \ --filter-error-type InternalServerError \ --filter-error-type ReadTimeout \ --filter-error-type ReadError \ --filter-error-type ConnectTimeout \ --filter-error-type RemoteProtocolError # deliberately NOT AgentTimeoutError — that's a legitimate result, not infra flakiness - Harbor's own printed end-of-run summary double-counts across resume passes (it doesn't dedupe eval stats between attempts) — don't trust the final
Trials/Exceptions/Meantable it prints after a multi-pass run. Get the real per-task outcome by taking, for each task name, the trial directory with the latestfinished_atinresult.json(reward atverifier_result.rewards.reward, orexception_info.exception_typeif it errored).
Final result (89/89 tasks, after 3 resume/mop-up passes)
| Outcome | Count | % of 89 |
|---|---|---|
| Passed | 53 | 59.6% |
| Failed (genuine, reward 0) | 16 | 18.0% |
| Errored (unscored) | 20 | 22.5% |
Pass rate among the 69 genuinely-scored tasks: 76.8%. Of the 20 errors, 16 are legitimate AgentTimeoutError (task too slow even at 4x budget); the remaining 4 (circuit-fibsqrt, feal-linear-cryptanalysis, query-optimize, schemelike-metacircular-eval) failed with SandboxError/RemoteProtocolError on every one of 3 separate retry attempts (across 2 different model-serving sessions) and were accepted as final errors — see the pitfall below before trying a 4th time.
Pitfall: resuming a job after the model server URL changes
If the model-serving job dies (it will — HF Jobs --timeout is enforced eventually, just unpredictably; ours ran ~91h against a 24h setting before getting killed) and you relaunch it, do not harbor job resume the original job just because you updated api_base in its config.json/lock.json. Job.create()'s resume path matches each on-disk completed trial against a freshly-resolved TrialConfig via exact equality — which includes the agent's kwargs. Editing only the job-level files doesn't touch the ~85 individual completed trials' own per-trial config.json, so none of them match anymore and harbor concludes the entire job is still pending, silently re-running everything (including tasks you already solved) instead of just the ones you meant to retry. This wasted ~8 hours (a 2h + a 6h job) for us with zero output, because the runs actually landed under an unexpected jobs/<job-name>/ bucket path — the default harbor run/resume subdirectory — not the flat job path we were watching, so it looked idle rather than busy-doing-the-wrong-thing.
Do this instead: launch a small standalone harbor run (not resume) into a new job name, scoped to just the tasks you need via repeated --include-task-name <name>, pointed at the new endpoint. Merge results at final-tally time by scanning every relevant job directory and, per task name, keeping whichever trial has the latest finished_at.
Run 2: gpt-oss-20b (terminal-bench 2.1)
1. Launch the model server
The model card's own recommended command (uv pip install --pre vllm==0.10.1+gptoss --extra-index-url https://wheels.vllm.ai/gpt-oss/ ...) pins a launch-day (Aug 2025) PyTorch nightly build that has since been pruned from the nightly index — it fails with No solution found when resolving dependencies. Used current stable vLLM instead:
hf jobs run \
--flavor l40sx1 \
--expose 8000 \
--secrets HF_TOKEN \
--timeout 12h \
--label project=terminal-bench-harness \
--label model=gpt-oss-20b \
-d \
vllm/vllm-openai:latest \
vllm serve openai/gpt-oss-20b --host 0.0.0.0 --port 8000
Note: hf jobs run <image> <command> passes <command> as a literal argv, not through the image's shell/ENTRYPOINT — spell out the full command (vllm serve openai/gpt-oss-20b ...), don't rely on bare flags assuming an entrypoint wraps them (--model ... alone fails with exec: "--model": executable file not found in $PATH).
2. Run the benchmark
Same pattern as Run 1, orchestrator on its own HF Job with the bucket mounted — but written to land flat at the bucket root by passing --jobs-dir . after cd /data (the default --jobs-dir jobs would otherwise nest output at <bucket>/jobs/<job-name>, inconsistent with every other job dir here):
# inside the job container, after cd /data
OPENAI_API_KEY="$HF_TOKEN" harbor run \
--agent terminus-2 \
--model "openai/openai/gpt-oss-20b" \
--ak api_base="https://<job_id>--8000.hf.jobs/v1" \
--repo https://huggingface.co/datasets/harborframework/terminal-bench-2.1 \
--env hf-sandbox \
--ek flavor=cpu-upgrade \
--agent-timeout-multiplier 4 \
--jobs-dir . \
--job-name gpt-oss-20b-terminus2-tb21-full \
--n-concurrent 3 \
-y
(--model "openai/openai/gpt-oss-20b" is correct, not a typo — the LiteLLM openai/ provider prefix plus the HF repo id openai/gpt-oss-20b just happen to both start with "openai".)
Ran a 1-task smoke test first (--n-tasks 1, plain local Docker, no --env hf-sandbox needed for a single task) to confirm the endpoint/harness wiring before committing to the full run.
Final result (89/89 tasks, single clean pass, no resume needed)
| Outcome | Count | % of 89 |
|---|---|---|
| Passed | 4 | 4.5% |
Failed (genuine, incl. AgentTimeoutError) |
81 | 91.0% |
| Errored (infra, excluded) | 4 | 4.5% |
Pass rate excluding infra errors: 4.71% (4/85) — spot-checked the 4 passes for real multi-episode agent activity (not degenerate zero-effort completions): confirmed genuine. HF Sandbox reliability was strong this run (only 4/89 excluded: 2 SandboxError, 1 RemoteProtocolError, 1 CancelledError from the outer job hitting its 12h timeout mid-trial at the very end — harbor's own process had already finished cleanly and printed its 89/89 Mean: 0.045 summary, but a lingering unclosed aiohttp session kept the container alive past that point until the timeout force-killed it). Only 3 genuine AgentTimeoutErrors — this smaller/faster model wasn't timeout-bound the way the 27B reasoning model was; the whole 89-task run finished in ~13h vs. days for Run 1.
For comparison: Qwen3.8-27B-FP8 scored 62.35% on the same dataset/harness (Run 1) — gpt-oss-20b genuinely struggled with terminal-bench 2.1's agentic coding tasks.
Run 3: Qwen3.8-27B-FP8 with mini-swe-agent (terminal-bench 2.1)
Same model as Run 1, different harness agent, to compare terminus-2 vs mini-swe-agent on identical model/dataset. claude-code was considered first but ruled out: it requires an ANTHROPIC_BASE_URL speaking the Anthropic Messages API, incompatible with sglang's OpenAI-format endpoint without a LiteLLM proxy bridge — not worth building for this comparison, so mini-swe-agent was used instead (its CLI runs inside the sandbox, so wiring is via --ae, not --ak, unlike terminus-2 — see agent-wiring notes below).
1. Launch the model server
hf jobs run \
--flavor h200 --expose 30000 --secrets HF_TOKEN --timeout 12h \
--label project=terminal-bench-harness --label model=qwen3_8-27b-fp8 --label agent=mini-swe-agent \
-d lmsysorg/sglang:latest \
sglang serve \
--trust-remote-code --model-path Qwen/Qwen3.8-27B-FP8 \
--kv-cache-dtype fp8_e4m3 --mem-fraction-static 0.85 \
--attention-backend flashinfer --chunked-prefill-size 32768 --max-prefill-tokens 32768 \
--reasoning-parser qwen3 --tool-call-parser qwen3_coder \
--mamba-full-memory-ratio 3.67 --host 0.0.0.0 --port 30000 \
--mamba-radix-cache-strategy extra_buffer_lazy --mamba-ssm-dtype float32 \
--default-chat-template-kwargs '{"enable_thinking": false}'
Note the added --default-chat-template-kwargs '{"enable_thinking": false}' vs. Run 1 — Qwen3's reasoning/thinking mode was on by default and caused runaway generation (AgentTimeoutErrors with suspiciously low output-token counts, e.g. 650 tokens over 3600s — confirmed via the server's own decode-batch logs showing #full token climbing continuously, and via non-zero reasoning_tokens in the trajectory JSON). Disabling it server-side fixed this (verified: reasoning_content: null, reasoning_tokens: 0 on a test completion).
A newer sglang cookbook variant adding speculative decoding (--speculative-algorithm DFLASH + draft model, --mamba-full-memory-ratio 11.01) was tried and OOM'd on H200 (confirmed CUDA OOM traceback) — reverted to the proven config above (no speculative decoding, ratio 3.67).
HF Inference Providers were tried as a self-hosting alternative for a bit (Qwen/Qwen3.8-27B:deepinfra) but produced repeated 504 Gateway Time-outs mid-run under sustained agentic load (LiteLLM retry-looping) — reverted to self-hosting.
2. Run the benchmark
# orchestrator, as its own HF Job with the bucket mounted at /data (git-lfs required, jobs-dir . for flat bucket layout)
pip install -q --pre "harbor[hf-sandbox]==0.22.1.dev202609020403" # see pipefail/dash fix note below
harbor run \
--agent mini-swe-agent \
--model "openai/Qwen/Qwen3.8-27B-FP8" \
--ae OPENAI_API_KEY="$HF_TOKEN" \
--ae OPENAI_BASE_URL="https://<job_id>--30000.hf.jobs/v1" \
--repo https://huggingface.co/datasets/harborframework/terminal-bench-2.1 \
--env hf-sandbox \
--ek flavor=cpu-upgrade \
--ek job_timeout=2h \
--agent-timeout-multiplier 4 \
--jobs-dir . \
--job-name qwen3_8-27b-fp8-mswea-tb21-full \
--n-concurrent 3 \
-y
Notes:
- mini-swe-agent's CLI runs inside the sandbox (unlike terminus-2's LiteLLM, which runs on the host) — so it's wired via
--ae OPENAI_API_KEY=... --ae OPENAI_BASE_URL=...(env vars forwarded into the sandboxed exec), not--ak api_base=...+ a host-exported key. set -o pipefail/dash bug: hitNonZeroAgentExitCodeError: set: Illegal option -o pipefailon all 89 trials instantly (6 min) — harbor'sensure_system_dependenciesprepends bash-onlyset -o pipefail;, but--env hf-sandboxexecs via POSIX/bin/sh(dash), not bash (local Docker wraps in bash explicitly, hf-sandbox didn't). Fixed upstream in harbor-framework/harbor#3016; pinharbor[hf-sandbox]==0.22.1.dev202609020403(a--prePyPI dev build) until it lands in a stable release.- Sandbox idle-timeout bug:
RemoteProtocolError/SandboxErrorrecurring on the same step even after retries — root cause found by checking the underlying ephemeral sandbox job's own logs (hf jobs ps -ato find it, thenhf jobs logs), not harbor's wrapper:sbx-server: idle for 601917ms, shutting down. hf-sandbox's default 600s idle timeout was killing the sandbox mid-task because mini-swe-agent runs its whole agent loop as one long single exec call (no intermediate keep-alive activity harbor can see). Fixed with--ek job_timeout=2h(maps to the sandbox's ownidle_timeout).
Final result (89/89 tasks, single pass, no resume needed)
| Outcome | Count | % of 89 |
|---|---|---|
| Passed | 42 | 47.2% |
Failed (genuine, incl. AgentTimeoutError + ContextWindowExceededError + 1 exec-timeout) |
39 | 43.8% |
| Errored (infra, excluded) | 8 | 9.0% |
Pass rate excluding infra errors: 51.9% (42/81). Full per-task breakdown: qwen3_8-27b-fp8-mswea-tb21-full/README.md in this bucket.
Of the 11 initial NonZeroAgentExitCodeError trials, only 3 were genuine infra (qemu-startup, qemu-alpine-ssh: apt-get failing on an expired Debian bullseye-security archive mirror; make-doom-for-mips: /bin/sh: ps: not found in a minimal task image) — the other 8 were real model/agent capability limits: 7 ContextWindowExceededError (mini-swe-agent resends full growing conversation history every turn; hit Qwen's 262144-token context limit on long tasks) and 1 exec-level timeout kill (query-optimize, agent launched a long-running background shell command and got cut off). None were a recurrence of the pipefail/dash bug above — that fix held across the full run.
Comparison: terminus-2 vs mini-swe-agent, same model (Qwen3.8-27B-FP8, terminal-bench 2.1)
| Agent | Pass rate (excl. infra) | Passed / Scored |
|---|---|---|
| terminus-2 | 76.8% | 53/69 |
| mini-swe-agent | 51.9% | 42/81 |
terminus-2 substantially outperformed mini-swe-agent on the same model/dataset — plausibly related to mini-swe-agent's full-history-resend pattern (causing the context-window failures above) vs. terminus-2's context handling, though this wasn't isolated further.
- Total size
- 374 MB
- Files
- 3,182
- Last updated
- Sep 10
- Pre-warmed CDN
- US EU US EU