This post is my submission for DEV Education Track: Build Multi-Agent Systems with ADK.
What I Built
Focus Three takes a messy free-text brain dump and gives back the three things you should actually do today, with the reasoning attached. By messy I mean the usual: items are vague, deadlines are implied rather than stated, and half the entries are really three tasks in a trenchcoat.
Ranking is not the hard part. The hard part is that one prompt asked to prioritize a list will skip items it does not understand, quietly merge two tasks into one, and still hand back a confident top three that leaves out the thing that was on fire. None of that shows up in the output. Splitting the job across specialists made each failure surface somewhere I could fix it.
Cloud Run Embed
Paste in your own brain dump and watch it run. The frontend streams progress events, so you can see each specialist report in before the final three appear.
Give it a minute on the first run. The services scale to zero, so a cold start wakes five containers before the first agent speaks; after that a run takes about a minute.
All six services carry the DEV label from the embed guide:
gcloud run deploy focus-three \
--source . \
--region us-central1 \
--allow-unauthenticated \
--labels dev-tutorial=blog-devcommunity2026
Your Agents
Four LLM agents, all running gemini-3-flash-preview, each with one job, plus a small Python step that drives the retry loop.
Task Analyzer. Parses the raw dump into atomic tasks. It splits compound items, estimates effort in focused minutes, and records the exact source fragment each task came from. It emits a Pydantic TaskList instead of prose, so nothing downstream has to re-parse English.
Coverage Validator. The quality gate. It reads the original input alongside the parsed list and asks one question: is everything accounted for? Unsplit compound items, dropped fragments and tasks still too vague to act on all earn a fail plus specific feedback. It returns a strict pass/fail schema and is blocked from delegating or chatting, so a verdict is the only thing it can emit.
Escalation check. Not an agent, just Python, running in-process inside the orchestrator. It reads the validator's verdict out of shared session state and yields an event with escalate=True on a pass, which is the signal the parent loop catches to break out. On a fail it yields a plain event and the loop runs again with the feedback in context.
Urgency Checker. Scores each task 0-100 on deadline pressure and consequence of delay, with a one-line justification per task. I kept it separate from the final pick so scoring and selection can be debugged on their own.
Focus Agent. Picks the final three. Not just the top three by score: it enforces a shape on the day, so it will not hand you three four-hour tasks, and it always includes at least one quick win.
The Task Analyzer, the Coverage Validator and the escalation check sit inside a LoopAgent capped at three iterations. That loop, the Urgency Checker and the Focus Agent sit inside a SequentialAgent. Six Cloud Run services in total: the four LLM agents, the orchestrator and the frontend, wired together over A2A with agent-card URLs passed in as environment variables.
Key Learnings
The hard part was getting honest answers, not good ones.
Separating scoring from selection is what fixed that. Once the Urgency Checker has to publish a number and a one-line justification for every task, the Focus Agent cannot quietly drop the expensive ones. It has to argue for what it left out. On the test dump it returned the login bug (120 min, urgency 95), the slides (90 min, urgency 88) and the dentist (15 min, urgency 50), then explained that replying to the twelve emails scored higher urgency than the dentist but would have pushed the day to 255 minutes against a 240-minute budget. That trade-off note is the output I trust most, and it only exists because two agents disagree in the open instead of one agent deciding in private.
Constraining an agent turned out to be mostly about taking capabilities away. The Coverage Validator returns a strict pass/fail schema and is blocked from delegating or replying conversationally, so a verdict is the only thing it can produce.
Stack: Google ADK + A2A + Cloud Run + Gemini 3 Flash Preview
Top comments (0)