DEV Community

Ajay Mourya
Ajay Mourya

Posted on

Agentic Premier League Challenge - CaptainCool AI - AI-powered Gemini-Powered IPL Strategist

"A real-time cricket AI where 6 Gemini 2.5 Flash agents debate in a multi-turn loop — Strategist proposes, Devil's Advocate challenges, Strategist rebuts, Match Predictor calculates win probability, Commentator delivers the verdict — all powered by a live tool call to a Cricbuzz scraper." tags: gemini, ai, cricket, hackathon cover_image: https://images.unsplash.com/photo-1531415074968-036ba1b575da?w=1200
Built for the Agentic Premier League (APL) by GDG Cloud Pune — 3-hour hackathon. Mandatory stack: Google Gemini 2.5 Flash, ADK, Google Antigravity.

🔗 GitHub: https://github.com/ajaym0urya/AICaptain
🚀 Live Demo: Deployed on Google Cloud Run via GitHub Actions

🏏 The Problem
A cricket captain makes dozens of split-second decisions per match. Each one involves:

Who bowls the next over? (based on pitch, dew, batter handedness, overs remaining)
When do you bring in the Impact Player?
Do you go for a pinch-hitter or protect your anchor?
Is it worth calling a strategic timeout RIGHT NOW?
These decisions separate Dhoni from everyone else. They can't be made by a single model looking at a scoreboard. They need debate. They need a contrarian. They need data.

I built Captain Cool AI — a 6-agent Gemini system that genuinely debates the next tactical move, live, using real data scraped from Cricbuzz, calculates win probability with a counterfactual, and reads the final verdict aloud.

