Skip to content

Redesign VeRO as a generic program optimization harness#41

Open
varunursekar wants to merge 67 commits into
mainfrom
v0.5
Open

Redesign VeRO as a generic program optimization harness#41
varunursekar wants to merge 67 commits into
mainfrom
v0.5

Conversation

@varunursekar

@varunursekar varunursekar commented Jul 15, 2026

Copy link
Copy Markdown

Summary

  • replace the paper-era Policy and experiment model with backend-neutral candidate, evaluation, optimization, runtime, workspace, and coding-agent interfaces
  • support language-neutral command evaluators, optimizer-independent Python tasks, and Harbor as a canonical evaluation backend
  • add a declarative vero.toml workflow, baseline-only vero evaluate, repeatable vero run, and a complete CLI for objectives, constraints, case selection, refs, environments, limits, and concurrency
  • add a checked-in C matrix-multiplication quickstart that compiles, checks correctness, benchmarks, optimizes, selects the faster feasible commit, preserves the target checkout, and cleans up worktrees
  • support sequential and parallel candidate production, durable budgets and reports, external producers, built-in Vero and Claude coding agents, and cancellation-safe concurrent batches
  • make session resume restore candidate lineage, completed rounds, compatible evaluation history, and supported coding-agent state
  • add recursive session discovery, aggregate evaluation inspection, and optional W&B reporting over canonical runtime events
  • add Harbor sidecar, verifier, transport, HTTP/CLI, and task compiler support with trusted policy and finalization boundaries
  • retain both Python and non-Python matrix-multiplication examples while keeping exact paper reproduction on paper/v1 and the paper-v1 tag

Harbor and Modal

  • support Harbor at the outer level by compiling a VeRO optimization into a canonical Harbor task
  • support Harbor at the inner level by evaluating candidate programs through nested harbor run jobs
  • propagate required task-environment secrets to remote Harbor environments without embedding their values in the compiled task
  • support pinned Harbor environment extras such as harbor[modal]==0.18.0 and select an explicit inner Python version
  • preserve both local Harbor selectors and canonical result task names
  • import candidates safely across the outer agent/sidecar UID boundary using exact trusted Git directories

Hardening

  • terminate complete host process groups on timeout/cancellation and terminate the in-container process group for Docker executions
  • reconcile database.json from canonical completed evaluation directories on resume, closing the write-order crash window
  • persist cancelled evaluations as terminal records and make durable budget reservation disk/memory atomic under cancellation; budgets explicitly meter attempted runs
  • use detached candidate worktrees, roll back interrupted copies, and retain evaluated commits under durable hidden refs/vero/... refs without leaking normal branches
  • make the generic evaluation engine fail closed unless authorization is configured; the trusted local factory opts into an explicit allow-all resolver
  • validate optimizer configuration as a discriminated command/agent union so irrelevant fields cannot be silently ignored
  • map backend request rejection to HTTP 400, separate producer and evaluation timeouts in the CLI, lock database readers, and move remaining durable writes off async event loops
  • document aggregate-differencing and shared-container admin-token trust assumptions

Validation

  • complete suite: 379 passed, 6 skipped
  • Ruff checks pass for all changed Python files
  • source distribution and wheel build successfully
  • checked-in C optimizer and advertised Python evaluation example pass end to end
  • live credentialed VeroAgent C matrix-multiplication optimization completed with five agent checkpoints plus baseline and selected an improved candidate (about 5.5x faster in that run)
  • both tracked uv lockfiles pass uv lock --check
  • isolated wheel imports pass for base, Claude, optimize, and Harbor dependency sets
  • deterministic outer-Harbor-on-Modal smoke completed with reward 1.0 and no exceptions
  • real outer Codex (gpt-5) run completed the full nested workflow on Modal: status, candidate validation through inner Harbor, submission, trusted hidden final evaluation through inner Harbor, and outer reward 1.0 with no exceptions

The final live topology is:

Harbor (Modal, Codex) -> VeRO sidecar -> Harbor validation (Modal) -> submit -> VeRO verifier -> Harbor hidden final (Modal)

Greptile Summary

This PR replaces the paper-era VeRO implementation with a fully generic program optimization harness: backend-neutral candidate/evaluation/optimization/runtime interfaces, a declarative vero.toml workflow, Harbor/Modal integration as both outer task and inner evaluation backend, and hardened worktree, budget, and session lifecycle management.

  • Evaluation engine: new EvaluationEngine with authorization resolver, discriminated-union optimizer config, asyncio.to_thread for all durable writes (engine, budget, sidecar, session), and asyncio.TaskGroup-based parallel candidate production replacing the previous asyncio.gather approach.
  • Harbor integration: GitCandidateTransport fetches via unique temporary refs to avoid FETCH_HEAD races, retains commits under hidden refs/vero/… refs, and validates all paths and symlinks before extraction in the build compiler.
  • Unshielded cleanup: in Optimizer._produce_candidate, the finally: await candidate_workspace.destroy() is not wrapped with asyncio.shield, so when TaskGroup cancels sibling tasks the git worktree removal can be interrupted mid-execution, leaving worktrees registered and on disk — unlike temp_copy, which already uses asyncio.shield for the same cleanup.

