PETAL is a multi-agent AI workspace for tasks, calendar, notes, and chat.
Built with FastAPI, React, Vite, Supabase, and Gemini.
PETAL combines a chat-first interface with specialized agents and MCP integrations so the workspace can act on natural language requests instead of treating them like static forms. The backend is built to keep working even when external services are slow or temporarily unavailable, using local fallbacks for calendar and notes flows where possible.
| Layer | Technology | Badge |
|---|---|---|
| Frontend | React 18 | |
| Vite | ||
| TypeScript | ||
| Backend | FastAPI | |
| Python | ||
| SQLAlchemy | ||
| Database | PostgreSQL | |
| Supabase | ||
| AI | Gemini 2.0 Flash | |
| Cloud | Docker | |
| Google Cloud Run |
PETAL routes natural language requests through a small team of specialized agents:
- Orchestrator — routes requests and manages context
- Task Agent — manages todo workflows
- Calendar Agent — handles event scheduling
- Info Agent — stores notes and knowledge
The frontend is a brutalist, high-contrast interface designed to feel like one coherent workspace instead of separate apps.
In practice, the workspace is organized around four user goals:
- Chat with the orchestrator and let it route requests to the right agent.
- Manage tasks, calendar events, and notes in separate but connected views.
- Monitor backend, agent, and MCP health from the diagnostics and MCP pages.
- Deploy the same app to Cloud Run with clear separation between frontend delivery and backend APIs.
flowchart TB
subgraph Client["Frontend (React + Vite)"]
UI["Brutalist UI"]
SC["Supabase Client"]
API["API Client"]
end
subgraph CloudRun["Cloud Run"]
subgraph Backend["FastAPI Backend"]
Auth["JWT Auth"]
Router["Request Router"]
subgraph Agents["Multi-Agent System"]
Orch["Orchestrator Agent"]
Task["Task Agent"]
Calendar["Calendar Agent"]
Info["Info Agent"]
end
DB["SQLAlchemy + asyncpg"]
end
end
subgraph Supabase["Supabase"]
PG["PostgreSQL"]
AuthSupabase["Auth"]
end
subgraph Gemini["Google Gemini 2.0 Flash"]
AI["AI Inference"]
end
UI --> API
API --> CloudRun
API --> SC
SC --> Supabase
CloudRun --> Auth
Auth --> Router
Router --> Orch
Orch --> Task
Orch --> Calendar
Orch --> Info
Task --> AI
Calendar --> AI
Info --> AI
Orch --> DB
DB --> PG
PG --> AuthSupabase
- Multi-agent routing for task, calendar, and notes requests.
- Calendar scheduling that can sync to MCP-backed Google Calendar when available.
- Notes search and save flows with MCP support plus local fallback behavior.
- Live backend health, MCP status, and agent activity views in the frontend.
- Auth-aware routes with Supabase-backed sign-in, sign-up, password reset, and Google OAuth.
The backend exposes a few useful endpoints for day-to-day operations and deployment checks:
GET /healthfor a fast service health check.GET /api/v1/agents/statusfor current agent states.GET /api/v1/agents/healthcheckfor a deeper routing sanity check.GET /api/v1/mcp/statusfor MCP connectivity and latency.POST /api/v1/chatfor the main chat entry point.
MCP integrations currently cover calendar and Gmail, with notes support optional via NOTES_MCP_URL. Calendar and notes features are designed to degrade gracefully if the external MCP service or database path is unavailable.
sequenceDiagram
participant User
participant UI as Frontend
participant API as Backend
participant Orch as Orchestrator
participant Agent as Specialized Agents
participant DB as Database
participant AI as Gemini
User->>UI: Natural language input
UI->>API: POST /api/chat (bearer token)
API->>Orch: Route to orchestrator
Orch->>AI: Analyze intent + context
AI-->>Orch: Intent + required agents
alt Task intent
Orch->>Agent: Invoke Task Agent
Agent->>AI: Generate todos / update status
AI-->>Agent: Structured response
Agent->>DB: CRUD operations
end
alt Calendar intent
Orch->>Agent: Invoke Calendar Agent
Agent->>AI: Parse event details
AI-->>Agent: Structured response
Agent->>DB: Create / update event
end
alt Info intent
Orch->>Agent: Invoke Info Agent
Agent->>AI: Store / retrieve knowledge
AI-->>Agent: Structured response
Agent->>DB: Note operations
end
DB-->>Agent: Confirm operation
Agent-->>UI: Structured response
UI-->>User: Render updated UI
cp .env.example .env
pip install -r requirements.txt
cd frontend && npm installIf you only want to run the backend, you can skip the frontend install. If you only want to inspect the frontend, the app will still boot with mocked or empty states, but auth and data-backed views are more useful once the backend is up.
Backend:
cd backend
python -m uvicorn main:app --reload --port 8080Frontend:
cd frontend
npm run devFor local development, Vite proxies /api requests to http://localhost:8080, so the frontend can talk to the backend without extra CORS setup.
Use .env.example as the source of truth. Do not commit real keys or secrets.
The repo is configured to ignore .env, service-account JSON files under config/keys/, and Terraform variable files. Keep production credentials in Secret Manager or your deployment environment, not in source control.
Required variables:
DATABASE_URL=
SUPABASE_URL=
SUPABASE_JWT_SECRET=
SUPABASE_ANON_KEY=
GEMINI_API_KEY=
GROQ_API_KEY=
JWT_SECRET=
ALLOWED_ORIGINS=
VITE_API_URL=
VITE_SUPABASE_URL=
VITE_SUPABASE_ANON_KEY=Recommended values by environment:
DATABASE_URLshould point to a reachable Postgres endpoint or the deployment secret used by Cloud Run.GEMINI_API_KEYpowers tool-calling and general orchestration when Gemini is enabled.GROQ_API_KEYis used as a fallback chat provider when Gemini is unavailable.SUPABASE_ANON_KEYis safe to expose to the frontend build, but still should be injected at build time rather than hardcoded.GOOGLE_APPLICATION_CREDENTIALSshould reference a local file only during development; production should use workload identity or Secret Manager.
Backend deployment on Cloud Run:
./scripts/deploy-cloud-run.shFrontend build and deploy:
./scripts/deploy-frontend.shThe frontend Cloud Build requires valid API/WS URLs and Supabase public config at build time. The deploy script reads SUPABASE_URL and SUPABASE_ANON_KEY from .env and injects them automatically.
The backend deploy script writes required runtime secrets to Secret Manager and mounts them into Cloud Run. It also rewrites obvious localhost MCP URLs so they do not accidentally get deployed into production.
Production URLs:
- Frontend: https://petal-frontend-ycmhorzhoa-uc.a.run.app
- Backend: https://petal-api-ycmhorzhoa-uc.a.run.app
If you change these service URLs, update the frontend Cloud Build substitutions and backend CORS configuration together.
Secrets are intentionally excluded from source control.
Ignored by default:
.env,.env.local,.env.productionfrontend/.env,frontend/.env.local,frontend/.env.productionconfig/keys/*.jsoninfrastructure/terraform/*.tfvars- Terraform state files
- Common private key formats
Before pushing, always verify that git status does not include .env, private JSON keys, or generated credential files. If a local secret slips into the working tree, remove it from the commit set before pushing.
backend/ FastAPI app, agents, routes, database
frontend/ React app, components, pages, styles
assets/ Logo and showcase images
infrastructure/ Terraform and migrations
scripts/ Deployment helpers
- The app is designed to run with bearer-token auth and Cloud Run-friendly CORS.
- Build-time frontend env vars are required for the deployed Supabase client.
- If you change deployment URLs, update the frontend build args and the backend CORS origin list together.
- If chat routes but no tool action happens, check the agent health page and confirm Gemini or Groq is configured.
- If calendar requests create local events but do not sync externally, verify
GCAL_MCP_URLand the calendar MCP service health. - If notes search is empty, confirm
NOTES_MCP_URLor rely on the local notes fallback. - If deployment fails, re-run the frontend build with production API and Supabase values and confirm the backend service account can read the required secrets.






