Deployment & Operations โ How Agents Actually Run
Every domain so far explained what the pieces are. This page answers the architect's next question: where does this code physically run, who starts it, and how do you assemble it in an enterprise cloud project?
๐ New here? The "works on my laptop" gap
The gap: you've built the loop โ it runs when you type python agent.py. But production means the loop runs when you're not there: at 2 AM for a batch, on every merge in CI, on every customer webhook. Something must host the harness, hold the credentials, restart it when it crashes, and collect its logs. That "something" is a deployment topology, and interviewers (and the exam's scenario framing) expect you to have one in mind.
The reassuring truth: an agent deploys like any other service, because the harness IS an ordinary program โ a Python or Node process that makes HTTPS calls to the Claude API. There is no special "AI runtime" to provision, no GPU to rent (inference happens on Anthropic's side). Everything you know about deploying web services applies unchanged; this page just maps the agent-specific concerns (secrets, egress โ outbound network connections, budgets, evals) onto that familiar shape.
So what for the exam: scenario questions say things like "the team wants nightly runs in CI" or "expose the agent to internal users" โ each phrase implies one of the five runtime forms below. Recognize the form and the architecture answer follows.
The five runtime forms โ recognize which one a scenario implies
Form
What runs, where
Triggered by
Canonical example
Interactive CLI
Claude Code in a developer's terminal
a human typing
daily development work
Headless / CI
claude -p โ same engine, no human attached
pipeline events (merge, PR, nightly)
auto-triage new issues on every push
Long-running service
your harness as a web service (the SDK inside a container)
HTTP requests / webhooks
the support agent behind an endpoint
Scheduled batch
a harness job spun up, run to completion, torn down
cron / scheduler
10,000-invoice nightly extraction
Event-driven worker
harness consuming a queue
messages (Pub/Sub, SQS)
"a ticket was created" โ agent enriches it
The first two run Claude Code itself; the last three run your own harness built on the Claude API or Agent SDK. That's the whole taxonomy โ every "how do we ship this?" conversation starts by picking a row.
Headless mode โ the agent with nobody at the terminal
Headless means Claude Code running non-interactively: you pass the prompt as an argument, it does the work, prints machine-readable output, and exits. Same engine, same tools, same CLAUDE.md loading โ but no human to approve anything, which is why the flags below exist:
BASH
claude -p "Triage the new GitHub issues: label severity, close duplicates." \
--output-format stream-json \
--allowedTools "Read,Grep,Bash(gh issue:*)" \
--max-turns 15
-p (print mode) is the headless switch โ prompt in, result out, exit code for the pipeline.
--output-format json / stream-json makes the output parseable by the calling system (CI step, another program).
--allowedTools is the deterministic leash: with no human watching, permissions are the gate โ allowlist exactly what the job needs, nothing more.
--max-turns is the budget: a runaway loop in CI burns money silently; the ceiling makes it terminal.
In a CI pipeline it's just a step:
YAML
# .github/workflows/triage.yml โ an agent as a CI step
on:
issues: { types: [opened] }
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm install -g @anthropic-ai/claude-code
- run: |
claude -p "Triage issue #${{ github.event.issue.number }}: apply severity label." \
--allowedTools "Bash(gh issue:*)" \
--max-turns 10
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
The API key comes from the pipeline's secret store โ never from a file in the repo. This one YAML block is the entire "AI in CI/CD" story the exam gestures at.
The harness as a service โ it's just a program
When the agent must serve users or systems (rows 3โ5), you deploy your own harness: an ordinary containerized service that happens to call the Claude API. Nothing about it is exotic โ it follows the same operational rules as any ordinary web service: config in the environment, logs to stdout, no state baked into the container.
PYTHON
# app.py โ the support agent as a plain web service (FastAPI)
# shape-only sketch โ production adds auth, a typed/validated request model, size limits, error handling
from anthropic import Anthropic
from fastapi import FastAPI
app = FastAPI()
client = Anthropic() # reads ANTHROPIC_API_KEY from the environment
@app.post("/support")
def handle(ticket: dict):
result = run_agent_loop(client, ticket) # the Domain-1 loop, verbatim
return {"resolution": result.text, "state": result.terminal_state}
Containerize it, and every platform question becomes a standard one: where do containers run, where do secrets live, where do logs go. Which brings us to the concrete version.
Reference architecture โ the support agent on GCP
The Domain-1 walkthrough's support agent, deployed for real on Google Cloud:
flowchart TD
U[Customer email / chat] --> GW[API Gateway / webhook endpoint]
GW --> PS[Pub/Sub topic: support-tickets]
PS --> CR[Cloud Run: the harness container]
SM[Secret Manager: ANTHROPIC_API_KEY] -.mounted at startup.-> CR
CR -->|HTTPS: model calls| CAPI[Claude API โ api.anthropic.com]
CR -->|tool calls| SQL[(Cloud SQL: orders DB)]
CR -->|tool calls| MCP[MCP server: internal customer-records CRM โ Cloud Run service]
CR --> LOG[Cloud Logging โ BigQuery: traces, tokens, gate verdicts]
SCH[Cloud Scheduler: nightly] --> EV[Eval job: golden set vs staging]
EV --> LOG
HITL[Approval queue: escalations UI] --- CR
Component
GCP piece
The agent-specific reason
Entry point
API Gateway + Pub/Sub
the queue absorbs traffic spikes so the harness pulls work at its own pace โ rate-limit protection by architecture, not by retries
The harness
Cloud Run
scale-to-zero container (no container runs, and you pay nothing, until a request arrives); each request is one agent run; concurrency caps give you throughput/backpressure control (per-run budgets still live in the harness)
Secrets
Secret Manager
the Claude API key is delivered as a secret-backed environment variable on the Cloud Run revision (a new key version is picked up on the next revision deploy) โ never baked into the image, never in git
Model calls
egress to api.anthropic.com
the only internet egress (outbound network connection) the container needs โ allowlist it and block the rest, and a prompt-injected agent has nowhere to send stolen data. (Tool backends and the internal CRM are reached privately over the VPC โ Virtual Private Cloud โ network, not the public internet.)
Tool backends
Cloud SQL, internal services
least-privilege service account per tool โ the DB user can read orders but cannot drop tables
Shared tools
MCP servers as sibling Cloud Run services
the Domain-4 catalog pattern deployed: one server, many agent hosts
the golden set runs nightly against staging; a red run blocks the next deploy
HITL
an approval queue + tiny UI
the violation branch of the harness gate check โ the decision diamond from the Domain-1 loop โ has to land somewhere a human actually looks
๐ See it run โ one customer message through the GCP topology
Entry point: a customer emails "my order #4531 never arrived" at 09:14.
The email webhook posts to API Gateway, which publishes the message to the Pub/Sub topic. A push subscription then delivers each message as an authenticated HTTPS POST to the Cloud Run service; the service acks by returning 2xx, and failed deliveries are redelivered โ which is why the harness's idempotency keys matter here too. If 500 emails arrive in one minute, they queue calmly โ nothing melts.
Cloud Run has scaled to zero overnight; the first message wakes a container. ANTHROPIC_API_KEY arrives as a secret-backed environment variable from Secret Manager on the running revision โ the code just reads the env var, exactly like on your laptop.
The harness runs the Domain-1 loop verbatim: it calls the Claude API over its one allowlisted internet egress route; the model returns tool_use: get_order; the harness queries Cloud SQL privately over the VPC using a service account that can read orders and nothing else.
Turn 2's create_replacement hits the harness gate check (the decision diamond from the Domain-1 loop) โ $89 < $100, auto-approved. (At $600 it would have landed in the approval queue, and the container would have persisted state and moved on โ a human clicks approve later, a new run resumes from the checkpoint.)
Every step streamed to Cloud Logging: prompt version, tokens (2,140 in / 380 out), cost, tool calls, gate verdicts, terminal state resolved. Tonight, BigQuery aggregates it into the cost-per-resolution dashboard; the Cloud Scheduler eval job replays the golden set against the same revision before tomorrow's deploy.
Total infrastructure the "AI part" required beyond a normal web service: one secret, one egress rule, one logging schema. That's the punchline โ the model is a dependency, not a datacenter.
The same shape on any cloud
Concern
GCP
AWS
Azure
Harness container
Cloud Run
Fargate / Lambda
Container Apps
Queue
Pub/Sub
SQS / EventBridge
Service Bus
Secrets
Secret Manager
Secrets Manager
Key Vault
Logs/analytics
Cloud Logging + BigQuery
CloudWatch + Athena
Monitor + Log Analytics
Scheduler (evals)
Cloud Scheduler
EventBridge Scheduler
Logic Apps / Functions timer
The names change; the topology โ queue in front, stateless harness container, secret store, single allowlisted egress, traces out โ does not. (Amazon Bedrock (AWS) and Vertex AI (Google Cloud) โ each cloud's own managed model service โ add a variation: Claude is called through the cloud's endpoint instead of directly to api.anthropic.com โ same harness, different base URL and cloud-IAM authentication (the cloud's own Identity and Access Management, instead of an Anthropic API key).)
Enterprise assembly checklist โ what the architect signs off
Identity & secrets: API keys in the secret store, rotated; one service account per tool backend, least-privilege each.
Egress control: the harness can reach the Claude API and its tool backends โ and nothing else. This single network rule is your strongest defense against exfiltration (smuggling data out): even a prompt-injected agent has nowhere to send it (Domain 3's layer 3, at the network layer).
Budgets as infrastructure: max-turns/cost ceilings in the harness AND platform quotas (Cloud Run concurrency, spend alerts) โ two independent layers.
Observability first-class: per-run traces with correlation ids landing in a queryable store before launch, not after the first incident.
Evals in the deploy path: golden set green = deployable; a config/prompt/model change that can't turn the suite red proves nothing (Domain 5's negative controls).
HITL has a real surface: escalations land in a queue humans actually monitor, with an SLA โ an unmonitored approval queue is a silent-failure machine.
๐ชค Trap: "we need GPUs to deploy the agent" โ no. Inference runs on Anthropic's side of the Claude API; your side is an ordinary container that makes HTTPS calls. The trap answer provisions infrastructure for a problem you don't have; the architect answer is the checklist above.