Confidence Score: 4/5

Safe to merge with the worktree cleanup fix; all other hardening, atomicity, and security changes look correct.

The entire new evaluation/optimization/harbor stack is well-structured and the previously-flagged blocking-write issues are resolved with asyncio.to_thread throughout. One gap remains: Optimizer._produce_candidate calls await candidate_workspace.destroy() in a bare finally block that is not shielded, so a TaskGroup cancellation during parallel production can abort the git worktree teardown mid-way, leaving worktrees registered on disk. All other cleanup paths (temp_copy, budget reservation, session manifest) are already shielded consistently.

vero/src/vero/optimization/optimizer.py — the _produce_candidate finally block needs asyncio.shield on destroy().

Important Files Changed

Filename Overview
vero/src/vero/optimization/optimizer.py New batch-oriented optimizer with parallel candidate production; unshielded destroy() in finally block can leave git worktrees allocated when a parallel task is cancelled by TaskGroup.
vero/src/vero/harbor/transport.py New GitCandidateTransport: resolves agent ref to an object ID before fetching, uses a unique temporary ref to avoid FETCH_HEAD races, retains commits under refs/vero/candidates/, and validates all paths as absolute.
vero/src/vero/evaluation/engine.py New EvaluationEngine with authorization resolver, budget metering, and atomic asyncio.to_thread persistence. Correctly wraps the synchronous write in to_thread (previously-flagged issue is addressed).
vero/src/vero/harbor/verifier.py New CanonicalVerifier for final candidate scoring; the blocking _atomic_write_json inside the asyncio.Lock in finalize was flagged in a previous thread and remains unaddressed.
vero/src/vero/workspace/git.py Refactored worktree management to use --detach, roll back interrupted copies, propagate project_path correctly into copies; temp_copy correctly shields cleanup with asyncio.shield.
vero/src/vero/harbor/sidecar.py Agent-facing sidecar with access policies, aggregate floor enforcement, and correct asyncio.to_thread offloading; previously-flagged sync-write issue is resolved.
vero/src/vero/evaluation/security.py New sanitize_evaluation_report helper that redacts secrets from all free-form report fields while preserving structural identifiers.
vero/src/vero/harbor/build/compiler.py New Harbor task compiler; _safe_extract_tar validates all member paths and symlink targets before extraction.
vero/src/vero/config.py New declarative vero.toml config system with discriminated-union OptimizerConfig validation and path resolution beside the config file.
vero/src/vero/runtime/session.py New durable OptimizationSession with manifest reconciliation on resume and asyncio.to_thread for all manifest writes.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant CLI as vero CLI
    participant Session as OptimizationSession
    participant Optimizer as Optimizer
    participant TG as asyncio.TaskGroup
    participant Producer as CandidateProducer
    participant Workspace as GitWorkspace copy
    participant Engine as EvaluationEngine
    participant Backend as EvaluationBackend

    CLI->>Session: run()
    Session->>Optimizer: run(baseline)
    Optimizer->>Engine: evaluate_candidate(baseline)
    Engine->>Backend: evaluate(request)
    Backend-->>Engine: EvaluationReport
    Engine-->>Optimizer: EvaluationRecord baseline

    loop max_rounds
        Optimizer->>Optimizer: strategy.propose(context)
        Optimizer->>TG: create tasks parallel proposals
        TG->>Workspace: copy from_version parent.version
        TG->>Producer: produce workspace evaluation_gateway
        Producer->>Engine: evaluate_current optional checkpoints
        Engine-->>Producer: EvaluationRecord
        Producer-->>TG: CandidateChange
        Note over TG,Workspace: finally await destroy not shielded
        TG->>Engine: evaluate_candidate new_candidate
        Engine->>Backend: evaluate request
        Backend-->>Engine: EvaluationReport
        Engine-->>Optimizer: EvaluationRecord
    end

    Optimizer-->>Session: OptimizationResult
    Session-->>CLI: best candidate
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant CLI as vero CLI
    participant Session as OptimizationSession
    participant Optimizer as Optimizer
    participant TG as asyncio.TaskGroup
    participant Producer as CandidateProducer
    participant Workspace as GitWorkspace copy
    participant Engine as EvaluationEngine
    participant Backend as EvaluationBackend

    CLI->>Session: run()
    Session->>Optimizer: run(baseline)
    Optimizer->>Engine: evaluate_candidate(baseline)
    Engine->>Backend: evaluate(request)
    Backend-->>Engine: EvaluationReport
    Engine-->>Optimizer: EvaluationRecord baseline

    loop max_rounds
        Optimizer->>Optimizer: strategy.propose(context)
        Optimizer->>TG: create tasks parallel proposals
        TG->>Workspace: copy from_version parent.version
        TG->>Producer: produce workspace evaluation_gateway
        Producer->>Engine: evaluate_current optional checkpoints
        Engine-->>Producer: EvaluationRecord
        Producer-->>TG: CandidateChange
        Note over TG,Workspace: finally await destroy not shielded
        TG->>Engine: evaluate_candidate new_candidate
        Engine->>Backend: evaluate request
        Backend-->>Engine: EvaluationReport
        Engine-->>Optimizer: EvaluationRecord
    end

    Optimizer-->>Session: OptimizationResult
    Session-->>CLI: best candidate
