Inspiration
Most AI agent demos stop at chat. You type something, the model replies with text, and nothing in the real world actually happens. Meanwhile, the workflows that eat our days — quoting a customer, checking inventory, sending follow-ups — die in inboxes and spreadsheets, invisible and unaudited.
We asked a simple question: what does it take to let an agent actually run a business workflow autonomously — and still keep a human in control? Autonomy without governance is a liability; governance without autonomy is just another dashboard. We built Agent Control Plane (ACP) to prove you can have both.
What it does
ACP runs a complete business workflow end-to-end: a customer emails asking for a quotation → the system ingests the email → an autonomous Gemini agent checks inventory, looks up the customer, generates a quote, and sends it. A human only steps in when policy says so — every step is audited.
- Full execution lifecycle (
QUEUED → RUNNING → WAITING_APPROVAL → COMPLETED / FAILED), persisted in Firestore and live-polled in an ops dashboard - Human-in-the-loop approvals gated by verified Google identity, recorded in the audit trail
- A Tool Gateway enforcing RBAC (agent vs admin), risk classification (LOW→CRITICAL), and per-tool sliding-window rate limits on every single tool call
- Event ingestion from inbound email (IMAP daemon) and CRM webhooks
- Four typed MCP servers (inventory, CRM, email, GCP monitoring) exposed over JSON-RPC 2.0
How we built it
- Gemini 3.5 Flash via Vertex AI, orchestrated by Google ADK 2.7.1 (Agent, Runner) behind our own
/api/executionsservice contract - Cloud Run hosting a FastAPI backend in a multi-stage non-root container, plus a Next.js/TypeScript frontend
- Firestore as the single source of truth: executions, audit events, integrations config, and shared rate-limit state
- Google OAuth for verified human approver identity
- An architecture diagram of the whole system is in the repo (
docs/architecture.svg) and the README walks through local + cloud spin-up.
Challenges we faced
- Distributed rate limiting is silently wrong by default. A process-local limiter works fine until your Cloud Run service scales past one instance — then quotas double invisibly. We moved the sliding window into Firestore transactions, fail-closed, so one shared quota holds across all instances.
- Modeling autonomy and control in one state machine. Making approvals first-class lifecycle states (not side-channel flags) was the design breakthrough that made both fully-autonomous and human-approved runs expressible in the same system.
- Keeping one audit history. It's tempting to log decisions to Cloud Logging and the database; we forced everything into a single Firestore event subcollection so there is exactly one answer to "who did what and why".
What we learned
- Governance is a feature, not friction. The hardest engineering was making the agent's autonomy auditable — and that's exactly what makes it trustworthy enough to run unsupervised.
- Audit beats logging. Structured logs answer "is it up?"; an event-sourced audit trace answers "who did what and why".
- Service boundaries pay off. Because the ADK Runner sits behind our own API contract, swapping agent runtimes never touches the UI.
What's next for ACP
- Real outbound actions. Swap the demo SMTP simulation for a production email transport (Gmail API / SendGrid) so completed workflows send real quotations — the Tool Gateway policy and audit layers stay exactly the same.
- Live streaming updates. Replace the 3-second polling with Firestore listeners / WebSockets for instant lifecycle transitions in the dashboard.
- Deeper agent observability. Emit OpenTelemetry-compatible traces of the full reasoning chain (plan → tool call → result) alongside the existing Firestore audit trail.
- Stronger guardrails. Add inline prompt-injection detection (Model Armor-style) at the ingestion boundary, so untrusted email content is screened before it ever reaches the agent.
- Agent registry. Catalog multiple workflows/agents for cross-team discovery, moving ACP from a single control plane toward an enterprise agent fleet.
- More event sources. Generalize the webhook + IMAP ingestion layer into pluggable connectors (Slack, HubSpot native, ticketing systems).
Built With
- cloud-run
- docker
- fastapi
- firestore
- gemini-3.5-flash
- google-adk
- google-cloud
- google-oauth
- json-rpc-2.0
- mcp
- next.js
- python
- react
- tailwind
- typescript
- vertex-ai
Log in or sign up for Devpost to join the conversation.