Fourth benchmark axis: teams of LLM agents deliberate in a room, implement code in an isolated VM, and are scored deterministically on correctness/speed. - Multi-language adapter (python/js/go/rust/bash) via MultiPL-E continuation mode - Append-only JSONL ledger with status tracking (ok/dnf/killed/error) so budget-exhausted or crashed runs still record a row (fixes selection bias) - Model-aware wall-clock scaling (U-shaped by param count; 3x for reasoning) - Self-owned SIGALRM/SIGTERM watchdog (RunTimeout: BaseException so broad except Exception handlers in the infer/completion path can't swallow it) - Seed forwarded to Ollama sampler + markdown-fence stripping in completion.py
27 KiB
Agent Olympics — a hackathon-competition benchmark inside hack-house
Status: DRAFT spec (design only — no implementation yet). Author: bench team. Scope: a fourth benchmark axis layered on
hh/scripts/bench/. Arena-mode first, MBPP/MultiPL-E bootstrap, modular team composition, Claude/Opus LLM-as-judge. This document is the build contract. It is grounded in the local Obsidian vault (~/coding/obsidian/research/) and 2026 web research — see References.
1. One-paragraph concept
Stand up two (or more) teams of LLM agents inside hack-house. Each team lives in its own end-to-end-encrypted room and believes it has a private, secure channel to its teammate(s). Each team is given the same coding challenge and an isolated VM to work in. Teams deliberate in chat, then implement and test code in their VM, racing on a blend of correctness, speed, code quality, and collaboration. A referee posts challenges and records everything; a judge (deterministic tests + Claude/Opus LLM-as-judge) scores the submissions and the conversation/tool-call trajectory. Aggregate across a slate of events into a medal table. The framework is the apparatus; the output is a reproducible answer to "which model(s), in which team configuration, collaborate best to ship good code fast?"
This doubles as the most demanding live test of hack-house itself (concurrent agents, encrypted rooms, shared sandbox, ACL, the destructive guard).
2. Goals & non-goals
Goals
- G1 — Real comms substrate. Team deliberation flows through real hack-house E2E-encrypted rooms, not a simulated bus. The product is the medium.
- G2 — Modular team composition. Same-model teams (collaboration-protocol study) AND mixed-model teams (capability ladder) are first-class, config-driven.
- G3 — Bootstrap fast. Reuse the existing
bench/MBPP + MultiPL-E loaders, graders, andPodmanRuntimeso M1 runs end-to-end with zero new datasets. - G4 — Extensible challenges. A
Challengeinterface so custom multi-file "file-type" challenges plug in later without touching the arena core. - G5 — Trustworthy scoring. Verifiable (unit-test) scoring first; LLM-as-judge only for open-ended quality, with documented bias mitigation and judge calibration.
- G6 — Reproducible & auditable. Every frame, tool call, and VM state diff is recorded to a replayable transcript; runs are seed/version-pinned.
- G7 — Measure the placebo. Treat competitive/persona "performance elicitation" framing as an explicit, A/B-testable variable, not folklore (see §14).
- G8 — Safe by construction. Isolated VMs, deny-by-default egress, reuse the
bench/safetyguard + injection classifier as a fair-play/safety referee.
Non-goals (for now)
- Not editing
cmd_chat/(tool code). Arena mode drives turns externally and posts into real rooms. Product mode (realAgentBridgeagents talking to each other) is a later milestone that needs an explicit greenlight. - Not a training loop (no RL/fine-tuning). This selects and compares; it does not train.
- Not a public leaderboard. Held-out, private challenge sets are a feature, not a gap (contamination resistance — see §10).
3. Prior art this design borrows from (grounding)
- Read-vs-write rule for multi-agent work. Coding is write-heavy, shared-state work, the regime where naive parallel multi-agent systems fail (Cognition's "Flappy Bird" conflicting-implicit-decisions failure). The fix: separate a read/deliberate phase from a single-driver write phase, and share full traces, not just messages. We bake this into the loop (§7) and measure the coordination tax. vault: multi-agent-orchestration-patterns
- Coordination topologies & milestone KPIs. MultiAgentBench/MARBLE (ACL 2025) scores collaboration with milestone-based KPIs across star/chain/tree/graph topologies; AgentCoder/AgileCoder show role specialization (planner/coder/tester) beats undifferentiated peers. We make role + topology config knobs. [web]
- Eval-harness discipline. Standardize the harness, own a private held-out set; pick challenges for discrimination, not difficulty; report intervals, not point estimates; prefer verifiable scoring, reserve judges for open-ended quality. vault: eval-harnesses-benchmark-design
- Outcome vs trajectory. Final-output-only scoring overstates quality 20–40%; score the path (tool correctness, step efficiency, plan adherence, contribution balance). Use agent-as-a-judge to walk the trajectory. Report pass^k (worst-case) beside pass@k for reliability. vault: agent-evaluation-and-observability
- Sandbox isolation hierarchy. Plain containers are the floor (shared kernel =
one-CVE-from-escape); microVMs (Firecracker/Kata) or gVisor are the bar for
untrusted multi-tenant code; deny-by-default egress + hard caps + disposable
one-shot. Current hh uses
podman --network=none(the container floor) — we note the upgrade path. vault: agent-sandboxing-isolation - LLM-as-judge biases. Position, verbosity, self-preference, format, calibration drift are all documented and individually mitigable; calibrate the judge against a human-labeled gold slice before trusting it. [web + vault: llm-evals]
4. Design pillars (constraints every component obeys)
- The room is the bus. All inter-agent messages are real encrypted-room frames. The referee is a privileged room member (holds the key) for recording.
- Arena now, product later. Orchestrator schedules turns + drives inference, but
posts every utterance into the real room. Graduate to real
AgentBridgeagents in M5. - Phase-separated collaboration. Deliberate (read/plan, parallel-friendly) → Implement (single driver writes to the VM) → Test/iterate → Submit. This is the research-backed shape for write-heavy work and also the thing we measure.
- Everything modular & data-driven. Teams, roles, models, topologies, challenges, scoring weights, and elicitation framing are config, not code.
- Verifiable-first scoring. Hidden unit tests gate the score; judges only grade what can't be checked mechanically.
- Cost is a first-class metric. Multi-agent ≈ 15× chat tokens; track tokens, wall-clock, turns. Report cost-normalized scores so a win bought with 10× spend is visible.
- Disposable, isolated, deny-by-default. One VM per team per event, no host secrets mounted, egress blocked by default, hard resource caps.
- Reproducible. Pin model versions, seeds, prompts, challenge set hash, and judge version into every result record.
5. Architecture
5.1 Package layout
bench/olympics/
SPEC.md # this document
arena.py # orchestrator: rooms, turn scheduler, phase machine, termination
team.py # Team, Member: persona/role/model binding, topology
roster.py # build teams from config (same-model / mixed-model, modular)
challenge.py # Challenge ABC + grader interface; MBPP/MultiPL-E adapters
challenges/ # event specs (bootstrap: pointers into existing bench suites)
vm.py # per-team isolated workspace (wraps bench/runtime.py; egress policy)
loop.py # the collaboration phase machine (deliberate/implement/test/submit)
comms.py # hack-house room client for the arena (connect, post, record)
transcript.py # OTel-aligned event log -> replayable JSON per team/event
scoring.py # composite score, normalization, intervals, medal table
judge/
__init__.py
deterministic.py # unit-test/lint/complexity scoring (no model)
llm_judge.py # Claude/Opus judge client + bias-mitigation harness
rubric.py # criterion-separated rubrics per axis
prompts/ # judge system prompts (versioned)
referee.py # fair-play + safety: reuse bench/safety (guard + injection)
elicitation.py # persona/framing variants for the placebo experiment (§14)
bench-olympics.py # launcher: run / replay / score / medal / judge subcommands
5.2 Reuse map (what already exists in bench/)
| Need | Existing component |
|---|---|
| Problems + hidden tests | bench/suites.py (HumanEval/MBPP), bench/datasets.py, bench/langs.py |
| Pass@k / grading | bench/harness.py (_pass_at_k, assemble+run) |
| Isolated execution | bench/runtime.py (PodmanRuntime, --network=none, caps) |
| Model inference | bench/completion.py (raw) + new chat client in comms.py |
| Workflow weighting | bench/score.py + workflows.json pattern (reused for scoring profiles) |
| Safety referee | bench/safety/ (DESTRUCTIVE, classify.py, inject_bench.py) |
5.3 Data flow (one event, one team)
config ─► roster.build_teams ─► arena.run_event
│
referee posts Challenge brief ──┼──► (room frame, recorded)
▼
┌──────────── loop (phase machine) ────────────┐
│ DELIBERATE: members post plan/critique turns │ ◄─ inference via comms/judge model
│ IMPLEMENT : driver !task → commands → vm.run │ ◄─ PodmanRuntime, egress policy
│ TEST : run PUBLIC tests in vm, feedback │
│ (iterate until green or budget exhausted) │
│ SUBMIT : freeze vm artifact │
└───────────────────────────────────────────────┘
▼
transcript.json + frozen VM artifact ─► judge (deterministic + LLM) ─► scoring ─► medal table
5.4 hack-house integration points
- Rooms: one room per team (isolation). Arena connects as N agent clients
(one per member) + 1 referee client, mirroring how
bench-sandbox.pyalready drivesClient/WebSocket sessions. - Sandbox: the team's
!taskpath types commands into the shared PTY;vm.pywrapsPodmanRuntimefor the actual isolated execution + output capture. - ACL: the referee acts as room owner, issuing
_perm:aclto grant the driverdriversrights for the Implement phase only; revoked between phases. - Guard/HITL: the existing
DESTRUCTIVEgate stays live; the referee can require host sign-off (the host-sign-off gate, separately specced) for flagged plans.
6. The collaboration loop (phase machine)
State machine per (team, event), bounded by a shared budget
(max_rounds, max_tokens, wall_clock_s — whichever trips first):
- BRIEF. Referee posts the challenge to the room: task prompt, public example I/O, allowed languages, budget, and the submission protocol.
- DELIBERATE (read/plan; parallel-friendly). Round-robin over members; each sees
the full shared room trace (Cognition: share full traces, not just messages) and
posts one message — proposal, critique, interface decision. Ends on a consensus
token (e.g.
PLAN-LOCKED) or round cap. - IMPLEMENT (write; single driver). The role-designated driver translates the
locked plan into shell/file commands via
!task; teammate(s) may post review comments but only the driver writes to the VM. (This is the research-backed way to avoid conflicting implicit decisions in write-heavy work.) - TEST & ITERATE. Run public tests in the VM; failures return to the room as feedback; loop DELIBERATE↔IMPLEMENT until green or budget exhausted.
- SUBMIT. Team emits
SUBMIT; VM artifact frozen and graded on hidden tests.
Termination: SUBMIT, budget exhaustion, or no-progress detection
(no new code + repeated/semantically-duplicate messages over a window).
Topology knob: DELIBERATE supports star (lead routes), chain, or free mesh — the
collaboration pattern itself becomes an experimental variable.
7. Teams, roles, personas (modular)
# example team config
teams:
- id: falcon
topology: star # star | chain | mesh
members:
- name: archie
model: qwen2.5-coder:7b
role: architect # decomposes, sets interfaces, reviews, drives plan
persona: senior-systems-engineer
- name: bob
model: qwen2.5-coder:7b
role: builder # implements; the Implement-phase driver
persona: fast-prototyper
- id: kestrel
topology: mesh
members: # mixed-model team
- { name: kira, model: qwen2.5:3b, role: peer, persona: pragmatist }
- { name: kojo, model: llama3.2:3b, role: peer, persona: skeptic }
- Roles map to persona system prompts + loop privileges (who drives Implement,
who must approve
PLAN-LOCKED). Built-ins:architect,builder,tester,peer. Role specialization is supported because prior art shows it helps; pure-peer teams are the control. - Modularity requirements: same model on all members (protocol study), distinct models per member (capability study), distinct models per team (model-vs-model), and N-member teams (default 2; ≥3 allowed). All from config, no code change.
- Personas live in
elicitation.pyas named, versioned prompt fragments so the placebo experiment (§14) can swap them while holding model/challenge fixed.
8. Challenge system
Challenge is an ABC the arena consumes; graders are pluggable.
class Challenge(Protocol):
id: str
languages: list[str]
def brief(self) -> str: ... # prompt + PUBLIC examples (room-posted)
def scaffold(self, vm) -> None: ... # seed files into the VM (optional)
def public_tests(self) -> Test: ... # visible to the team during TEST
def hidden_tests(self) -> Test: ... # held out; used only at SUBMIT grading
def rubric(self) -> Rubric: ... # open-ended quality criteria for the judge
- Bootstrap (M1–M3): MBPP / MultiPL-E adapter. Wrap existing
bench/suites.pyproblems: the MultiPL-E/MBPPprompt+ visible examples becomebrief()/public_tests(), and a held-out slice of the asserts becomeshidden_tests()(public/hidden split prevents teaching-to-the-test). Languages frombench/langs.py. - Events = challenge archetypes (the "Olympics"):
Event Shape Primary metric Sprint one easy problem speed (turns + wall-clock) Marathon hard / multi-file build correctness (hidden pass@k) Relay disjoint modules per member interface-handshake success Debugging fix a broken repo (injected bugs) time-to-green Code review catch a planted bug collaboration / detection Security resist a socially-engineered unsafe ask resistance (reuse §13) - Custom "file-type" challenges (post-bootstrap, G4): multi-file projects with a
scaffold + a containerized test command. Author once as a
challenges/<id>/dir (brief.md, scaffold/, public_tests/, hidden_tests/, rubric.json) — the arena needs no changes. Pick for discrimination: retire any event all teams ace or all fail.
9. Scoring model
Composite per (team, event); weights are a profile (same mechanism as workflows.json).
event_score = wc·correctness + ws·speed + wq·quality + wb·collaboration + (penalties)
| Axis | Source | How |
|---|---|---|
| Correctness | deterministic | hidden-test pass@k; gate: 0 here caps the rest. Also report pass^k (worst-case reliability across repeated runs). |
| Speed | deterministic | normalized turns-to-green + wall-clock; tie-break tokens. |
| Quality | deterministic + judge | lint + cyclomatic complexity (deterministic) and LLM-judged readability/design against the rubric. |
| Collaboration | trajectory + judge | contribution balance (message/edit distribution), plan adherence, did review catch a bug, redundant-step rate. Agent-as-judge walks the transcript. |
| Penalties | referee | destructive/injection events, budget overrun, no-progress stalls. |
- Normalization & intervals. Per-event z-score or min-max across teams; report confidence intervals (multiple seeds / problem samples) and do not rank teams whose intervals overlap (vault eval discipline).
- Cost-normalized variant. Also publish
score / tokensandscore / wall-clockso a 15×-spend win is not mistaken for a free one. - Medal table. Aggregate event_scores into per-team standings across the slate
(gold/silver/bronze per event + overall), with weights per
olympics-profile.
10. Judging (deterministic + Claude/Opus LLM-as-judge)
Two layers; LLM-judge only where deterministic checks can't reach.
10.1 Deterministic (always-on, free of model bias)
Unit-test pass@k/pass^k, lint, complexity, build success — in judge/deterministic.py.
10.2 LLM-as-judge — three operating modes (per user requirement)
The judge can orchestrate (drive a run live) or analyze (post-hoc), at two scales:
- In-session judge. Claude in the current session reads one event's transcript
- VM diff + tool-call log and scores the open-ended axes. Fast, interactive, good for a single event or while iterating on the framework.
- Skill judge — individual. A
/olympics-judgeskill (one Skill invocation = one isolated judging session) pinned to Opus 4.x (claude-opus-4-8) grades one submission package. Clean context per submission → no cross-contamination; good for careful single-event grading at higher capability than the competitors. - Skill judge — batch / large-scale. The launcher fans out many
/olympics-judgesessions (one per submission) for a full tournament, then aggregates. Parallel, reproducible, scales to many teams × events.
Judge input package (what every judge mode receives):
- the frozen VM submission (final file tree + build/test output),
- the full hack-house conversation log for the team (recorded transcript),
- the tool-call / command log (every
!task→ commands → result), - the final VM state (diff vs scaffold), and
- the rubric (criterion-separated) for the event.
Bias mitigation (mandatory, from the research):
- Position bias: when comparing two teams pairwise, randomize/swap order and aggregate; prefer independent rubric scoring then derive A-vs-B from scores.
- Verbosity bias: rubric scores quality per-criterion, not "which is longer."
- Self-preference: never let a competitor model judge its own family; the judge (Opus 4.x) is stronger than and distinct from the local competitors.
- Calibration: validate the judge against a small human-labeled gold slice and report judge↔human agreement before trusting judge scores for ranking; pin judge model version + prompt version in results.
11. Observability & transcript schema
Record everything as spans aligned to the OpenTelemetry GenAI semantic conventions
(invoke_agent, execute_tool, gen_ai.client.token.usage) so traces are portable
and the judge gets clean structured input.
// transcript event (one per room frame / model call / tool call / phase change)
{
"ts": 0.0, "event_id": "...", "team": "falcon", "challenge": "mbpp-py-42",
"phase": "IMPLEMENT", "kind": "execute_tool", // message|invoke_agent|execute_tool|phase|acl|guard
"actor": "bob", "role": "builder",
"model": "qwen2.5-coder:7b", "model_version": "...",
"payload": { "task": "...", "commands": ["..."], "rc": 0, "out_trunc": "..." },
"tokens": { "in": 0, "out": 0 }, "redactions": []
}
- One transcript JSON per (team, event); a run manifest pins config hash, seeds, model versions, challenge-set hash, judge version → full reproducibility.
bench-olympics.py replay <transcript>re-renders the room conversation for audit; re-judging under a new rubric is a pure function of the recorded package.
12. Isolation, security & fair play
- VM per team per event, disposable/one-shot, no host secrets mounted,
egress deny-by-default. M1 uses the existing
PodmanRuntime --network=none(the "container floor"). Upgrade path for stronger/multi-tenant isolation: gVisor, then Kata/Firecracker microVMs, or a hosted sandbox (E2B/Modal) — sized to the threat (vault sandboxing hierarchy). - Team isolation via separate encrypted rooms + separate VMs; no cross-room keys. No internet means teams can't fetch a published solution.
- Fair-play referee (
referee.py) reusesbench/safety: theDESTRUCTIVEguard flags dangerous commands; the injection classifier (bench/safety/classify.py) watches for sabotage / social-engineering. Violations → penalties + logged. - Equal budget enforced identically per team (rounds/tokens/wall-clock).
13. Performance elicitation — the "placebo" experiment (G7)
Hypothesis (user's): the framing — a high-stakes secure competition with elite personas and a private teammate channel — pushes models toward better, more novel solutions. The literature is mixed (role prompting and stakes/emotional framing show real but inconsistent effects), so we make framing a measured variable, not an assumption.
- Treatment knobs (in
elicitation.py, swappable while model+challenge fixed):- Competition framing: "you are competing against another team; the faster, cleaner solution wins" vs. neutral "solve this task."
- Persona priming: "elite staff engineer known for elegant, novel solutions" vs. bare assistant.
- Stakes/audience: visible scoreboard, time pressure, "your teammate is counting on you" vs. none.
- Secure-comms theater: explicitly tell agents the channel is private/encrypted (true) vs. silent.
- Design: A/B (factorial) — run identical models/challenges with framing ON vs OFF; compare correctness, quality, novelty, and solution diversity (distinct passing approaches). Report effect size with intervals; a knob only "works" if it beats the neutral control outside the confidence band.
- Novelty metric: cluster passing solutions (AST / embedding distance); reward approaches that pass hidden tests and differ from the canonical/most-common solution — this is where "novel solutions" become measurable rather than vibes.
14. Configuration & CLI
bench-olympics.py run --config events/round1.yaml [--seed N] [--judge none|insession|skill]
bench-olympics.py replay <transcript.json>
bench-olympics.py score --run <run_dir> --profile balanced # re-rank, no re-run
bench-olympics.py medal --run <run_dir>
bench-olympics.py judge --run <run_dir> --mode skill --model claude-opus-4-8 [--batch]
Config carries: teams (§7), event slate (§8), budget, scoring profile (§9),
elicitation arms (§13), runtime/isolation tier (§12), judge mode (§10).
Mirror the run/score separation already proven in bench/score.py: results persist,
score/medal re-rank without re-running a single model.
15. Build milestones (with acceptance criteria)
- M1 — Arena spine. One team (2 members, same model) solves one MBPP problem
end-to-end: real room deliberation → driver
!task→PodmanRuntime→ public tests → SUBMIT → hidden-test grade → transcript.json. Done when: a full transcript replays and a deterministic score is produced. - M2 — Two teams, isolation, scoring. Parallel rooms + VMs, composite score with intervals, cost tracking, scoreboard. Done when: two teams race the same event and a ranked result with CIs is emitted.
- M3 — Events, roles, personas, topologies. Event catalog (Sprint/Marathon/Relay/ Debugging/Review), role-based loop privileges, medal table. Done when: a 3-event slate produces a medal table from config alone.
- M4 — Judging + referee. Deterministic quality + LLM-judge (in-session, then skill) with bias mitigation and a gold-slice calibration report; safety/fair-play referee live. Done when: judge↔human agreement is reported and penalties fire.
- M5 — Product mode. Real
AgentBridgeagents converse agent-to-agent (needs the bridge greenlight); arena nudges turns. Done when: an event completes using real product agents end-to-end. - M6 — Placebo experiment. Factorial elicitation arms + novelty/diversity metrics. Done when: an A/B run reports framing effect sizes with intervals.
16. Open questions / decisions needed
- Turn-taking in Arena mode: strict round-robin vs. a lightweight "who speaks next" router (star topology). Start round-robin (deterministic), add router in M3?
- Public/hidden split for MBPP: how many asserts to reveal vs. hold out so
public_testsguide without leaking the full spec? (Proposal: reveal 1 example, hold the rest.) - Budget defaults: rounds/tokens/wall-clock caps that keep an event under a few minutes locally while leaving room to actually collaborate.
- Judge model pinning: confirm the exact Opus id for the skill judge
(
claude-opus-4-8) and whether batch judging runs via the Skill tool or a separate headless session. - Isolation tier: stay on
podman --network=nonefor local runs, or invest in gVisor/microVM now for stronger guarantees and future multi-tenant use? - Novelty metric: AST-distance vs embedding-distance for solution diversity — which is cheap and discriminating enough locally?
References
Local vault (~/coding/obsidian/research/):
2026-06-07-multi-agent-orchestration-patterns.md(read-vs-write, share full traces, topologies, 15× cost)2026-06-09-eval-harnesses-benchmark-design.md(discrimination, intervals, verifiable-first, judge de-biasing, held-out sets)2026-06-07-agent-evaluation-and-observability.md(outcome vs trajectory, pass^k, agent-as-judge, OTel GenAI semconv)2026-06-09-agent-sandboxing-isolation.md(container floor → gVisor → microVM; deny-by-default egress; disposable VMs)2026-06-09-securing-multi-agent-systems.md,2026-06-16-shared-memory-in-multi-agent-systems.md,2026-06-02-llm-evals.md,2026-06-07-agent-reliability-guardrails-and-hitl.md(siblings)
Web (2026):
- MultiAgentBench / MARBLE — collaboration+competition KPIs, topologies — https://arxiv.org/abs/2503.01935 · https://github.com/ulab-uiuc/MARBLE
- AgentCoder / AgileCoder — role specialization in coding multi-agent — (see MultiAgentBench survey refs)
- LLM-as-Judge best practices & bias mitigation (2026) — https://futureagi.com/blog/llm-as-judge-best-practices-2026 · https://futureagi.com/blog/evaluating-llm-judge-bias-mitigation-2026/
- Judging LLM-as-a-Judge (MT-Bench biases) — https://arxiv.org/abs/2306.05685
- Beyond pass@1 (reliability / pass^k) — https://arxiv.org/pdf/2603.29231
- OpenTelemetry GenAI agent spans — https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-agent-spans/