Loading

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
vero/src/vero/optimization/optimizer.py:281-282
**Unshielded worktree cleanup under `TaskGroup` cancellation**

`await candidate_workspace.destroy()` in the `finally` block is not wrapped with `asyncio.shield`. When `max_concurrency > 1` and one `produce(proposal)` task raises, `asyncio.TaskGroup` cancels all remaining tasks by calling `task.cancel()`. Python raises `CancelledError` at the first `await` the cancelled task encounters — which is the `await candidate_workspace.destroy()` call here. The `destroy()` coroutine is then aborted at its own internal `await` (e.g., the `self._sandbox.run` call inside `_remove_worktree`), leaving the git worktree registered and on disk. The `temp_copy` context manager already uses `asyncio.shield` for the same reason, so the fix is consistent with existing practice.

Reviews (6): Last reviewed commit: "Document nested Modal Harbor workflow" | Re-trigger Greptile

Greptile also left 1 inline comment on this PR.

@socket-security

socket-security Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedpypi/​orjson@​3.11.5 ⏵ 3.11.9100 +1100 +1610010070 -30
Updatedpypi/​wandb@​0.23.1 ⏵ 0.28.074100100100100
Updatedpypi/​harbor@​0.20.0 ⏵ 0.18.074100100100100
Updatedpypi/​click@​8.3.1 ⏵ 8.4.296 +1100100100100
Updatedpypi/​uvicorn@​0.44.0 ⏵ 0.51.098 +1100100100100
Addedpypi/​pydantic@​2.13.4100100100100100
Addedpypi/​fastapi@​0.139.0100100100100100
Addedpypi/​fastapi@​0.139.2100100100100100

View full report

@socket-security

socket-security Bot commented Jul 15, 2026

Copy link
Copy Markdown

All alerts resolved. Learn more about Socket for GitHub.

This PR previously contained dependency changes with security issues that have been resolved, removed, or ignored.

View full report

Comment thread vero/src/vero/evaluation/engine.py
Comment thread vero/src/vero/evaluation/budget.py Outdated
Comment thread vero/src/vero/optimization/optimizer.py Outdated
Comment thread vero/src/vero/evaluation/persistence.py
Comment thread vero/src/vero/harbor/verifier.py
Comment thread vero/src/vero/harbor/sidecar.py Outdated
Comment thread vero/src/vero/optimization/optimizer.py Outdated
varunursekar and others added 29 commits July 17, 2026 18:02
…knobs)

load_harbor_build_config resolves ${NAME} / ${NAME:-default} / ${NAME:?msg}
from --param (repeatable) layered over the environment, so run-time knobs —
optimizer model, inner sandbox provider, concurrency — vary without editing/
recompiling the task by hand. Untemplated fields stay fixed (the reproducible
measurement substrate). vero harbor run maps --model to the reserved
${optimizer_model}, so a build whose producer allowed_models references it keeps
codex's model and the gateway allow-list in lockstep (kills the 403 mismatch
that silently wedged GAIA). GAIA build parametrizes environment_name and the
producer model as the first users.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-list

The per-scope model allow-list is role-differentiated, but it is not a hard
guarantee that the target model stays fixed: an adversarial optimizer can
smuggle its producer token into the candidate and reach the shared gateway's
producer scope from the eval sandbox. Record this as a known, deferred
limitation (only exploitable by a deliberately-cheating optimizer); the hard
fix is per-role egress isolation, not path-scoping. Comment only.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 1 of the native-runner modernization. Deletes the VeroAgentHook
token-limit machinery (MaxTokenCountExceededError, the on_llm_start
re-tokenization guard, the max_tokens field) — an approximate, input-only,
mid-run-aborting limit that duplicated what loop config + a metered budget
provide. Limits move to the orchestration boundary.

Bumps openai-agents[litellm] from <0.14 to 0.18.3 to gain the SandboxAgent
API (agents.sandbox: SandboxAgent/Manifest + unix-local/docker/modal/e2b
clients), the substrate for the Stage 3 native rebuild. Full suite green
on the bump (461 passed, 5 skipped); VeroAgent tests unaffected.

