Inspiration
I was inspired by the endless context-switching required to manage data pipelines, local AI models, and everyday productivity apps. While orchestrating AI datasets and working on custom hardware projects, I realized how much time is wasted manually shifting data between disparate tools. I wanted to build an autonomous "smart coordinator" that behaves less like a chatbot and more like a background taskmaster—something that actively watches for events, decides on the next logical step, and simply gets the job done across various apps.
What it does
Quantara is an event-driven autonomous routing engine that acts as a smart coordinator for your workflows. Instead of waiting for a prompt, it operates in the background, monitoring for specific data triggers. Once a change is detected, it figures out the next logical step and interacts with various applications to execute complex multi-step tasks from start to finish.
For example, acting as an Automated Product Manager, it can read meeting transcripts, extract action items, create Jira tasks, and post a summary directly to Slack. As a Freelance Pipeline, it can watch an inbox for new inquiries, check availability on a calendar, draft a proposal based on past work, and save it for review.
How we built it
The core decision-making engine is built using Gemini 3.5 and the Google Agent Development Kit (ADK) to process incoming event payloads and autonomously determine the next best action. We hosted the event listener and routing logic on Google Cloud, leveraging Cloud Run to reliably catch webhooks 24/7. When a trigger fires, the system passes the payload to Gemini, which utilizes function calling to seamlessly authenticate and interact with third-party APIs to execute the workflow.
Challenges we ran into
Ensuring the routing engine didn't get stuck in execution loops or misinterpret ambiguous event data was a major hurdle. We had to implement strict validation checks and refine the agent's constraints so that it would safely pause and save its progress for human review rather than executing incorrect API calls when uncertain.
Accomplishments that we're proud of
It runs with nobody watching, and we have the logs to prove it. There is no chat box in this project. An email arrives, Gmail pushes to Pub/Sub, Cloud Run wakes an ADK agent, and the work gets done. In one observed wake-up the agent read the message, queried real calendar availability, generated a scoped proposal in Google Docs, and prepared a threaded reply — four tool calls, start to finish, triggered by nothing but an inbound email:
| step | tool | duration |
|---|---|---|
| 1 | get_email_thread |
448 ms |
| 2 | find_free_slots |
75 ms |
| 3 | create_proposal_doc |
2813 ms |
| 4 | draft_email_reply |
426 ms |
One notification, three runs, three different decisions. A Gmail push doesn't say what
arrived — it hands you a historyId and nothing else. Replaying that history surfaced
three messages in a single wake-up: a newsletter, and two genuine inquiries. The agent
escalated the newsletter as an automated notification and completed the other two. Triage
and execution from one unattended trigger.
Exactly-once effects on at-least-once delivery — eventually. (We got this wrong first; see What we learned. What follows is the version that's actually true, verified live: two emails, two notifications, two runs, no duplicates.)
The guarantee. Pub/Sub guarantees delivery at least
once, so every event eventually arrives twice. For an agent with side effects that's the
difference between one draft and two. Before doing anything the router performs an atomic
Firestore create() on
$$k = \text{source} \mathbin{:} \text{event_id}$$
which fails if the key exists. The failure is atomic, so there's no read-then-write race. Across (n) deliveries of one event:
$$\text{effects}(e) = \begin{cases} 1 & n \geq 1 \ 0 & n = 0 \end{cases}$$
Failure doesn't loop. The router returns 2xx even when the agent fails. That looks
wrong until you think about it: a non-2xx makes Pub/Sub redeliver, so a workflow that
failed on malformed input would fail forever, burning tokens every retry. Failures land in
Firestore and surface on the dashboard. Retrying is a decision a human makes, not a reflex
the infrastructure has.
It stops instead of guessing — and it knows when not to act. Given a message it
couldn't resolve, the agent retried once with a different identifier, failed again, and
called request_human_review with an accurate reason rather than inventing a reply. In a
separate run it was asked only about availability, and it answered with times and
deliberately did not write a proposal nobody had requested. A hard budget of
(s_{max} = 12) tool calls bounds the worst case.
What we learned
Autonomy is an architecture property, not a model property. The instinct is one service that catches the webhook and runs the agent inline. That breaks immediately: a multi-second agent run blows the webhook timeout, the sender retries, and two agents race on the same email. Splitting ingress from execution is what makes background operation possible at all. The interesting work was in the seams, not the prompt.
Gmail's push notification doesn't tell you what arrived. It carries
{emailAddress, historyId} — never a message ID. You have to replay
users.history.list from a stored watermark to learn what actually landed, and one
notification can cover several messages. We built the naive version first, and every real
trigger 404'd. Only a live push exposed it; every earlier test had supplied the message ID
by hand, which quietly tested the wrong thing.
A container has no idea where it is. datetime.now().astimezone() resolves to UTC on
Cloud Run, so "9 to 5 local" silently became 9–5 UTC and the agent started offering a
client 5 a.m. meetings. It even labelled them "UTC" correctly, which made the output look
right while being useless. Business hours are meaningless without a named zone. This is
the bug we'd most likely have shipped, because it passes every test written by someone in
the same timezone as the server.
We proved exactly-once, wrote the formula down, and still shipped a duplicate. The
atomic Firestore claim worked exactly as designed. It was guarding the wrong key. Gmail
sends one notification per arriving message, so two emails sent together produce two
notifications — and both replay the same history window, so both surface both messages.
We'd keyed the claim on historyId + messageId, which made two views of one message look
like two distinct events. Nothing collided. The agent wrote two proposal documents for one
email.
The lesson isn't "handle at-least-once delivery" — we had done that, and had a proof. It's that a deduplication key has to name the thing with the side effect, not the thing that told you about it. We had tested Pub/Sub redelivery, which is the easy case and the one we had thought of. The case that broke it only appears when two messages arrive close enough together to overlap their history windows, which is exactly what a demo does and exactly what a quiet test inbox never does.
Function calling is only as good as the type hints. ADK derives the tool schema Gemini sees from Python signatures and docstrings. They aren't documentation — they're the interface the model reasons over. That changed how we wrote every tool.
Guardrails need to be watched, not just written. The agent once signed a draft
[Operator] — a literal placeholder in something a human would have sent. The escalation
logic worked perfectly the whole time; the failure was in output nobody had read yet. A
tool returning ok=True says the API call succeeded, not that the result was any good.
What's next for Quantara: Autonomous Routing Engine
More sources, same core. The Event schema is deliberately source-agnostic — the
router doesn't know what Gmail is. Calendar changes, Drive edits, GitHub webhooks, and
Cloud Storage notifications all normalize into the same shape and reuse the whole pipeline.
Learning from review decisions. Every escalation is a labelled example of the agent's own uncertainty. Feeding approve/reject history back as context should let the confidence threshold move over time instead of staying hand-tuned.
Multi-agent decomposition. One router currently does triage, planning, and execution. Splitting those into ADK sub-agents with narrower tool sets would shrink each context and localize failures.
Durable execution. The step log is already append-only, so mid-workflow resume is mostly a matter of replaying it — turning a Cloud Run instance dying at step 3 from a lost run into a hiccup.
Governance. Per-tool allowlists, spend caps, and an approval queue with real RBAC: the difference between a personal automation and something an organization would let near its inbox.
Built With
- agent-development-kit
- cloud-run
- fastapi
- firestore
- gemini-3.5
- google-adk
- google-cloud
- pubsub
- python
Log in or sign up for Devpost to join the conversation.