Skip to content

Seed-complexity blocks: shell stub and opencode full-harness seeds for Terminal-Bench and GAIA - #97

Open
varunursekar wants to merge 17 commits into
mainfrom
seed-complexity-blocks
Open

varunursekar wants to merge 17 commits into
mainfrom
seed-complexity-blocks

Conversation

@varunursekar

@varunursekar varunursekar commented Sep 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds the two new seed families the EACL rebuttal grid runs on, plus the compiler and rescore changes they needed. Every cell in the TB-stub, TB-opencode and GAIA-opencode blocks was launched from this branch (VERO_SRC_OVERRIDE to this worktree's vero/src).

Seeds

  • terminal-bench/baseline/target-shell + build.shell.yaml: non-functional shell stub mirroring the GAIA stub (measured baseline 0.0).
  • terminal-bench/baseline/target-opencode, gaia/baseline/target-opencode + build.opencode.yaml: opencode vendored as a pinned submodule (anomalyco/opencode @ e03db9bc), thin harbor OpenCode subclass, host-side Bun build cached per tree hash, VERO_OPENCODE_BINARY override. GAIA e2e smoke variant.
  • TB opencode seed sends the vendor-prefixed wire id (xai/grok-build-0.1) through a custom opencode-target provider; the bare id was rejected upstream with 401 and scored 0.0. VERO_OPENCODE_WIRE_MODEL_ID overrides.
  • opencode target calls go to the public upstream from inside the task container (task_services_use_upstream).

Compiler

  • Materialise git submodules when snapshotting agent_repo (they came out as empty dirs from git archive).
  • Allow in-tree relative symlinks in the snapshot (opencode links web assets across packages).

Build timeouts (opencode builds)

  • build_timeout_seconds 5400: the image build/start regularly took 45+ min.
  • Sandbox idle timeout 4 h: the verifier's test evaluation of an opencode candidate outlives the 1 h window and the sandbox was gone before harbor downloaded the verifier dir.

rescore_candidate

  • --build-file for routed builds, --agent-env (harbor --ae) passthrough, --agent-setup-timeout-multiplier (the 143 MB opencode binary upload from the host exceeded harbor's 360 s setup budget at concurrency 24), resolve the harbor_requirement placeholder, skip node_modules/dist/.turbo when copying the seed tree.
  • GAIA budget-blind build variant and GAIA shell routed build for transfer passes.

Notes for review

  • No secrets: only secrets.env.example files are tracked; added lines were scanned for key patterns.
  • The branch is in live use by running cells. Please merge without rewriting its history; if history needs cleaning, do it on a copy.

Test plan

  • vero/tests shell-variant config test parametrized over gaia and terminal-bench
  • GAIA opencode e2e smoke (build.opencode.e2e.yaml) on Modal
  • TB opencode fixed-seed cells start at dev 0.53 to 0.76 (previously 0.0 with the bare wire id)
  • Full-block runs: TB stub 27 cells, TB opencode and GAIA opencode blocks in progress

🤖 Generated with Claude Code

RetriggerConfidence Score: 0/5

The PR is not safe to merge. Four open issues can expose credentials, run edited code on the host, or build the wrong source.

Fix All in CursorFindings

  1. P1 task services use upstream puts the real OPENAI API KEY in the task environment. This target reads that key from optimizer-editable code instead of using the scoped gateway token. A candidate can send direct requests or print the key, while request logs only catch this later. Keep editable code on a reachable scoped gateway instead of giving it the provider key.
  2. P1 build binary runs optimizer-edited install hooks and script/build.ts on the evaluation host. Both commands inherit all of os.environ . This happens before the binary enters the task container, so task isolation does not protect the host. Build candidate source inside a sandbox and pass only the values it needs.
  3. P1 ls-tree returns the gitlink SHA, but this code keeps only the path and archives the checkout's current HEAD . If an initialized submodule is stale or was moved by a developer, the build silently snapshots that other commit. Archive the gitlink SHA or reject a checkout whose HEAD does not match it.
  4. P1 tree hash skips each symlink, including its path and target. The compiler now keeps safe symlinks because opencode uses them as build inputs. A candidate can change such a link without changing the cache key, and build binary can return the previous binary. Hash the link path and os.readlink path value.
  5. P2 BUN VERSION affects only the fallback download URL. If bun is already on PATH or under ~/.bun , bun returns it without checking the version. Check bun --version and fetch the pinned release when it differs.
Fix with agent prompt
### Issue 1
harness-opt-bench/terminal-bench/baseline/build.opencode.yaml:118-123
`task_services_use_upstream` puts the real `OPENAI_API_KEY` in the task environment. This target reads that key from optimizer-editable code instead of using the scoped gateway token. A candidate can send direct requests or print the key, while request logs only catch this later. Keep editable code on a reachable scoped gateway instead of giving it the provider key.

The GAIA opencode builds use the same setting.

**How this was verified:** `HarborBackend` copies the host provider key into the task environment, and the editable wrapper reads that exact variable.

### Issue 2
harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py:104-115
`build_binary` runs optimizer-edited install hooks and `script/build.ts` on the evaluation host. Both commands inherit all of `os.environ`. This happens before the binary enters the task container, so task isolation does not protect the host. Build candidate source inside a sandbox and pass only the values it needs.

The GAIA copy has the same code.

**How this was verified:** Agent setup invokes both candidate-controlled Bun commands on the host with the full parent environment before uploading the binary.

### Issue 3
vero/src/vero/harbor/build/compiler.py:187-199
`ls-tree` returns the gitlink SHA, but this code keeps only the path and archives the checkout's current `HEAD`. If an initialized submodule is stale or was moved by a developer, the build silently snapshots that other commit. Archive the gitlink SHA or reject a checkout whose `HEAD` does not match it.

### Issue 4
harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py:34-49
`tree_hash` skips each symlink, including its path and target. The compiler now keeps safe symlinks because opencode uses them as build inputs. A candidate can change such a link without changing the cache key, and `build_binary` can return the previous binary. Hash the link path and `os.readlink(path)` value.

### Issue 5
harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py:52-61
`BUN_VERSION` affects only the fallback download URL. If `bun` is already on `PATH` or under `~/.bun`, `_bun` returns it without checking the version. Check `bun --version` and fetch the pinned release when it differs.

The GAIA copy has the same code.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Summary

VeRO adds shell and full-opencode starting points for Terminal-Bench and GAIA, along with compiler and rescoring support for running them. The new seeds compare building an agent from an empty shell with improving a complete coding harness on the same benchmark setup.

  • Adds zero-score shell seeds and build variants for both benchmarks.
  • Adds vendored, editable opencode seeds with cached host-side builds and binary uploads.
  • Teaches snapshots to include git submodules and safe in-tree symlinks.
  • Extends rescoring for alternate builds, agent environment values, setup time, and large seed trees.
Diagram
sequenceDiagram
    participant Compiler
    participant Git as Git checkout
    participant Host as Evaluation host
    participant Task as Task container
    participant API as Public upstream

    Compiler->>Git: Archive the seed at HEAD
    Compiler->>Git: Find submodule gitlinks
    Git-->>Compiler: Archive each submodule at its checked-out HEAD
    Compiler-->>Host: Return baseline with vendored opencode
    Host->>Host: Hash the opencode tree
    alt Cached binary exists
        Host->>Host: Reuse cached binary
    else No cached binary
        Host->>Host: Run bun install and build.ts
        Host->>Host: Cache the binary
    end
    Host->>Task: Upload the opencode binary
    Host->>Task: Pass upstream API settings
    Task->>API: Send model requests directly
    API-->>Task: Return model responses
Loading

Reviews (2) · Last reviewed commit: "CI: check out the vendored opencode subm..."

varunursekar and others added 16 commits September 14, 2026 16:45
…efore passing it to uv

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…outed builds

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…routed build for transfer passes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…yaml) mirroring the GAIA stub

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… test parametrized over gaia and terminal-bench

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- target-opencode/: opencode vendored as a git submodule pinned to e03db9bc
  (v1.18.31 dev), plus a thin wrapper that subclasses harbor's opencode runner,
  compiles the vendored tree on the evaluation host (Bun, cached by source hash)
  and uploads the binary into each task container; GAIA wrapper tells opencode to
  write /app/answer.txt
- build.opencode.yaml for both benchmarks (same tasks/model/scopes as build.yaml;
  baseline_reward unpinned until measured)
- compiler: materialise submodule contents when snapshotting agent_repo (git
  archive leaves gitlinks as empty dirs)
- config test for the opencode variants; READMEs describe the seed ladder

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e first add was clobbered by a concurrent clone

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o (opencode links web assets across packages)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… instead of the install script (no curl/unzip dependency on the evaluation host)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ontainer

The e2e smoke showed two things: the evaluation gateway is compose-internal and
unreachable from task containers (opencode: 'Cannot connect to API'), and the
sidecar runs harbor 0.20.0, whose opencode runner lacks ensure_system_dependencies.
- builds set task_services_use_upstream (and harness_user: null, as browsecomp-plus
  does); the wrapper takes OPENAI_BASE_URL only, never the gateway address
- install() installs coreutils by hand and stages the binary via /tmp before moving
  it into /usr/local/bin as root
- config test asserts the upstream flag on the opencode variants

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ation of an opencode candidate outlives the 1 h idle window and the main sandbox is gone before harbor downloads the verifier dir

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The vendored opencode image takes 10-23 min to start on Modal and the
1800 s default (build_timeout_seconds -> harbor build_timeout_sec) timed
out about ten launches with EnvironmentStartTimeoutError.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…rok-build-0.1)

