Skip to content

Repository files navigation

Deploying Agentic AI Applications

Note

Ship your agent on a 100% free stack. Hands-on workshop · 90 minutes

Your agent works beautifully on localhost. Then you deploy it, someone clicks "Run", and 30 seconds later the request dies with a 504.

This repo is about the one architectural decision that fixes that — and a complete, working, deployed example of it.

The one idea

Tip

Never run the agent inside the HTTP request

Accept the job, return an ID immediately, do the work in the background, let the client poll. Every timeout problem dissolves once that clicks.

POST /runs        →  202 {"run_id": "abc"}        ~200 ms, always
[background]      →  agent runs, writing each step to the database
GET  /runs/abc    →  {status, steps[]}            client polls every 1.5 s

The demo agent researches with Wikipedia, searches the live web through Tavily's MCP server when you give it a key, and holds a conversation — ask a follow-up and it remembers, because the history lives in Postgres rather than in the browser tab.

Start here

If you… Go to
want to learn this properly the workshop website — Learn → Build → Deploy
want it running in 5 minutes Quick start below
are running it yourself docs/ — run of show, prep, prerequisites
want the slides slides/index.html — open it, no build step

The website is the main thing. It's written so someone who wasn't in the room can go from nothing to a deployed agent on their own.

Quick start

You'll need a free Gemini API key and a free Supabase project. A free Tavily key is optional — it adds web search, so the agent can answer questions about recent events instead of only what Wikipedia has written up.

Important

Never commit your API key or database credentials. Use .env and .gitignore.

# 1. install uv (one tool for Python, venvs, and packages)
curl -LsSf https://astral.sh/uv/install.sh | sh

# 2. install dependencies — exact versions, from app/uv.lock
cd app && uv sync

# 3. your keys
cp .env.example .env            # then fill in the three values

# 4. create the tables
#    paste database/schema.sql into the Supabase SQL editor and run it

# 5. go
uv run fastapi dev main.py

Check http://localhost:8000/health — you want {"ok": true, "database": true}. It also names the provider and model answering, and whether web search is on.

Then start the client, in a second terminal from the repo root:

cd client
npm install
npm run dev                     # http://localhost:5173

Open http://localhost:5173, ask a question, and watch the steps appear.

Now tick "Naive mode" and ask again. Same agent, same answer, but a blank 30-second wait. That's the bug this whole project exists to fix.

Other useful commands

cd app && uv run --extra dev pytest                # 37 tests, no keys or network needed
cd client && npm run build                         # type-check + build the client
cd website && npm install && npm run dev           # the workshop website, locally
cd app && uv run python -m agent.manual_loop "..."  # the agent, no framework, from the CLI
cd app && uv run fastmcp dev tools/server.py        # poke the MCP tools in the Inspector

What's in here

├── app/                  the deployed application — its own uv project
│   ├── pyproject.toml    dependencies, pinned by app/uv.lock
│   ├── main.py           the API — /runs vs /runs/naive is the whole lesson
│   ├── agent/            the agent, plus the same loop written by hand
│   ├── tools/            the tools, and the same tools over MCP
│   ├── tests/            37 tests that need no API key
│   └── http/             ready-made requests for driving the API by hand
├── client/               the client — Vite + React + TypeScript
│   └── src/
│       ├── api.ts        the five HTTP calls — the whole backend contract
│       ├── useConversation.ts  accept-and-poll + threads, with cancellation
│       └── useHealth.ts  which model is answering, from /health
├── database/schema.sql   three tables
├── deploy/               Render blueprint — the only platform-specific file
├── slides/               the deck
├── website/              the workshop website + slides route (Astro)
└── docs/                 run of show, prep, prerequisites, free-tier notes

The stack

Layer Choice Free tier
Model Google Gemini via AI Studio yes, no card
Agent Pydantic AI open source
Tools FastMCP, mounted at /mcp open source
Backend FastAPI on Render or FastAPI Cloud yes, no card
Database Supabase Postgres + pgvector yes
Frontend Vite + React on Vercel or GitHub Pages yes

Total cost: nothing, and no credit card at any point.

Those are defaults, not requirements. The model is three environment variables (other free providers — Cerebras, OpenRouter, Groq) and the host is a deploy setting (other free hosts — Hugging Face Spaces, Fly.io, Koyeb). Pick whichever you like; the architecture doesn't change.

Free tiers have real trade-offs — your server sleeps, your database pauses, your model rate-limits. The Stack section is honest about all of them.

Deploying: two tracks, both free

"Deploying the app" is really two separate jobs, and only the first one is hard.

1 · The agentapp/, a FastAPI process that must keep working after it has sent the response. This is what the workshop is about.

Host Deploy by Notes
Render connecting a GitHub repo Primary. deploy/render.yaml has the settings; Root Directory app
FastAPI Cloud GitHub in the dashboard, or fastapi deploy Second target. No config file — it reads pyproject.toml, uv.lock and .python-version. Public beta

2 · The client (bonus)client/, a folder of static files. Nothing here can break the architecture, because nothing here runs your code.

Host Deploy by Notes
Vercel importing the repo Root Directory client, VITE_API_URL = your backend URL. client/vercel.json is already written
GitHub Pages pushing to main Already wired up — published at /demo/ alongside this site

Do the agent first; the client needs a backend URL to point at. Then wire the two together — VITE_API_URL on the client, ALLOWED_ORIGINS on the backend — and redeploy both. That last step is where "Failed to fetch" comes from, every single time.

Full walkthroughs: Deploy.

Bonus: your tools in Claude

The MCP server is mounted inside the API, so once you deploy, add this to Claude Desktop or Claude Code:

{ "mcpServers": { "research-tools": { "url": "https://<your-service>/mcp" } } }

Your Wikipedia tools show up as tools you can use in any conversation. No second deployment — see Learn · MCP.

The website

cd website
npm install
npm run dev          # http://localhost:4321

The deck and the demo client are single-sourced from slides/ and client/; website/scripts/sync-assets.mjs pulls them into the build — running the client's own Vite build along the way — so there is never a second copy to keep in sync. Edit slides/index.html and client/src/ in place.

Published to GitHub Pages by .github/workflows/deploy-pages.yml:

  • Website — https://<user>.github.io/deploying-agentic-ai-apps-workshop/
  • Slides — …/slides/
  • Demo client — …/demo/

Enable it once at Settings → Pages → Source: GitHub Actions.

Releases

Contributors

Languages