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

Share this project:

Updates

Submission history