Deploy as a REST API
Wrap any agent in a production HTTP server with a single function call.
Prerequisites
pip install 'gantrygraph[cloud]'
Step 1 — Minimal server
# server.py
from gantrygraph import GantryEngine
from gantrygraph.actions import FileSystemTools, ShellTools
from gantrygraph.cloud import serve
from langchain_anthropic import ChatAnthropic
def make_agent() -> GantryEngine:
return GantryEngine(
llm=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[
FileSystemTools(workspace="/workspace"),
ShellTools(workspace="/workspace", allowed_commands=["python", "pytest"]),
],
max_steps=30,
)
serve(make_agent, host="0.0.0.0", port=8080)
python server.py
serve() calls make_agent() once per POST /run request, so each job gets a fresh, isolated engine instance. The server exposes five endpoints: POST /run, GET /status/{job_id}, GET /stream/{job_id}, POST /resume/{job_id}, and GET /health.
Step 2 — Call with curl
# Submit a task
curl -X POST http://localhost:8080/run \
-H "Content-Type: application/json" \
-d '{"task": "Run the test suite and return a pass/fail summary"}'
{"job_id": "abc123", "status": "queued"}
# Poll for the result
curl http://localhost:8080/status/abc123
{"job_id": "abc123", "status": "completed", "result": "All 47 tests passed."}
# Stream live events via Server-Sent Events
curl -N http://localhost:8080/stream/abc123
Possible status values: queued, running, suspended, completed, failed.
Step 3 — Docker
# Use the built-in template as a starting point
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY server.py .
CMD ["python", "server.py"]
docker build -t my-agent .
docker run -p 8080:8080 \
-e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
-v "$(pwd)/workspace:/workspace" \
my-agent
For desktop automation in containers, add xvfb and set DISPLAY=:99 in the Dockerfile.
Complete example
# server.py
from gantrygraph import GantryEngine
from gantrygraph.actions import FileSystemTools, ShellTools
from gantrygraph.cloud import serve
from langchain_anthropic import ChatAnthropic
def make_agent() -> GantryEngine:
return GantryEngine(
llm=ChatAnthropic(model="claude-sonnet-4-6"),
tools=[
FileSystemTools(workspace="/workspace"),
ShellTools(workspace="/workspace", allowed_commands=["python", "pytest"]),
],
max_steps=30,
)
serve(make_agent, host="0.0.0.0", port=8080)
0
# Approve a suspended tool call
curl -X POST http://localhost:8080/resume/abc123 \
-H "Content-Type: application/json" \
-d '{"approved": true}'
Variants
- Custom host/port:
serve(make_agent, host="127.0.0.1", port=9000) - Async agent entry: use
arun()insidemake_agent—serve()handles the event loop - Browser agent server: swap tools for
BrowserToolsand addpip install 'gantrygraph[browser]'to your Dockerfile - Suspend/resume disabled (default): omit
enable_suspension=True; the agent will not supportPOST /resume
Troubleshooting
ImportError: serve() requires the [cloud] extra — run pip install 'gantrygraph[cloud]'.
POST /resume returns 409 Conflict — the job is not in "suspended" status. Only jobs created with enable_suspension=True can be resumed; check GET /status/{job_id} first.
GET /stream returns 410 Gone — the job finished before the SSE client connected. Poll GET /status/{job_id} for the result instead.
Next: Require human approval before actions · Monitor agent execution · Run agents in parallel