⊹ The Autonomous AI Travel Architect

The whole flow of Kompass,
visualized piece by piece

One message in chat fans out into a planning agent, two MCP servers, a grounded research sub-agent, a stress-scored set of trip scenarios, and a live map — all streamed back to you in real time. Here's exactly how a request travels through the system.

FastAPI + PydanticAI 🤖 Gemini 2.5 Flash 🔌 AG-UI over SSE
▾ explore the system
9
Agent tools
8
Ports & adapters
30
Eval cases
10
Evaluators
00 — Prefer to read?

The full written docs

Reference pages for anyone who wants the details instead of the demo — start with how it's built and how it's measured.

Reference

🏗️ Architecture

Hexagonal backend, agent tools, MCP integrations, persistence, and the frontend component map.

Explore the system →
Reference

🧪 Eval Learnings Log

What running a real LLM eval suite found — regressions caught, root causes, and fixes, updated live.

Read the log →
Reference

🚀 Product

Every feature across 8 categories, with the phase that delivered it.

See the feature tracker →
Reference

🎨 Design

The Candy theme: color palette, typography, motion, and the UI component map.

Browse the design system →
Reference

✅ User Stories

All 16 stories from the product spec, traced to the tool or component that delivers each one.

Check the story matrix →
01 — The map

Four layers, one streaming pipe

A Next.js client talks to a FastAPI backend over the AG-UI protocol. The backend hosts a PydanticAI agent that reaches out to external data sources. Tap any block to learn what it does.

FrontendNext.js · React 19 · CopilotKit v2 · "Candy" theme
CopilotChatconversational UI
Generative-UI cards8 streamed tool renderers
Trip / Saved sidebarresume · bookmark
Interactive map panelroute + markers
⇅   SSE stream (AG-UI protocol)
FastAPImain.py lifespan · api/routes.py
POST /api/copilotkitthe streaming endpoint
REST: trips · profile · savedsession + memory
SQLite persistenceSQLAlchemy + aiosqlite
AgentPydanticAI · Gemini 2.5 Flash
kompass_agentoutput: str
9 agent toolsthe toolbelt
research sub-agentGemini grounding
ExternalMCP servers · grounded search · tracing
Kiwi.com MCPflights · remote HTTP
SerpApi Hotels MCPaccommodations · stdio
Gemini groundingweb + ground transport
LangfuseOpenTelemetry traces

Click any block above 👆

Each piece of the architecture has a specific job. Select one to see what it owns and where it lives in the codebase.

02 — The journey

A single request, step by step

Follow one travel request from the chat box all the way to a saved, mapped itinerary. Press Run the flow to auto-advance, or click any step.

03 — The agent's hands

The toolbelt

The agent decides which tools to call and in what order. Each call streams a generative-UI card into the chat. Click a tool to expand it.

04 — Where the truth comes from

Live data sources

Kompass never invents prices. Structured data comes from real providers; grounded search fills the gaps and acts as the fallback.

Flights

Kiwi.com MCP

The official remote Kiwi MCP search-flight tool over streamable HTTP — no API key. Client-side max_stops / time filtering; cheapest-date sampling fires concurrent ±3-day flex searches.

Stays

SerpApi Google Hotels MCP

A local FastMCP stdio server (accommodations_server.py) wrapping SerpApi. Returns nightly + total rates, ratings, amenities, links. MCP_MODE=mock serves deterministic fake data to save quota.

Knowledge

Gemini grounding sub-agent

An isolated PydanticAI agent using native Google Search grounding — destination research, ground-transport (train/bus/ferry) routing, and the price fallback. Kept separate so grounding doesn't collide with structured output.

Memory

SQLite

Async SQLAlchemy + aiosqlite. trips store the full AG-UI message_history so cards rehydrate on reload; plus user_profiles (singleton) and saved_scenarios.

🛡️
The reliability contract. When a source errors or returns nothing — Kiwi unreachable, SerpApi key missing — the tools return no fabricated data (flights: empty list; accommodations: available: false) and the agent falls back to grounded search_web. Prices are never invented. For flights, a transport failure raises KiwiTransportError instead of silently returning an empty list, so search_flights/find_cheapest_dates can tag the fallback with data_source_error: true — a dead connection stays distinguishable from Kiwi genuinely finding zero itineraries.
05 — What you actually see

Generative-UI card gallery

Every tool call renders a purpose-built card, streamed live with animated loading states. Here's the family.

🎯 Preferences
Direct flights4★ hotelstrain okfoodie
preferences-card.js
❔ Clarify (HITL)
BeachCityMountainsOther…
clarify-card.js · pauses the run
📅 Cheapest dates
€212
≈ approx
cheapest-dates-card.js
✈️ Flights
€189
flights-card.js · Kiwi
🏨 Stays
★ 4.6wifipool
€96/night
accommodations-card.js · SerpApi
🔎 Research
research-card.js · grounded
🚆 Ground transport
train2h 40m€18–34
ground-transport-card.js
⚖️ Scenarios
€640
stress
Best value
scenario-comparison-card.js
06 — Why it's clean

Hexagonal architecture

The agent core depends on ports (interfaces), never on infrastructure. Adapters plug the real world in — so a mock hotel server or a different DB is a one-line swap.

Adapters
Kiwi MCPmcp_flight_service
SerpApi MCPmcp_accommodation
SQLite repossqlite_*_repository
Ports
FlightServicePortsearch · dates
AccommodationPortsearch
Repositoriestrip · profile · saved
Core domain
kompass_agent+ tools
Domain modelsTrip · Scenario · Itinerary
AgentDependenciesinjected deps
07 — Under the hood

The tech stack

Backend
  • FastAPI
  • PydanticAI
  • Gemini 2.5 Flash
  • Python 3.14 · uv
Protocol
  • AG-UI over SSE
  • MCP (HTTP + stdio)
  • OpenTelemetry
Frontend
  • Next.js 16
  • React 19
  • CopilotKit v2
  • Tailwind CSS v4
Data & maps
  • SQLite + SQLAlchemy
  • aiosqlite (async)
  • @vis.gl/react-google-maps
Observability
  • Langfuse v4
  • per-trip session traces
  • no-op without keys
Quality
  • pytest (backend)
  • Vitest (units)
  • Playwright (e2e)
  • Agent evals (evals/)