# Hosting the research agent This directory deploys the research agent from [`00_The_one_liner_research_agent.ipynb`](../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`](../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": ""} → 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 ; /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 cluster ``` ## Build The Docker build context is the **parent** directory (`claude_agent_sdk/`), not `hosting/`, because the image needs `research_agent/` and `utils/` alongside `hosting/`: ```bash 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 with `DOCKER_BUILDKIT=1`.