(uv.lock secret-scan hit is a false positive: the sentry-sdk sdist SHA256.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…anitization

Stage 3 (substrate). Rebuilds VeroAgent on the OpenAI Agents SDK SandboxAgent:
the harness (model orchestration, tool dispatch, event streaming) runs on the
host while shell/file effects run inside a sandbox via the SDK's Shell +
Filesystem capabilities (real shell, apply_patch). The sandbox is bound to the
candidate checkout's host dir via Manifest(root=...) + UnixLocalSandboxClient
(validated: workspace_root_owned=False, execs land on the host dir, dir is not
deleted), so mid-run evaluation and boundary capture operate unchanged. The
sandbox client is the containment seam (swap to Docker/Modal/E2B later).

default_tool_sets drops bash/file_read/file_write/grep/git_* (subsumed by the
SDK capabilities); only vero-specific tools remain (evaluation, planning).
Deleting those now-unused tool files + the filesystem ACL is a follow-up.

Deletes run_agent_with_json_sanitization (an Anthropic invalid-JSON retry hack);
VeroAgent and SubAgentTool now drive Runner.run_streamed + stream_events
directly. Full suite green (461 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… hooks

Stage 3 cleanup. The SDK Shell/Filesystem capabilities now provide shell/file/
grep/git, so the custom coding tools and vero's in-process access-control are
dead weight:

- Delete tools/{bash,file_read,file_write,grep,git_control,version_control,
  git_viewer,history_viewer}.py. Relocate the subprocess-termination-safety
  helper run_bash_command to utils/asyncio.py (next to run_subprocess_with_tee).
- Remove the filesystem ACL as a security boundary: delete filesystem.py
  (AccessType/AccessRule/WorkspaceAccessPolicy), strip the access layer from
  workspace/base.py (keeping standalone path resolution), workspace/git.py, and
  runtime/context.py's read-access configuration. Enforcement of "don't touch
  the context dir" now rests on the instruction text, not fake in-process ACLs.
- Strip ClaudeCodeAgent's in-process hooks (the PostToolUse auto-commit +
  PreToolUse bash blocklist + ACL-derived disallowed_tools + enable_hooks); keep
  the agent and its cli/config wiring and permission_mode.
- Delete the per-write auto-commit (FileSystemWriteBase.run_and_commit): the
  optimizer already commits the dirty tree at the generate boundary.

Fix tools/__init__ + sub_agent defaults to surviving tools; drop the ACL/tool
tests (test_filesystem, test_write_tools, Grep/FileRead/Bash suites in
test_tools). Full suite green (299 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…eds it)

Live smoke test (native optimizer on circle-packing) surfaced that SandboxAgent's
Shell/Filesystem capabilities register *hosted* tools (apply_patch, shell) which
the SDK only supports over the OpenAI Responses API, not ChatCompletions. The
prior LitellmModel path raised "Hosted tools are not supported with the
ChatCompletions API".

Rebuild the template model on OpenAIResponsesModel with an AsyncOpenAI client
pointed at OPENAI_BASE_URL (the LiteLLM proxy exposes /v1/responses for the
OpenAI-family models it fronts). Default model openai/gpt-5.4, overridable via
VERO_OPTIMIZER_MODEL or VeroAgent.for_model(). model_str() recognizes the new
model type.

Consequence: the native agentic path is OpenAI-family only (Responses + hosted
tools). Non-OpenAI models would need a function-tool variant that drives the
sandbox session directly, or go through Harbor. Documented; not implemented.

Validated live: circle-packing 0.96 -> 2.167 (valid) with gpt-5-mini, mid-run
self-eval and constraint-aware selection working end-to-end. Suite green
(299 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ssion

The live smoke test showed SandboxAgent's hosted Shell/Filesystem capabilities
require the OpenAI Responses API, locking the native path to OpenAI-family
models. Per the "one path, any provider" decision, replace the hosted
capabilities with plain function tools (shell/read_file/write_file, new
tools/sandbox_tools.py) that drive an SDK SandboxSession via session.exec.

VeroAgent is now a plain Agent + LitellmModel (any provider) that creates a
vero-managed SandboxSession bound to the candidate checkout
(Manifest(root=host_path), UnixLocalSandboxClient by default; the client is the
containment seam for docker/modal/e2b). Function tools work over ChatCompletions
OR Responses, so no OpenAI lock-in and no dual code paths. Reverts the
OpenAIResponsesModel default from the prior commit.

Add orjson (litellm 1.92 imports it on its completion path).

Validated live on circle-packing (native optimizer, 1 round):
- openai/gpt-5-mini: 0.96 -> 2.167 (valid)
- anthropic/claude-sonnet-4-5 (LiteLLM/ChatCompletions, non-OpenAI): 0.96 -> 1.686
  (valid) — proving the single path is genuinely model-agnostic.
Suite green (299 passed, 5 skipped). (uv.lock scan hit = sentry-sdk hash, false
positive.)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 2. Introduce a GenerationBackend abstraction so candidate production is a
swappable unit — the native in-process producer (Optimizer default) or a Harbor
run — behind one interface, without changing the working native path.

- Promote the per-proposal production result to a public GenerationOutcome
  (optimization/models.py), documenting the eval boundary: its trial_evaluations
  are the *generation-time feedback* the producer observed while iterating,
  distinct from the orchestrator's separate selection/target scoring.
- Add the GenerationBackend protocol (optimization/protocols.py):
  generate(proposal, parent, context, evaluation_records) -> GenerationOutcome.
- Optimizer gains an optional generation_backend; the production step routes
  through it when set, else the built-in native flow (default None = unchanged
  behavior). The generation-time-vs-selection split already lived in the loop
  (scoped-gateway trial evals vs post-production evaluate()) and is now named.
- harbor/generation.py: HarborGenerationBackend interface skeleton (full
  harbor-run-as-production wiring, reusing GitCandidateTransport, is a follow-on).
- Test: the Optimizer routes production through an injected backend and still
  improves. Suite green (300 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 4. Add a stateful population strategy — the native runner's distinctive
capability over Harbor's single-agent-as-optimizer. Each round it ingests the
disclosed evaluations into a direction-aware fitness archive (via ObjectiveSpec),
keeps the fittest population_size candidates, and emits num_offspring proposals
whose parents are chosen by tournament selection; before any feasible candidate
exists it seeds offspring from the current best (or baseline). Runs directly on
the existing Optimizer (which already fans out N proposals/round concurrently)
and the GenerationBackend seam — offspring can be produced natively or via Harbor.

Fitness reads only disclosed views (EvaluationRecord/Summary objective values);
target/none views carry no objective, so held-out scores never leak into
selection. Only mutation is implemented; crossover (combine two parents) is a
follow-on. CLI/config wiring to select this strategy is a follow-on too.

Tests cover baseline seeding, tournament selection from the fittest population
(infeasible excluded), and minimize-direction ranking. Suite green (303 passed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Stage 5. Wire the coding agent's per-step activity into the structured event
stream so tool calls, reasoning, and messages land in events.jsonl (and any
registered sink, e.g. W&B) live — the native runner's introspection advantage
over opaque environments.

- agent_event_emitter(bus, session_id, agent): adapts an agent's normalized
  serialize_event() stream onto the runtime EventBus (kind="agent").
- OptimizationSession wires each agent producer's on_event to the bus (respecting
  a caller-provided hook); EventSink remains the pluggable observer point.
- VeroAgent.run awaits awaitable on_event callbacks; serialize_event now also
  emits `thinking` (reasoning) events alongside message/tool_call/tool_result.

Non-agentic producers were cut from this stage: for generic code, blind
mutation/crossover operators produce garbage; the agentic producer is the unit
of variation.

Tests cover the emitter (normalized publish, async sinks, no-op for
non-normalizing agents). Suite green (306 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removes genuinely-unused symbols (not forward-looking extension points):
- exceptions.py: the FileEditException hierarchy (NoFilesChangedError,
  InputTooLongError, FileNotTrackedError, StringNotFoundError) and
  CommitNotInBranchHistory — all raised only by the deleted file/git tools.
  Only StreamEventTimeout remains.
- utils/tokens.py: get_token_count — orphaned when the token-limit hook was
  removed (run_result_to_messages kept; still tested/usable).
- VeroAgent + ClaudeCodeAgent: unused introspection helpers with no callers and
  not required by the CodingAgent protocol (tool_set_enabled,
  orchestrator_tool_sets, sub_agent_tool_sets, sub_agents_enabled, reset_trace).

Kept forward-looking/used surfaces: GenerationBackend + HarborGenerationBackend
skeleton, the AgentEvent type vocabulary, AgentRequirements.host_visible_workspace.
Verified by an AST occurrence scan (no removed symbol referenced elsewhere) and
ruff (no unused imports). Suite green (306 passed, 5 skipped).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The matmul pair is a vero-tasks example (matmul-eval is a scale-vero-tasks task
consumed by matmul-kernel's run.py), so it belongs with the task package, not in
vero's core examples. Moved to vero-tasks/examples/; fixed matmul-eval's
scale-vero-tasks source path (../../../vero-tasks -> ../..) and repointed the
vero e2e test at the new location. Test still passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
harbor-circle-packing demonstrates Harbor driving a coding agent (outer loop)
that edits packing.py, with a SIMPLE inner loop — a plain CommandBackend scorer
(harness/evaluate.py), not a nested `harbor run`. This is the custom-sidecar-
factory path (`vero harbor serve --factory circle_factory:build`), the
counterpart to `vero harbor build` (which always nests a harbor eval).

Includes the custom factory (CommandBackend + sidecar disclosure policies +
CanonicalVerifier), the scorer, the target program, task.toml/instruction, and
main+sidecar Dockerfiles that install scale-vero[harbor] (local-checkout install
documented). Objective: sum_radii maximize s.t. valid==1 (baseline ~0.96,
optimum ~2.635).

Mirrors a pattern validated end-to-end earlier; requires Docker + a coding agent
+ model access to run (not covered by the unit test suite). Factory imports
verified against the current API.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The guide described a pre-v0.5 system (.veroaccess ACLs, Policy, VeroResources/
@resource/ResourceControl, core/scaffolds, old vero init tasks / run CLI) — all
removed. Rewrote it around the current model: authoring an evaluation as a
command harness ({workspace}/{request}/{report}, dict-of-metrics report) or a
scale-vero-tasks Python task; running via config (vero init/check/evaluate/run
--config) or one-shot (vero optimize --harness-root/--evaluate/--agent vero);
and the VeroAgent producer (SandboxAgent function tools, any provider via
LiteLLM, sandbox-as-boundary, EvolutionaryStrategy, Harbor for containment).
Points at the real examples (c-matmul, circle-packing, vero-tasks/examples,
harbor-circle-packing).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The README was written at the CLI/config/concepts level that survived the
refactor, so no claims were stale; these are additive updates:
- coding-agent section: the vero agent runs on any provider via LiteLLM with its
  shell/file edits inside a sandbox bound to the checkout; model via
  VERO_OPTIMIZER_MODEL; pointer to the Harbor example for contained producers.
- core concepts: add GenerationBackend; note EvolutionaryStrategy under
  OptimizationStrategy.
- safety boundaries: add the sandbox-as-boundary bullet (containment is the
  sandbox, not in-process checks; Harbor for contained/untrusted).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
"Programs" reads narrowly (a single file), so the title and lead paragraph now
name all three target kinds explicitly — a program (a function up to a whole
codebase), text (prompt/spec/config), or an agent (scaffold, tools, prompts) —
and note that agents are programs treated as a first-class target. Applied to
both the repo-root and package READMEs; broadened the Candidate concept row to
"a program, text, or agent".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…EADMEs

Give the READMEs more visual life (inspired by the sia README), using
GitHub-native mermaid instead of binary image assets:
- badge row (arXiv, MIT, Python 3.11+) on both;
- the optimization loop as a rendered mermaid flowchart (replacing ASCII);
- an architecture mermaid in Core concepts showing the GenerationBackend seam
  (native VeroAgent+sandbox vs contained Harbor run) into the evaluator;
- a Highlights table and a "just want to try it?" callout to the Quickstart.

No PyPI/CI badges: there is no CI workflow, and the `scale-vero` name on PyPI is
an unrelated placeholder, so a version badge would be misleading.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The `scale-vero` name on public PyPI is an unrelated empty placeholder, so
installing it does not get VeRO (and is a dependency-confusion foothold). Switch
all documented installs to a local checkout:
- README quickstart / W&B / harbor sections use `uv sync --extra ...` + `uv run
  vero`, with an explicit "do NOT pip install scale-vero" note.
- The harbor example vendors the package (COPY vero /opt/vero + install from the
  build context) instead of pip-installing the placeholder; README documents the
  `cp -r <repo>/vero environment/vero` step and .gitignore excludes the copy.

The generated program-opt-bench/.../compiled bundle inlines vero/README.md and
will pick up the fix when recompiled. Reclaiming the PyPI name (PEP 541) is a
separate follow-up.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Enable running the VeRO Harbor optimizer as Claude Code with corpus-analysis
subagents baked into its workspace, and make the inference gateway
provider-agnostic.

- inference gateway: drop the hardcoded endpoint allow-list for a
  path-traversal guard (light passthrough to the upstream litellm proxy);
  accept the scope token via x-api-key (Anthropic) or Authorization: Bearer
  (OpenAI). Metering already handled both OpenAI and Anthropic usage shapes.
- workspace_overlays: general build field to bake arbitrary files/dirs into
  the compiled task's /work/agent (git-excluded so injected tooling doesn't
  pollute candidate diffs).
- claude: _compiled_run_environment sets ANTHROPIC_API_KEY/BASE_URL at the
  producer scope (base root, /v1 stripped for the Anthropic SDK); seed +
  overlay-gated instruction nudge.
- vero harbor run --env-file: load run secrets from a dotenv file, applied
  before the compile-time credential check and kept off the command line.
- insights-bundle example: Insights Generator reproduced as Claude Code
  subagents (insights-generator/ig-scout/ig-investigator) + skill + scripts,
  grounded against the real .vero Harbor trace layout.
- GAIA baseline: inject the bundle via overlay; secrets.env.example template.

39 harbor unit tests pass. Validated end-to-end on a full GAIA run
(claude-sonnet-4-6 optimizer; held-out test 0.636 vs 0.576 baseline).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The README was dense and buried Harbor as a ### subsection under "Python API"
(~line 480), opening with "Harbor is also an evaluation backend."

- Reframe the intro + Highlights around Harbor as the recommended backend.
- Add a "Backends" overview near the top: a Harbor-first table with a one-command
  `vero harbor run` teaser and jump links, so Harbor is reachable immediately.
- Promote Harbor to a top-level "Optimize an agent with Harbor" section and move
  it directly after Quickstart (the first backend section).
- Rewrite that section from a ~200-line prose wall into scannable pieces: an
  architecture diagram, numbered build/run steps, a build-knobs table, graded
  boundary bullets, and a security callout. Deep operational minutiae and the
  low-level HarborBackend API move into collapsible <details> blocks.
- Note the gateway now forwards any inference endpoint (matches the
  provider-agnostic passthrough), and demote the command backend to "the lightest
  path when you don't need containment."

All internal anchors resolve; <details> and code fences balanced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Same digestibility pass on the rest of the dense sections:

- Command-harness section: annotate the vero.toml inline so it's self-
  documenting, trim the surrounding prose, and collapse the retry / error-
  threshold / aggregation details into a <details> block.
- Core concepts: rewrite the disclosure/`.vero` prose wall as scannable
  full/aggregate/none bullets plus two tight paragraphs.

Anchors resolve; <details> and code fences balanced.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…runs

The Harbor sidecar's evaluation sub-run silently produced 0 trials for any
task that declares environment variables. tau3 declares them for its
user-simulator (TAU2_USER_*) and NL-assertion grader (TAU2_NL_ASSERTIONS_MODEL),
which makes `harbor run` prompt "Proceed? (Y/n)"; with no stdin the sub-run
aborts (returncode=1). That collapsed to a generic "no matching trials" error
and a budget refund, indistinguishable from a real miss. GAIA declares none,
so it was the only benchmark that ever worked.

- backend.py: pass `--yes` on the sub-run (`_command()`). It is always
  non-interactive, so this is the one correct value; the real credential
  control is `_environment()` (eval-scope token), not the human prompt.
- backend.py: enrich the failure message with found trial-group keys + exit
  code so "produced nothing" is distinguishable from "produced non-matching
  trials" — this is what surfaced the root cause.
- tau3 agent.py: forward OPENAI_API_KEY/OPENAI_BASE_URL into the in-env
  runner exec (the runner is a fresh process; only the host agent had creds).
- tau3 + swe-atlas build.yaml: template the producer allow-list as
  ${optimizer_model:-gpt-5.4} so a non-default optimizer isn't 403'd.

Verified: a claude-sonnet shakedown ran its first dev eval, charged 3/6
cases (a failed eval refunds), with zero eval errors and no prompt aborts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A stateful OptimizationStrategy in the style of the Darwin Godel Machine
(arXiv 2505.22954). Unlike EvolutionaryStrategy's fittest-K tournament, it
keeps the *entire* archive as candidate parents and samples parent p with
weight score(p) / (1 + children(p)) — every archived agent stays reachable
as a stepping stone, while performance and inverse-children bias selection
toward promising, under-explored lineages.

Defaults to a "self" producer (each offspring is the parent's own harness
modifying itself) — the self-referential loop the Godel Machine wanted but
validated empirically. Held-out target scores never enter selection (they
carry no objective in context.evaluations).

5 tests: seed-from-baseline, whole-archive reachability (incl. low/unscored),
inverse-children downweighting, cross-round child tracking, minimize direction.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…orward

A direct probe proved a stock in-container MCP agent solves tau3 (claude-code
scored reward 1.0), so the bespoke two-piece design (host shim + uploaded
runner.py + os.environ cred-forward) was over-built. The tau3-runtime MCP
server is stateful but HEADER-keyed (Mcp-Session-Id), and the session persists
across independent requests — verified by probing the FastMCP endpoint. So no
persistent in-container process is needed.

Rewrite Tau3Agent as a single class whose run() is the whole loop, host-side:
- target-model calls happen host-side via the OpenAI responses API (keeping
  previous_response_id caching); creds come straight from os.environ, which
  Harbor already populates in the agent process (HarborBackend._environment) —
  the cred-forward hack only ever failed because it targeted a separate
  in-container process.
- each MCP call is an environment.exec("curl … tau3-runtime:8000/mcp") into
  main, threading the session id; payloads are base64-encoded so arbitrary
  tool arguments survive the shell.

Deletes runner.py, the in-container mcp/openai install, and the upload/exec
dance. Declares openai as a target dep (host-side import) and relocks. Rewrote
the tests for the new surface (session/JSON-RPC parsing, curl-based tool calls,
full loop with a fake env + stubbed client). Verified live: new agent scores
reward 1.0 on tau3-airline-0 (docker), 6 turns, ~79% prompt-cache hit, no
credential or MCP errors.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In black-box optimization you expect solution quality to rise with budget;
vero (and the paper) found it doesn't. The hypothesis is that budget-*awareness*
changes the solver agent's behavior — given more budget it re-plans (front-loads,
paces, treats "exhaust the budget" as the goal) rather than simply running the
same per-step policy for longer, so quality is flat/non-monotone in budget.

Testing that requires the ability to hide budget from the optimizer while still
enforcing it. Add `disclose_budget` (default True = current behavior) as a master
switch over every channel that leaks budget signal to the agent:
- instruction template: the three always-on budget mentions are now gated, and
  the existing instruct_multifidelity / instruct_exhaust_budget blocks are
  AND-ed with it (both are inherently budget-aware), so disclose_budget=False
  renders zero budget language.
- sidecar `/status`: `evaluation_access[].budget` and `inference_usage`
  (remaining requests/tokens) are omitted when disclosure is off — this closes
  the live quantitative leak (`vero harbor status`), which had no toggle before.

Enforcement/metering are untouched: the budget is still charged and the run
still stops when it's exhausted; the agent just can't see or reason about it.
The budget-blind experiment arm is disclose_budget=False +
instruct_multifidelity=False + instruct_exhaust_budget=False.

Plumbed build config -> compiler (instruction + serve.json) -> deployment ->
EvaluationSidecar, mirroring submit_enabled. Tests: instruction renders 0 budget
mentions and serve.json carries the flag when off; /status omits budget and
inference usage when off.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…-sim/grader)

tau3's environment makes its own LLM calls — the user-simulator (inside the task
container) and the NL-assertions grader (verifier) — which failed with
"Connection error" under vero: the inference gateway is a compose-internal host
(inference-gateway:8001) reachable from the optimizer's `main` (where the agent
runs host-side) but NOT from the modal task containers where those eval services
live. GAIA never hit this (its agent calls the LLM host-side; it has no in-task
LLM service).

