How ReturnPilot works under the hood.
A support agent is easy to demo and hard to trust. These are the decisions that make this one safe to put in front of customers — and cheap enough to run for free.
Architecture
Browser
Chat · reviews · traces
Next.js on Vercel
Auth.js · route guards
FastAPI on Render · one Docker container
LangGraph agent
Checkpoints · interrupt()
MCP server
Order & refund tools
Policy engine
Deterministic rules
Celery + Redis
Idempotent jobs
Groq + Gemini
Free LLMs · routing, fallback, quota guard
Neon Postgres
+ pgvector
Key design decisions
01
The LLM proposes, deterministic code disposes
Eligibility, refund limits and whether a human must approve come from a pure-Python policy engine with exhaustive tests. Write tools only return proposals.
02
interrupt() + Postgres checkpoints
Risky actions pause the LangGraph run at an approval gate. State is checkpointed, so a reviewer can decide hours later and the run resumes exactly where it stopped.
03
customer_id comes from the token
The web server signs a 5-minute ES256 JWT per request. The agent runtime injects the customer id into every tool call — it isn't in the tool schema, so the model can't be talked into reading another customer's data.
04
Idempotent jobs
Refunds and labels run as Celery jobs keyed by sha256(action + target + approval). Double clicks, retries or a restarted worker can't refund twice.
05
Trajectory evals, not vibes
30 scenarios assert the tools called (in order), tools never called, approval routing and zero policy violations — deterministic tier on every PR, live tier nightly.
06
Two free providers + a quota guard
Groq Llama 3.3 for tool use and 3.1-8B for routing, Gemini as fallback. Usage is counted per day; at 90% the router switches, and when both run out the demo degrades to read-only.
07
Per-visitor demo sandboxes
Each browser gets a workspace id cookie; the backend clones the demo store for it. Customer and reviewer personas share it, so one person can play both sides privately.
08
The browser never holds a backend token
Auth.js keeps an httpOnly session; every API call goes through the Next.js proxy, which re-checks the role, mints the JWT and streams SSE through unbuffered.
Stack
Web
Next.js 16 · React 19 · TypeScript · Tailwind v4 · Auth.js v5 · TanStack Query · Recharts · motion
API & agent
FastAPI · LangGraph (Postgres checkpointer) · langchain-mcp-adapters · SSE
Tools
MCP server “commerce” (FastMCP, Streamable HTTP) · local tools for policy search & memory
Data
Neon Postgres · pgvector · hybrid retrieval (vector + full-text, RRF) · Alembic
Jobs
Celery + Redis in-container · retries with backoff · beat for expiring approvals
Monthly cost
No card is entered anywhere. Every service suspends or rate-limits at its free limit instead of billing.
| Service | Used for | Cost |
|---|---|---|
| Vercel HobbyNext.js web app | Next.js web app | $0 |
| Render free web serviceDocker backend (API, agent, MCP, worker, Redis) | Docker backend (API, agent, MCP, worker, Redis) | $0 |
| Neon freePostgres + pgvector, 1 GB | Postgres + pgvector, 1 GB | $0 |
| Groq free APILlama 3.3 70B / 3.1 8B | Llama 3.3 70B / 3.1 8B | $0 |
| Google AI StudioGemini fallback + embeddings | Gemini fallback + embeddings | $0 |
| GitHubCode, CI, eval and cron workflows | Code, CI, eval and cron workflows | $0 |
See it run
Sign in as Maya and ask about her boots. It takes three minutes.