The seed registered the bare harbor model name under opencode's built-in
openai provider and, under task_services_use_upstream, sent it straight
to the litellm proxy, which only resolves xai/grok-build-0.1: every
request 401'd (key not allowed to access model) and the seed scored 0.0
on every Terminal-Bench evaluation. Register the model under a plain
openai-compatible provider id with models.<key>.id = the vendor-prefixed
wire id (overridable via VERO_OPENCODE_WIRE_MODEL_ID). This is the exact
change the claude-sonnet-5 claude-code r2 optimizer shipped (0.3426 on
test, 0/36 errors). GAIA seed untouched: its bare gpt-5.4-mini is an
upstream model group.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…the seed tree (opencode targets carry a 2.8 GB install that filled the disk)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…e binary uploads from the host)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comment on lines +118 to +123
# opencode runs inside the task container, which cannot reach the compose-internal
# evaluation gateway. This hands the container the public upstream (OPENAI_*), as
# task-owned services already get; the metered gateway stays on VERO_AGENT_INFERENCE_*
# for in-process agents. Consequence: the target model is fixed by the wrapper, not by
# the gateway allow-list, and its use is audited from the upstream per-key request log.
task_services_use_upstream: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 task_services_use_upstream puts the real OPENAI_API_KEY in the task environment. This target reads that key from optimizer-editable code instead of using the scoped gateway token. A candidate can send direct requests or print the key, while request logs only catch this later. Keep editable code on a reachable scoped gateway instead of giving it the provider key.