Add `task_services_use_upstream` (HarborBuildConfig -> compiler -> HarborBackend).
When set, the eval sub-run's `_environment` points OPENAI_* at the real upstream
(read from the VERO_INFERENCE_UPSTREAM_* vars vero already injects into `main`),
so the task's user-sim/grader reach a real provider; the candidate agent keeps
its metered, model-allow-listed gateway on dedicated VERO_AGENT_INFERENCE_* vars.
This preserves the fixed-target-model control the budget-scaling experiment
depends on — the agent can't switch models — while unblocking the eval services.
`task_environment` injects the TAU2_USER_MODEL / TAU2_NL_ASSERTIONS_MODEL the
tasks otherwise default to gpt-5.2 (not on our proxy).

Tau3Agent reads VERO_AGENT_INFERENCE_* for its client when present (falls back to
OPENAI_*). tau3 build.yaml enables the flag + sets both TAU2 models to
gpt-5.4-mini. 375 registry task.tomls are unpatchable (downloaded per eval), so
the fix lives entirely in vero's env routing.

Tests: backend _environment routing (default gateway vs upstream mode) + its
validation; compiler plumbs the flags into serve.json; Tau3Agent prefers the
dedicated gateway creds.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…use_upstream

The first cut of task_services_use_upstream read VERO_INFERENCE_UPSTREAM_* from
the eval process env, but those are deliberately scrubbed to "" in both `main`
and the eval-sidecar (only the inference-gateway container holds the raw upstream)
— so the tau3 user-sim/grader flipped from "Connection error" to "Missing
credentials". Evals actually execute in the trusted eval-sidecar, so expose the
real upstream to *that* container (like the gateway service) when
task_services_use_upstream is set. The optimizer/main still sees these scrubbed to
"", so the candidate never gains raw upstream access — isolation preserved.