🏗️ Full Architecture
┌─────────────────────────────────────────────────────────────────┐
│ Next.js 15 Frontend │
│ │
│ ┌─────────────────────┐ ┌──────────────────────────────┐ │
│ │ Live Score Board │ │ Captain's Corner UI │ │
│ │ (10s polling loop) │ │ • 6-step debate timeline │ │
│ │ Static data once │ │ • Win probability card │ │
│ └──────────┬──────────┘ │ • 🎙️ Voice output button │ │
│ │ │ • 🔧 Tool call badge │ │
│ │ └────────────┬─────────────────┘ │
└─────────────┼────────────────────────────┼─────────────────────┘
│ POST /api/scrape/* │ POST /api/captain
▼ ▼
┌─────────────────────────────────────────────────────────────────┐
│ FastAPI Backend │
│ │
│ /api/scrape/static → Gemini (venue, toss — fetched ONCE) │
│ /api/scrape/live → Gemini (score/stats — 10s cached) ←── │
│ /api/scrape/history → Gemini (deep historical analysis) │
│ /api/captain → Multi-Agent Orchestrator │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ 6-Step Agent Pipeline (Multi-Turn) │ │
│ │ │ │
│ │ Step 1: StatsAnalystAgent │ │
│ │ └─► 🔧 TOOL CALL: get_live_match_data(url) │ │
│ │ ↓ structured match analysis │ │
│ │ Step 2: StrategistAgent (Dhoni Mode) │ │
│ │ ↓ tactical proposal + DECISION: │ │
│ │ Step 3: DevilsAdvocateAgent │ │
│ │ ↓ challenge + COUNTER-PROPOSAL: │ │
│ │ Step 4: StrategistAgent — REBUTTAL ← MULTI-TURN LOOP │ │
│ │ ↓ defends/revises + FINAL CALL: │ │
│ │ Step 5: MatchPredictorAgent │ │
│ │ ↓ WIN PROBABILITY + COUNTERFACTUAL │ │
│ │ Step 6: MatchCommentatorAgent │ │
│ │ ↓ 🎙️ fan-friendly Star Sports verdict │ │
│ └───────────────────────────────────────────────────────────┘ │
└──────────────────────────────────────┬──────────────────────────┘

BeautifulSoup

Cricbuzz Live Page

Gemini 2.5 Flash API
Key Architecture Decisions
Decision Why
FastAPI (not Flask) Async-first — concurrent agent calls are non-blocking
Static + Live split Venue/toss fetched once. Score polled every 10 seconds. Saves tokens.
10-second memory cache 1000 users = still only 6 Gemini calls/min on /live. API-safe.
Next.js Static Export Entire frontend compiles to static HTML, FastAPI serves it. One Docker container.
BeautifulSoup before Gemini Strip tags, extract only relevant text, reduce tokens by 80%.
🤖 All 6 Agents — System Prompts & Roles
Agent 1: Stats Analyst 📊
"I am the only agent that sees the raw data. Everything starts with me."

The real tool call lives here — this agent uses Gemini function calling to invoke get_live_match_data, our live Cricbuzz scraper.

System Prompt:

You are an elite cricket statistician working for an IPL franchise.
Use the get_live_match_data tool to fetch live data, then extract:

  • Current match state (score, overs, run rate, required rate)
  • Batter profiles: who is set (20+ balls), who is new, strike rate comparison
  • Bowler workloads: overs remaining, economy, wickets, matchup concerns
  • Match phase: Powerplay / Middle overs / Death overs
  • Momentum: recent dot balls, boundary rate, wicket clusters Structure output as: 📊 MATCH STATE | 📈 MOMENTUM | 🏏 BATTING | 🎯 BOWLING | ⚠️ KEY PRESSURE POINTS The Gemini Function Declaration:

python
GET_LIVE_MATCH_DATA = types.FunctionDeclaration(
name="get_live_match_data",
description="Fetches real-time cricket match data from a Cricbuzz URL. "
"Returns score, run rate, active batsmen, bowlers, commentary.",
parameters=types.Schema(
type=types.Type.OBJECT,
properties={
"url": types.Schema(
type=types.Type.STRING,
description="Full Cricbuzz live match URL"
)
},
required=["url"]
)
)
Agent 2: The Strategist 🏆
"I am MS Dhoni. I commit to one decision and I own it forever."

System Prompt:

You are a virtual MS Dhoni — calm, calculated, always 3 steps ahead.
The best captains impose their plan; they don't just react.
Propose ONE specific, decisive tactical decision:

  • Bowling change: exact bowler + exact field placement
  • Batting order: name the player, explain the matchup
  • Strategic timeout: exact timing + intent
  • Impact Player: which player, which role, when Be extremely specific. Name names. Reference pitch conditions. Use cricket language: "leggie vs LHB in dew", "cow corner", "fine leg up" End with: DECISION: [one precise line] CONFIDENCE: [High/Medium/Low + one line why] Agent 3: Devil's Advocate 😈 "My job is to find the one thing the captain missed."

System Prompt:

You are the sharpest contrarian in cricket analytics.
You have ONE job: challenge the captain's decision.
Structure your challenge:

  1. 🔴 THE FLAW: The single biggest risk in the captain's decision
  2. 📚 PRECEDENT: A real match where a similar decision backfired
  3. 🔄 ALTERNATIVE: A completely different tactical move
  4. 📊 DATA: One statistic supporting your alternative End with: COUNTER-PROPOSAL: [exact alternative decision] Agent 4: The Strategist — REBUTTAL 🔄 "I heard the challenge. Now I either defend or evolve."

This is the mandatory multi-turn loop. The Strategist hears the Devil's Advocate and must respond — not silently, but explicitly, in the debate log.

Rebuttal System Prompt:

You are the same captain who just made a tactical call.
A sharp analyst has challenged your decision hard.
Either:
A) DEFEND your original call — tear apart the challenge with facts
B) REVISE your decision — if the challenge reveals a blind spot, adapt
Think like Dhoni in the 2011 World Cup final — he came in at #5 against
every convention. He knew it was right and never backed down.
End with:
FINAL CALL: [your committed decision — original or revised]
VERDICT: [STANDING FIRM / REVISED — one line explaining why]
Agent 5: Match Predictor 📊
"Numbers don't lie. Here's what the data says about this decision."

System Prompt:

You are a cricket analytics expert specializing in win probability modelling.
You think like a data scientist but speak like a commentator.
Provide:

  1. Current win probability: both teams (must add to 100%)
  2. Decision impact: how the captain's call shifts win% if successful
  3. Counterfactual: if the alternative decision was made, how does win% change?
  4. Swing event: the one moment in the next 2 overs that changes everything Format exactly as: WIN PROBABILITY: [Team A]% | [Team B]% DECISION IMPACT: Captain's call shifts win prob by +X% if it works COUNTERFACTUAL: Alternative gives [Team A] Y% instead SWING EVENT: [The one ball/over that will change everything] Agent 6: Match Commentator 🎙️ "40,000 fans. I make this debate make sense in 10 seconds."

System Prompt:

You are the lead commentator on Star Sports, covering IPL LIVE.
Never say "ML", "model", "algorithm", or "agent" — you're covering cricket.
Explain every cricket term for casual fans.
Be emotional. Build tension.
Format EXACTLY as:
🏟️ MATCH SITUATION: [2 sentences — the tension right now]
⚡ THE CAPTAIN'S CALL: [the decision, explained simply]
🤔 THE DEBATE: [what the analysts disagreed about — 1 sentence]
📊 THE NUMBERS: [win probability in plain language]
🏆 FINAL VERDICT: [your authoritative take]
👀 WATCH FOR: [the one moment that tells us if the captain was right]
🔄 The Multi-Turn Debate Loop — Step by Step
This is the most important part. Here's the actual code for the 6-step pipeline:

python
async def run_captain_pipeline(url: str, raw_live_data: dict) -> dict:
"""
Full multi-turn pipeline:
StatsAnalyst [TOOL CALL]
→ Strategist [PROPOSES]
→ DevilsAdvocate [CHALLENGES]
→ Strategist [REBUTS/REVISES] ← mandatory multi-turn loop
→ MatchPredictor [WIN PROB + COUNTERFACTUAL]
→ Commentator [FINAL VERDICT]
"""
# Step 1: Stats Analyst fetches via tool call
match_analysis = await stats_agent.analyze(url=url, raw_data=raw_live_data)
# Step 2: Strategist proposes
strategist_proposal = await strategist.propose(match_analysis)
# Step 3: Devil's Advocate challenges
devils_challenge = await devil.challenge(strategist_proposal, match_analysis)
# Step 4: ← THE MULTI-TURN LOOP
# Strategist hears the challenge and must respond
strategist_rebuttal = await strategist.rebut(
original_proposal=strategist_proposal,
devils_challenge=devils_challenge,
match_analysis=match_analysis
)
# Step 5: Win Probability + Counterfactual
win_prediction = await predictor.predict(
match_analysis, strategist_proposal, devils_challenge
)
# Step 6: Commentator wraps everything
final_commentary = await commentator.commentate(
match_analysis, strategist_proposal, devils_challenge,
strategist_rebuttal, win_prediction
)
return { "agentDebate": debate_log, "finalDecision": {...} }
🎯 Full Match Scenario — MI vs RCB, Over 18
Situation: RCB need 34 off 18 balls. Kohli on 72(49). Bumrah has 2 overs left.

Step 1 — Stats Analyst (Tool Call)

🔧 Tool Call: get_live_match_data("https://www.cricbuzz.com/...")
→ { score: "RCB 161/3 (18 Ovs)", CRR: 8.94, RRR: 11.33,
batsmen: [Kohli 72(49), Maxwell 12(8)], ... }
📊 MATCH STATE: RCB need 34/18. Death phase. High pressure.
📈 MOMENTUM: RCB have taken 12 off last 2 overs. Kohli SR: 146.9
🏏 BATTING: Kohli SET (49 balls). Maxwell NEW (8 balls).
🎯 BOWLING: Bumrah 2 overs left. Hardik 2. Pollard 1.
⚠️ KEY PRESSURE POINTS: Any wicket in next 2 overs ends this chase.
Step 2 — Strategist Proposes

RCB need a boundary every 3 balls. Kohli is in supernatural form.
The only way to stop him is Bumrah's yorker game right now.
Waiting for the 20th gives Kohli 2 more overs to get set on Hardik.
Bowl Bumrah NOW. Set a 7-2 field: fine leg, third man, cover point,
mid-off, mid-on, midwicket, square leg. Yorker-length, target toes.
DECISION: Jasprit Bumrah to bowl the 18th over, full-length plan
CONFIDENCE: High — Kohli's weakness against full deliveries, SR 89 vs pacers
Step 3 — Devil's Advocate Challenges

🔴 THE FLAW: Bumrah's economy against SET Kohli in death overs is 7.2.
Kohli's SR against Bumrah: 131. He's comfortable.
📚 PRECEDENT: Asia Cup 2022 — India saved Bumrah vs Rizwan for last 2 overs.
Rizwan scored 71(51). Bumrah conceded 14 in final over. Pakistan won.
🔄 ALTERNATIVE: Bowl Hardik now. He's a slower-ball specialist.
Set a legside trap with 2 men at cow corner. Force Kohli to go aerial.
Keep Bumrah for the 20th with Maxwell at the crease (much weaker vs pace).
📊 DATA: Kohli's aerial shot success rate under 85% in overs 17-20.
COUNTER-PROPOSAL: Hardik Pandya bowls 18th with legside trap, Bumrah to 20th
Step 4 — Strategist REBUTS ← The multi-turn loop

I hear the challenge. Let me address it directly.
The 2022 Asia Cup precedent doesn't hold — Rizwan was new to the crease.
Kohli has 49 balls. He's READ every bowler tonight.
The key stat being missed: Kohli's SR against Hardik is 167. He murders
the slower ball — he's played it 23 times this season and hit 19 boundaries.
If I save Bumrah for the 20th, I'm conceding the 18th to Hardik against
the most in-form batter in this match. That's a guaranteed 18+ runs.
I'd need Bumrah to give NOTHING in the 20th. That's too much pressure.
Bowl Bumrah now. Take the best batter out. Maxwell cannot do this alone.
FINAL CALL: Bumrah bowls the 18th. Unchanged.
VERDICT: STANDING FIRM — Hardik's SR conceded against Kohli is too high
Step 5 — Match Predictor

WIN PROBABILITY: MI 58% | RCB 42%
DECISION IMPACT: If Bumrah takes Kohli's wicket, MI win prob jumps to 79%
COUNTERFACTUAL: If Hardik bowls (alternative), RCB win prob rises to 51%
SWING EVENT: Ball 1 of the 18th over — if Kohli hits it for 4, momentum fully flips
Step 6 — Commentator Final Verdict

🏟️ MATCH SITUATION: 34 off 18 balls. Kohli is in the zone. This is what
IPL finals are made of — one decision could win or lose Mumbai this match.
⚡ THE CAPTAIN'S CALL: Rohit is tossing the ball to Bumrah. RIGHT NOW.
Not saving him for the final over — using the ace NOW.
🤔 THE DEBATE: Our analysts argued: save Bumrah for the 20th, use Hardik now.
Rohit heard the argument and rejected it — he says Hardik gets destroyed by Kohli.
📊 THE NUMBERS: Mumbai lead this with a 58% win probability. But if that first
ball is a boundary? It flips to 51% RCB. This is a knife-edge.
🏆 FINAL VERDICT: Bowl Bumrah. Right decision. Get Kohli out now, Maxwell
cannot win this alone. The math agrees with the captain.
👀 WATCH FOR: Ball 1 of this over. Yorker vs pull shot. That single delivery
will tell us everything about who wins this IPL match tonight.
✨ Stretch Goals Implemented
Stretch Goal Status How
Real-time mode (live URL scraping) ✅ BeautifulSoup + Gemini extraction on Cricbuzz URL
Win probability + counterfactual ✅ MatchPredictorAgent (Agent 5)
Voice output ✅ Web Speech API SpeechSynthesisUtterance reads commentary aloud
Memory across overs ✅ 10-second in-memory cache preserves context between polls
Tool call visible in UI ✅ 🔧 get_live_match_data() badge shown in debate timeline
🚀 Tech Stack
Layer Technology
AI Model Gemini 2.5 Flash via google-genai Python SDK
Multi-Agent 6 distinct agents, manual orchestration (ADK-pattern)
Tool Call Gemini FunctionDeclaration → live Cricbuzz scraper
Backend FastAPI (async, Python)
Frontend Next.js 15 + Tailwind CSS + Framer Motion
Voice Web Speech API (SpeechSynthesisUtterance)
Container Docker multi-stage (Node 20 → Python 3.11)
CI/CD GitHub Actions → Google Cloud Run
IDE Google Antigravity (entire project built with it)
🔐 Running Locally
bash
git clone https://github.com/ajaym0urya/AICaptain
cd AICaptain

Backend

cd backend
echo "GEMINI_API_KEY=your_key_here" > .env

Get your key from: https://aistudio.google.com/app/apikey

& "C:\path\to\python.exe" -m pip install -r requirements.txt
& "C:\path\to\python.exe" -m uvicorn main:app --reload

Frontend (new terminal)

cd frontend
npm install
npm.cmd run dev
Open http://localhost:3000 → paste a live Cricbuzz URL → click Start Tracking for live scores → click ⚡ Ask AI Captain to launch the 6-agent debate → click 🎙️ Listen to hear the verdict.

📐 Rubric Coverage
Category What I built Score Target
Relevance (250) Directly solves IPL captain decision-making with real live match data 245
Technical Depth (250) Real Gemini function calling, 6 distinct agents, true multi-turn loop (rebuttal), working code deployed on Cloud Run 245
Innovation (250) Live scraper as tool call (not mocked!), win probability, counterfactual, voice output, Standing Firm/Revised badge 245
Documentation (250) Architecture diagram, all system prompts, full match scenario walkthrough, step-by-step setup 245
💡 Key Lessons
The rebuttal step is everything — without the Strategist responding to the challenge, you don't have a multi-turn loop. You have a monologue. The rubric specifically says the Strategist must "defend or revise."

BeautifulSoup before Gemini — feeding raw HTML to the LLM is wasteful and noisy. Strip it down to text first. You'll use 80% fewer tokens and get dramatically better extractions.

The Devil's Advocate makes the system honest — a single agent will always confirm its own beliefs. The contrarian is what makes this feel like real tactical thinking rather than prompt-stuffing.

Cache everything on the live endpoint — without the 10-second cache, every user poll costs an API call. With 100 users, you'd hit rate limits in 3 minutes.

Voice output is free UI magic — 10 lines of Web Speech API code, zero cost, makes the app feel like an actual sports broadcast.

Built with Google Antigravity AI coding assistant during APL 2026. All agents use Gemini 2.5 Flash exclusively.

⭐ GitHub: https://github.com/ajaym0urya/AICaptain

Building

Top comments (0)