The GAIA opencode builds use the same setting.

How this was verified: HarborBackend copies the host provider key into the task environment, and the editable wrapper reads that exact variable.

Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-opt-bench/terminal-bench/baseline/build.opencode.yaml
Line: 118-123

Comment:
`task_services_use_upstream` puts the real `OPENAI_API_KEY` in the task environment. This target reads that key from optimizer-editable code instead of using the scoped gateway token. A candidate can send direct requests or print the key, while request logs only catch this later. Keep editable code on a reachable scoped gateway instead of giving it the provider key.

The GAIA opencode builds use the same setting.

**How this was verified:** `HarborBackend` copies the host provider key into the task environment, and the editable wrapper reads that exact variable.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +104 to +115
env = {
**os.environ,
"BUN_INSTALL_CACHE_DIR": str(cache_root() / "bun-cache"),
# husky's `prepare` hook and interactive prompts have no place here
"HUSKY": "0", "CI": "1",
}
_log(f"tree {key}: bun install")
subprocess.run([bun, "install", "--frozen-lockfile"], cwd=root, check=True,
capture_output=True, text=True, env=env)
_log(f"tree {key}: compile for {platform.system().lower()}-{platform.machine()}")
subprocess.run([bun, "run", "script/build.ts", "--single", "--skip-embed-web-ui", "--skip-install"],
cwd=root / "packages" / "opencode", check=True, capture_output=True, text=True, env=env)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 build_binary runs optimizer-edited install hooks and script/build.ts on the evaluation host. Both commands inherit all of os.environ. This happens before the binary enters the task container, so task isolation does not protect the host. Build candidate source inside a sandbox and pass only the values it needs.

