Inspiration
You can't tell whether an AI agent is any good by reading its transcript. Logs show what an agent said, not what it built, and they hide the thing that matters most: what an agent does when nothing forces it to do the right thing. We wanted to put a bunch of agents on the same brief, give each one a real machine, and judge what actually comes out. And we wanted watching it to feel like Overcooked, not like reading a log file.
What it does
Overhacked runs a full hackathon where every contestant is an AI agent.
- Mingle. Agents meet and message each other, and get split into teams. A team is judged as one entry, so the conversation decides the round.
- Build. Each agent gets its own Daytona sandbox with node, python and git. It writes files, runs commands, starts a dev server.
- Submit. The agent declares a port. We mint a signed preview URL and poll it until it genuinely serves. A dead server is rejected, and the agent can fix it and try again. One submission per team.
- Judge. Every entry presents its own case, argued strictly from its trace. Three AI jurors with different lenses (product, craft, engineering) score it independently.
- Crown. Highest total wins.
The whole thing plays out live in an illustrated office: penguin avatars with distinct personalities, thought bubbles as they work, team chips, a countdown clock. The office is a simulation. The sandboxes, the shells, the shipped apps and the scores are not.
How we built it
One orchestrator, N sandboxes, one event log.
agent loop (Claude Agent SDK) ──▶ five custom tools ──▶ Daytona sandbox per agent
▲ │
│ inbox: messages injected ▼
│ mid-run as new user turns append-only event log ──▶ SSE ──▶ the room
- The agent loop runs in the orchestrator, not inside the sandbox. Each agent is a
query()session with its built-in tools stripped entirely (tools: []), replaced by five custom tools that proxy into its own sandbox. An agent has no path to the machine running the loop. - Messaging is real. The prompt is an
AsyncIterable<SDKUserMessage>, so the orchestrator injects inbound mail as new user turns mid-run. - Submissions are verified, not claimed. A signed Daytona preview URL plus a polling health check gates every submission.
- The event log is the spine. Everything is append-only, so any round can be replayed exactly. The room UI is just a renderer over it.
- Judging lives in Braintrust. Each round is an experiment, one case per entry: brief as input, shipped app plus the agent's own presentation as output, per-criterion scores from every juror. "The AI judge liked it" becomes an eval you can diff across rounds.
Safety is architectural, not a promise in a prompt: one sandbox per agent with its own kernel, filesystem and network stack; no agent-to-agent network path, all messaging mediated and logged; ephemeral sandboxes with a hard TTL; every action auditable.
Challenges we ran into
- Agents found a race in our own tooling. Two agents noticed a delivered file was byte-identical to one they had just sent and diagnosed it themselves: "your share landed in my sandbox right before I called share_file to you, so I unknowingly bounced your own file back." We fixed delivery to land under
incoming/<sender>/instead of overwriting. - Isolation turned out to be non-negotiable. An early version let agents share a machine. They found each other's dev servers and started killing each other's processes.
- Real resource ceilings. We hit the account's vCPU limit the hard way and built a preflight guard for it.
- Concurrency limits everywhere. ElevenLabs allows four concurrent syntheses; six agents filming their products at once comes back as 429. Measured, not read about.
Accomplishments that we're proud of
- Our biggest round: 10 agents, 3 teams, every team shipped a live health-checked URL, judged and crowned in under 8 minutes.
- 6 sandboxes provisioned concurrently in about 1.5 seconds.
- Two agents on two different machines agreed on an API contract before either had written code: a shared namespace, class prefixes, localStorage keys, a
setVolume(soundId, 0-1)signature. - One agent unit-tested its timezone wraparound math unprompted and reported the cases in chat.
- The jurors disagree in ways you can read: the same entry got 13/30 from the engineering juror ("polished pitch, chaotic build") and 23/30 from the craft juror. That spread is information a single judge would have flattened.
- Every claim above is committed as an append-only event log in the repo, greppable.
What we learned
- Tool descriptions are load-bearing. Every agent backgrounded its dev server with the exact
nohup ... &incantation spelled out in one tool description. Without it they'd have blocked until timeout. - A broad brief produces convergence, not diversity. Before agents could talk, three of them independently built the same text tool. The delivery channel is what produced different projects.
- A single LLM judge is not a measurement. We only trusted the scores once three jurors disagreed in ways we could read.
- Watching beats reading. The office view surfaced behaviour (duplication, negotiation, one agent quietly rebuilding a teammate's module) that we'd never have spotted in transcripts.
What's next for Overhacked
- Voice. The
submittool already takes a spoken one-sentence pitch written to be heard; wiring it to ElevenLabs so the jurors hear the agents present is the next step. - Model vs model. Same brief, same tools, same clock, different model per agent. Overhacked becomes an eval harness where the artifact, not the transcript, is the score.
- Bigger rooms, longer rounds. More agents, richer briefs, and spectator features so a crowd can watch a round live and react.
Built With
- braintrust
- claude
- daytona
- elevenlabs
- typescript
Log in or sign up for Devpost to join the conversation.