docker-compose.yaml.j2: add gateway_environment (VERO_INFERENCE_UPSTREAM_*) to the
eval-sidecar env under `{% if task_services_use_upstream %}`; compiler passes the
flag into the template context. Test asserts the sidecar gets the upstream while
main keeps it empty.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@varunursekar

Copy link
Copy Markdown
Author

Pushed a batch of work onto v0.5 (clean fast-forward). Highlights since the last state:

tau3 benchmark now runs end-to-end

  • Collapsed the tau3 target to a single host-side Tau3Agent (deleted runner.py + the os.environ cred-forward); it drives the container-internal MCP server via exec-curl and makes target-model calls host-side.
  • task_services_use_upstream: routes a task's own LLM eval services (tau3's user-simulator + NL-assertions grader, which run in the task containers and can't reach the compose-internal gateway) to the real upstream via the trusted eval-sidecar, while the candidate agent keeps the metered, model-allow-listed gateway (VERO_AGENT_INFERENCE_*). Optimizer/main never sees the raw upstream. Verified live: real graded rewards, no connection/credential errors.

Budget-blindness

  • disclose_budget toggle: hides all budget signal from the optimizer (instruction + vero harbor status) while enforcement is unchanged — enables budget-blind optimization runs to test whether budget-awareness is what stops quality from scaling with budget.

Strategy

  • DarwinGodelStrategy: open-ended archive evolution (whole-archive parent sampling ∝ score/(1+children)).

Full vero test suite green (327 passed, 5 skipped).

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