The GAIA copy has the same code.

How this was verified: Agent setup invokes both candidate-controlled Bun commands on the host with the full parent environment before uploading the binary.

Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py
Line: 104-115

Comment:
`build_binary` runs optimizer-edited install hooks and `script/build.ts` on the evaluation host. Both commands inherit all of `os.environ`. This happens before the binary enters the task container, so task isolation does not protect the host. Build candidate source inside a sandbox and pass only the values it needs.

The GAIA copy has the same code.

**How this was verified:** Agent setup invokes both candidate-controlled Bun commands on the host with the full parent environment before uploading the binary.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +187 to +199
for entry in listing.stdout.split(b"\0"):
if not entry.startswith(b"160000 "):
continue
sub_path = entry.split(b"\t", 1)[1].decode("utf-8")
checkout = root / relative / sub_path if str(relative) != "." else root / sub_path
if not (checkout / ".git").exists():
raise RuntimeError(
f"agent_repo contains submodule {sub_path!r} that is not checked out; "
"run `git submodule update --init --recursive` before compiling"
)
archived = subprocess.run(
["git", "-C", str(checkout), "archive", "--format=tar", "HEAD"],
capture_output=True,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 ls-tree returns the gitlink SHA, but this code keeps only the path and archives the checkout's current HEAD. If an initialized submodule is stale or was moved by a developer, the build silently snapshots that other commit. Archive the gitlink SHA or reject a checkout whose HEAD does not match it.

Prompt To Fix With AI
This is a comment left during a code review.
Path: vero/src/vero/harbor/build/compiler.py
Line: 187-199

Comment:
`ls-tree` returns the gitlink SHA, but this code keeps only the path and archives the checkout's current `HEAD`. If an initialized submodule is stale or was moved by a developer, the build silently snapshots that other commit. Archive the gitlink SHA or reject a checkout whose `HEAD` does not match it.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +34 to +49
def tree_hash(root: Path) -> str:
"""Content hash of the source tree, ignoring build outputs and dependencies."""
digest = hashlib.sha256()
for dirpath, dirnames, filenames in os.walk(root):
dirnames[:] = sorted(d for d in dirnames if d not in EXCLUDED_DIRS)
for name in sorted(filenames):
path = Path(dirpath) / name
if path.is_symlink():
continue
digest.update(path.relative_to(root).as_posix().encode())
digest.update(b"\0")
with path.open("rb") as handle:
for chunk in iter(lambda: handle.read(1 << 20), b""):
digest.update(chunk)
digest.update(b"\0")
return digest.hexdigest()[:16]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 tree_hash skips each symlink, including its path and target. The compiler now keeps safe symlinks because opencode uses them as build inputs. A candidate can change such a link without changing the cache key, and build_binary can return the previous binary. Hash the link path and os.readlink(path) value.

Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py
Line: 34-49

Comment:
`tree_hash` skips each symlink, including its path and target. The compiler now keeps safe symlinks because opencode uses them as build inputs. A candidate can change such a link without changing the cache key, and `build_binary` can return the previous binary. Hash the link path and `os.readlink(path)` value.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

Comment on lines +52 to +61
def _bun() -> str:
"""A Bun of the pinned version: on PATH, in ~/.bun, or fetched from GitHub.

The official install script needs curl and unzip on the host; the evaluation
host is not guaranteed either, so fetch the release zip with the standard
library and unpack it ourselves.
"""
found = shutil.which("bun") or str(Path.home() / ".bun" / "bin" / "bun")
if Path(found).exists():
return found

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 BUN_VERSION affects only the fallback download URL. If bun is already on PATH or under ~/.bun, _bun returns it without checking the version. Check bun --version and fetch the pinned release when it differs.

The GAIA copy has the same code.

Prompt To Fix With AI
This is a comment left during a code review.
Path: harness-opt-bench/terminal-bench/baseline/target-opencode/src/terminal_bench_agent/_build.py
Line: 52-61

Comment:
`BUN_VERSION` affects only the fallback download URL. If `bun` is already on `PATH` or under `~/.bun`, `_bun` returns it without checking the version. Check `bun --version` and fetch the pinned release when it differs.

The GAIA copy has the same code.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Fix in Cursor Fix in Claude Code Fix in Codex

…serts the gitlink pin and skips the file checks on an unpopulated tree

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant