Inspiration

Modern knowledge workers juggle tasks across disconnected tools — a calendar here, a task manager there, emails everywhere. Existing AI assistants handle single-turn queries well but fall apart at multi-step, cross-tool workflows. I built PETAL because I was tired of switching between five apps just to schedule a meeting, create prep tasks, and draft a follow-up email. What if a workspace could act on natural language instead of treating it like a static form?

What It Does

PETAL is a multi-agent AI workspace that combines tasks, calendar, notes, and chat into a unified interface. The system routes natural language requests through specialized agents:

Orchestrator — analyzes intent and delegates to the right agent Task Agent — creates, updates, and manages todos with priority levels and due dates Calendar Agent — schedules events with Google Calendar sync via MCP Info Agent — saves and searches notes and knowledge Users interact through a chat-first interface, and the workspace degrades gracefully when external services (Google Calendar, MCP servers, AI providers) are unavailable.

How We Built It

The backend uses FastAPI with async SQLAlchemy and PostgreSQL (via Supabase). The agent system has two routing layers:

Deterministic keyword routing (routing.py) — fast-path for simple commands like "create task" or "list events" LLM function calling (Gemini 2.0 Flash) — handles complex, ambiguous intents Tech stack:

Frontend: React 18 + Vite, brutalist CSS design system Backend: Python 3.12, FastAPI, SQLAlchemy async Database: PostgreSQL via Supabase AI: Gemini 2.0 Flash (primary), Groq (fallback) Integrations: MCP for Google Calendar and Gmail Deployment: Docker on GCP Cloud Run

Challenges We Ran Into

Multi-agent coordination without a framework. Early versions used Google ADK but pivoted to custom routing + function calling for lower latency and finer fallback control. Graceful degradation. Designing fallback chains so calendar, notes, and chat all work when MCP or AI providers are down — layered fallback: MCP → local DB → rule-based reply. Brutalist UI polish. Heavy borders, stark contrast, and monospace fonts — every spacing and color decision is visible. No hiding behind soft shadows. Async blocking. Non-critical operations (history saves, status updates) competed with chat responses. Fixed with asyncio.wait_for timeouts so user input always takes priority. Supabase + SQLAlchemy integration. Managing async sessions under Cloud Run's auto-scaling required careful connection lifecycle management.

Accomplishments We're Proud Of

Production-ready deployment on Cloud Run with health checks, monitoring, and secrets management Dual fallback AI — Gemini 2.0 Flash primary, Groq secondary, rule-based chat last MCP integration with graceful degradation — local database fallback when external services unavailable Real-time agent status in the UI showing orchestrator, task, calendar, and info agent states Full auth system with Supabase (email/password + Google OAuth) and protected routes Latency under 3 seconds for 95th percentile queries by using hybrid routing

What We Learned

Hybrid routing beats pure LLM routing for latency-critical apps. Deterministic keyword matching handles 80% of requests in milliseconds; the LLM only runs for ambiguous cases. Fallback chains are a feature, not a bug. Designing for failure from day one means the app works even when everything downstream fails. Brutalism is harder than minimalism. Every design decision is exposed — no hiding behind soft shadows or rounded corners. Cloud Run optimization matters. Lazy client initialization, sub-200MB containers, and connection pooling keep cold starts under 5 seconds.

What's Next for PETAL

Voice input — speech-to-text chat so users can dictate requests hands-free Memory layer — persistent user preferences and conversation context across sessions More MCP integrations — Notion, Linear, Slack for broader workflow automation Mobile app — native iOS/Android with the same brutalist design language Self-hosting option — Docker Compose for local deployment without cloud dependencies

Built With

Share this project:

Updates