Claude Agent SDKclaude-agent-sdk 0.2.157 · Python 3.10+
Dashboard
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Hosting the SDK

Hosting the Agent SDK is running a service whose every session owns a separate Claude Code process, with that process's files on local disk. It is not a stateless API wrapper, and the difference drives every decision below.

Last updated: 20 Oct, 2026 · Claude Agent SDK

When your code calls query(), the SDK starts a claude process and talks to it over its standard input and output. That process owns a shell, a working directory and the session transcripts it writes. N sessions at once means N processes. The hosting page covers this in full, with Dockerfiles and Kubernetes manifests in Anthropic's hosting cookbook.

A hosted Agent SDK deployment: a client calls your app inside a container, your app starts the claude CLI as a subprocess over stdio, the subprocess writes session transcripts to the container's local disk and calls api.anthropic.com through an egress proxy over HTTPS, while a dashed line carries OpenTelemetry data out to a collector and another dashed line mirrors transcripts out to a durable SessionStore.

Seeing the process the SDK would start

The options you set are turned into a command line. Reading it is the quickest way to see what reaches the process and what shapes the process instead, and it runs here with no key, because nothing is started.

Example
import shlex

from claude_agent_sdk import ClaudeAgentOptions
from claude_agent_sdk._internal.transport.subprocess_cli import SubprocessCLITransport

# a fixed cli_path keeps the printed command the same on every machine
options = ClaudeAgentOptions(max_turns=20, cwd="/work/session-a", cli_path="claude")

# _build_command is the command line the SDK hands to the operating system
started = SubprocessCLITransport(prompt="", options=options)._build_command()
print("binary:", started[0])
print("flags: ", shlex.join(started[1:]))

What the command line does and does not say

  • The binary is a separate program. Both SDKs bundle a Claude Code binary pinned to the package version, so upgrading the SDK is how the process gets upgraded.
  • --max-turns 20 went across. An option that bounds the loop has to be enforced by the side that runs the loop.
  • --output-format stream-json is always there. The messages the SDK yields are those JSON lines, which is why standard output has to stay clean.
  • cwd is missing from the flags. It is the directory the process is started in, not something it is told, and it is how two sessions are given separate filesystems.

The state that dies with the container

Three kinds of state sit on the container's own disk by default, and a restart, a scale-down or a move to another node takes all three.

StateWhere it lives by default
Session transcripts~/.claude/projects/, or under CLAUDE_CONFIG_DIR when that is set
CLAUDE.md memory files~/.claude/CLAUDE.md for the user tier, the working directory for the project tier
Anything the agent wroteThe session's working directory

A session store carries the transcripts across hosts. It mirrors transcripts and nothing further, so memory files and written artifacts need a mounted volume or a sync of their own.

Four shapes a deployment takes

PatternThe container's lifeWhat it suits
EphemeralOne container per task, destroyed when the task endsOne-off work: a bug fix, an invoice to read, a document to translate
Long-runningPersistent containers, often many sessions eachAgents that act on their own or handle a steady stream of messages
HybridEphemeral, hydrated from a store on start and written backWork that spans days but sits idle between visits
Multi-agentOne container, several processes inside itAgents that have to collaborate in a shared environment

The hybrid pattern is the one where a session store stops being optional. Shutting a container down without one loses the transcript with it, and there is nothing to hydrate from when the person comes back.

python
# session_id comes from your own database, keyed by the user
options = ClaudeAgentOptions(resume=session_id, session_store=session_store)

async for message in query(prompt=user_input, options=options):
    ...

Working out how many agents fit on a host

Each session is a process, so a host holds as many as its memory allows: take the host's RAM, subtract the overhead, and divide by the ceiling one session reaches. The documentation gives a starting point of roughly a gibibyte of RAM, five gibibytes of disk and one CPU per agent for a freshly started instance, and calls it a floor rather than a ceiling, because memory grows with session length and tool activity. Measure your own ceiling by running a session to the length you expect under the tool load you expect, and recording the peak.

Where containers hold many sessions, put a pool of them behind a load balancer and pin each session to one container by hashing its session id. A pinned session keeps reaching the same process until that container is replaced. Token spend normally dwarfs the container bill, so size for comfort rather than squeezing.

Keeping tenants apart in one container

Settings files and memory files are read from the filesystem by default, which in a shared container is how one tenant's context reaches another tenant's session. Four options close that, and the run below shows which of them reach the process as flags and which shape the process itself.

Example
import shlex

from claude_agent_sdk import ClaudeAgentOptions
from claude_agent_sdk._internal.transport.subprocess_cli import SubprocessCLITransport

tenant = ClaudeAgentOptions(
    cwd="/work/tenant-a", cli_path="claude", setting_sources=[],
    env={"CLAUDE_CONFIG_DIR": "/work/tenant-a/.claude",
         "CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1"})

# cwd and env never appear as flags: they shape the process the SDK starts
started = SubprocessCLITransport(prompt="", options=tenant)._build_command()
print(shlex.join(started[1:]))
print("cwd:", tenant.cwd)
print("env:", sorted(tenant.env))

Why each of the four is there

  • An empty setting_sources becomes --setting-sources=. The flag with nothing after it is how the process is told to read no user, project or local settings.
  • CLAUDE_CODE_DISABLE_AUTO_MEMORY=1 is needed as well. Auto memory loads into the system prompt whatever the setting sources say, so the empty list alone does not stop it.
  • CLAUDE_CONFIG_DIR gives each tenant its own config directory. Without it, tenants share one global config file.
  • cwd gives each tenant its own filesystem. Pass it on every call; the default is your application's directory, which every tenant would then share.

Egress rules belong in the same list. Per-tenant outbound addresses, credentials or domain allowlists at your proxy are what stop a tenant that has been talked into something from sending data out under another tenant's policy.

What the SDK will not do for you

LimitationWhat to do about it
A session does not time outBound it with max_turns, which caps the round trips rather than the clock
Memory grows over a long sessionCap the session length, or recycle the process from time to time
A wide fan-out of subagents can hit rate limitsBreak the work into smaller batches instead of one wide dispatch
No wall-clock deadline per subagentCap each subagent with its own max_turns in its definition
Watch out. An agent that starts on your laptop and fails in a container is usually the process not being found: a service manager runs your application with a different PATH than your shell, so an install your terminal can see is invisible to the process. The troubleshooting page has the error text for that one and for a binary built for the wrong architecture.
Try it yourself
  • Add max_budget_usd=1.0 to the options and look for its flag in the printed command.
  • Set cwd to two different directories and confirm the flags come out identical.
  • Print started[0] with cli_path left out, to see the binary your install would start.
PreviousTodo tracking

Little by little, you're building something great.