Inspiration
World Cup 2026 tickets are sold by match number, months before the bracket exists. For 32 knockout matches, nobody knows who will play there. If you hold a ticket for Match 87 in Kansas City, the schedule reads "Winner Group K vs 3rd Group D/E/I/J/L". Should you book the flight? Rootin4 answers exactly that: a weather forecast for the seat you already bought.
What it does
- Simulates the entire tournament — all 104 fixtures, FIFA tiebreakers, the third-place allocation matrix, penalty shootouts — 5,000+ times per question from Elo-based strengths. Every probability on the site is an empirical frequency computed live by the engine. No placeholders, ever.
- Updates itself, with no human in the loop. On matchdays, Cloud Scheduler wakes an ops agent (Gemini on Google ADK) that reads a public score wire, validates each completed match against the fixture list, and records it. The score always comes from the wire — the agent chooses which completed fixture to commit, it can never invent numbers. A deterministic fallback sweeps behind it, and the hourly cadence doubles as the retry loop. As we hit submit, Mexico–South Africa is in stoppage time at the Azteca — the next sync will record it without us.
- Re-prices like a market. A recorded result is locked into every simulation and updates both teams' Elo before the remaining fixtures are sampled. Every real event appends a snapshot to a durable probability history — each team row carries a Polymarket-style sparkline of its odds over time, stepping only when reality does.
- Audits itself in Arize Phoenix. Every Gemini call and tool call is traced; the agent reads its own traces back through the Phoenix MCP server, and when the evidence shows a systematic bias it corrects its own Elo priors — publicly, in the site's activity ticker.
- Answers the human question in plain language: "I have a ticket for match 87 — what should I expect?"
How we built it
Two Cloud Run services. The backend is Python 3.12 + FastAPI hosting a code-first Google ADK agent on Gemini 2.5 (via Vertex AI), a NumPy Monte Carlo engine, and a filtered Arize Phoenix MCP toolset over stdio; durable state (results + probability history) lives in Cloud Storage. The frontend is Next.js 16 — server components fetch live data, and the sparklines are server-rendered SVG (zero client JS). Observability is OpenInference auto-instrumentation → Phoenix Cloud, and the agent consumes those same traces as a tool: observability as a capability, not just a dashboard.
Challenges we ran into
- Token discipline. Phoenix's MCP server exposes 27 tools; carrying all the schemas blew the context on every Gemini turn. We filtered the toolset down and built a compact
phoenix_calibration_reportthat summarises spans server-side. - Trusting an autonomous writer. Letting an LLM record facts that condition the whole engine felt wrong — so the agent can only select a wire-validated fixture; score parsing, fixture validation and goal-order alignment are deterministic code, and an idempotent fallback re-checks after every turn.
- The knockout matching problem. Wire events name teams; knockout fixtures name slots ("Winner Group K"). We resolve the real bracket from already-recorded results, so an event can only match a fixture that reality has determined.
- Honest charts. Sparklines only earn a point when something real happens — no synthetic history, which meant designing charts that start nearly empty on day one and grow with the tournament.
What we learned
ADK's code-first agents plus Phoenix tracing turn "the agent audits itself" into a real loop instead of a slogan. And autonomy is a systems problem more than a model problem: validation layers, idempotence and retries bought more reliability than any prompt ever did.
What's next
Nothing — and that's the point. The cron records every match through the final on July 19, the bracket probabilities sharpen exactly when ticket-holders need them, and the agent keeps auditing its own calibration as the evidence accumulates.
Built With
- arize
- fastapi
- gemini
- mcp
- next.js
- numpy
- phoenix
- python
- react
- tailwind
- typescript
Log in or sign up for Devpost to join the conversation.