The problem
Small retailers miss public money. Not because the grants don't exist — the Basque Country, where my pilot city Vitoria-Gasteiz sits, publishes them regularly — but because the eligibility rules live in dense PDFs, the deadlines are short, and a two-person bakery has no grants department. The application itself is the final friction point: forms that demand exact epigraph codes, investment categories and municipal details that the owner half-knows.
I wanted to build an agent that does the heavy lifting — watching, matching, asking, drafting — while being honest about the one thing it must never do: hit "submit" on someone's behalf.

What the agent does
AupaZu is an event-driven pipeline with a human gate at the end:
A Cloud Scheduler job (HTTP + OIDC) wakes the system every morning.
New grant calls are detected and normalized into a typed graph.
A matcher scores each call against each merchant's profile.
If a fact is missing — say, the investment amount — a Gap Analyst agent asks exactly one question over WhatsApp, in plain language.
The merchant's reply updates the profile; the eligibility explanation is regenerated, and every claim carries a citation ID pointing to the official source.
A Draft Builder produces a versioned draft. Confirmed facts only. Anything missing appears as a [PENDING: field] marker — never an invented value.
End to end, the full cycle takes about 85 seconds. You can watch a real run here:
🎥 Demo video (3 min)
How it's built
Google ADK orchestrates six small agents (Orchestrator, Curator, Matcher, Synthesizer, Gap Analyst, Draft Builder).
Gemini 3.7 Flash on Vertex AI does the reasoning; the runtime runs on two Cloud Run services — a private brain and a public webhook that Meta can reach.
Pub/Sub carries domain events (grant.detected, message.received, match.ready, merchant.profile.updated…), each with an event_id for idempotency and a correlation_id that survives the whole journey — visible in Pub/Sub, in Cloud Run logs, and in the case file itself.
Supabase/PostgreSQL is the system of record, with migrations versioned in the repo.
Secret Manager holds every credential; the runtime service account is least-privilege.
Governance is the feature
The most important line of the product is printed on every draft: "DRAFT — AupaZu does not submit the application; human review is mandatory." There is deliberately no submit tool, no endpoint, no button.
That principle shows up in smaller decisions too. The system of record never stores a phone number — only a reference token. Every demo merchant is a fictitious persona flagged is_demo: true inside the database itself. And the repo keeps a written list of everything still imperfect: nine known debts, from missing dead-letter queues to IAM scope. What is written down is never a surprise.
The freeze as evidence
Before the final end-to-end run, I defined the acceptance criterion in the spec: two consecutive full runs under five minutes, no manual retries, with console evidence. The first attempt took ten minutes — a cold pull subscription — so a warm-up run became part of the drill. Then: 1 min 25.6 s, and 1 min 16.8 s, back to back.

The freeze also caught two real bugs the test suite had missed: a database CHECK constraint that rejected the canonical event name merchant.profile.updated, and a webhook validator that returned 403 to legitimately signed Meta callbacks. Both were fixed with migrations, re-verified, and documented with their commit hashes. The freeze wasn't a phase of fear — it was a phase of evidence.
What I learned
Observability designed for operations turned out to be the best demo material: one correlation ID, filterable logs, saved queries.
A written debt list builds more trust with reviewers than a polished claim of completeness.
Next time, specs live in the repo from day one — retrofitting governance works, but costs double.
That is how I believe agents should be built: drafts that are automatic, decisions that stay human, and receipts for everything.
Links
🎥 Demo video https://youtu.be/2iESHE0NlbA
🏆 All Things Agentic Hackathon,
Top comments (0)