Chapter 15
Hosting the research agent
Hosting the research agent
This directory deploys the research agent from
00_The_one_liner_research_agent.ipynb
through three tiers: local Docker, Modal, and Kubernetes. The agent, the
container image, and the HTTP interface are the same across all three —
only the operational machinery around the container changes.
Walk through 07_Hosting_the_agent.ipynb for
the full narrative.
Interface contract
All three tiers conform to this contract. The Kubernetes gateway routes against it.
The agent image exposes:
GET /health
→ 200 {"status": "ok"}
Liveness check for orchestration.
POST /sessions/{session_id}/messages
Body: {"prompt": "<user message>"}
→ 200 text/event-stream
event: message — data is a serialized SDK message
(SystemMessage | AssistantMessage | ResultMessage)
event: done — turn complete
event: error — data is {"message": "..."}
Resumes the session if it exists, creates if not.
Stream contains ONLY the new turn's events, not history.
session_id MUST match ^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$. Invalid → 400.
Port: 8000
Required env: ANTHROPIC_API_KEY
Optional env: MODEL (default: claude-sonnet-4-6),
CLAUDE_CONFIG_DIR (default: /data — mount this for persistence),
AGENT_AUTH_TOKEN (when set, /sessions/* requires
Authorization: Bearer <token>; /health stays open)
⚠️ SECURITY: This server has no authentication by default. It MUST sit
behind a gateway/proxy that (1) authenticates callers and (2) only
forwards session_ids that belong to the authenticated caller. Do not
expose port 8000 to the internet directly.
If there is no gateway (tier 2: Modal hands out a public tunnel), set
AGENT_AUTH_TOKEN. It is the minimal stand-in, not a replacement — it
does not scope session_ids to callers.
LIFECYCLE: The server does not self-terminate. The orchestrator is
responsible for killing idle containers.Directory layout
hosting/
README.md ← you are here
Dockerfile ← shared agent image (build context = claude_agent_sdk/)
Dockerfile.dockerignore
server.py ← FastAPI + SSE server (the hybrid path)
run_once.py ← ephemeral path: one prompt, print result, exit
entrypoint.sh ← dispatches: ephemeral run vs. start server
requirements.txt
.env.example ← ANTHROPIC_API_KEY, MODEL
docker/ ← Tier 1: local Docker / docker-compose
modal/ ← Tier 2: Modal Sandbox
kubernetes/ ← Tier 3: pod-per-session on your own k8s clusterBuild
The Docker build context is the parent directory (claude_agent_sdk/), not
hosting/, because the image needs research_agent/ and utils/ alongside
hosting/:
cd claude_agent_sdk/
docker build -f hosting/Dockerfile -t research-agent .The build uses the sibling
Dockerfile.dockerignore(note the prefixed name), which requires BuildKit — the default builder in Docker 23.0+ and Docker Desktop. On an older engine, run the build withDOCKER_BUILDKIT=1.
