Skip to content
Changelog

Run sandboxed Claude and Codex agents on Amazon Bedrock AgentCore

October 16, 20263 min read

Agno's AgentCoreSandbox gives each sandbox generation one AgentCore runtime session, named agno- plus a hash of the namespace, agent, session and generation. That makes create idempotent, so a create whose reply got lost finds the same microVM again by name. The agent around it doesn't change.

import os
 
from agno.agents.claude import ClaudeAgent
from agno.db.postgres import PostgresDb
from agno.sandbox.agentcore import AgentCoreSandbox
 
runtime_arn = os.environ["AGENTCORE_RUNTIME_ARN"]
 
agent = ClaudeAgent(
    id="coder",
    permission_mode="bypassPermissions",
    db=PostgresDb(db_url="postgresql+psycopg://ai:ai@localhost:5532/ai"),
    sandbox=AgentCoreSandbox(
        runtime_arn,
        env={"CLAUDE_CODE_USE_BEDROCK": "1", "AWS_REGION": runtime_arn.split(":")[3]},
    ),
)

Install agno[agentcore-sandbox] and deploy the runtime once with agentcore_setup.py. The script builds the ARM64 image from the same Dockerfile the Docker provider uses, pushes it to ECR, creates the runtime and prints its ARN. With CLAUDE_CODE_USE_BEDROCK set, Claude Code calls Bedrock through the runtime's execution role, so no Anthropic key enters the microVM. Every microVM gets 2 vCPU and 8 GiB.

How AgentCoreSandbox runs a sandboxed agent. On your host, ClaudeAgent or CodexAgent with sandbox=AgentCoreSandbox, the coordinator and Postgres holding the lease, generation and recovery point, and AgentCoreCheckpointTransfer writing to the checkpoint store you pass. Create uses a session id hashed from namespace, agent, session and generation. InvokeAgentRuntime carries start, poll and stage calls, InvokeAgentRuntimeCommand carries commands that are never resent, and checkpoints move in 8 MiB chunks up to 2 GiB. Inside one microVM per generation, with 2 vCPU and 8 GiB, a root server on port 8080 claims the microVM, starts the runtime and writes a random incarnation. A stale handle is refused because every request names the claimed config and incarnation. A guard drops to UID 1000, where commands and Claude Code or Codex run in /workspace. Capture and restore stop the agent's processes while the archive moves.

Every request names its claim

A root server on port 8080 answers AgentCore inside the microVM. On create it starts the runtime as UID 1000, waits for its health check, and then writes the identity and a random incarnation to a file only root can read. Every later request has to carry that configuration and incarnation. AgentCore boots a fresh microVM whenever someone calls a stopped session again, and this check keeps an old handle from ever running work on the newer claim.

Commands pass through a guard that drops to UID 1000 in /workspace. AgentCoreSandbox never sends a command twice. When the outcome is unknown, it stops the computer and the session recovers from its checkpoint. The server also refuses connections from UID 1000 itself, so agent code can't talk to it over loopback.

With no AWS account for this entry, we drove AgentCoreSandbox against the fake AgentCore data plane in the release's own tests.

# real output, the release's test fake in place of AgentCore
create         agno-8af706bb313748afc11ca0a26be596ab81701f28/c9b76000d1dc62fa
create again   agno-8af706bb313748afc11ca0a26be596ab81701f28/c9b76000d1dc62fa (same)
generation 2   agno-525493c992bd91272927c16ca4dcb02f7af2136b
stale handle   AgentCore sandbox refused stage: _Refused: Computer identity mismatch
commands sent  0
3 GiB limit    AgentCore checkpoints are limited to 2 GiB

Checkpoints in 8 MiB chunks

AgentCore has no pause, so during a capture or restore the server stops the agent's UID 1000 processes and later resumes only the ones it stopped. A UID 1000 child process builds or unpacks the archive, and AgentCoreCheckpointTransfer moves it through InvokeAgentRuntime in chunks of at most 8 MiB, up to 2 GiB per checkpoint. The host rejects an archive that holds an excluded credential, or a hard link to one. AGENTCORE_NATIVE_EXCLUSIONS also leaves out the plugin marketplace of about 100 MiB that Codex clones on start. If a restore fails, that computer refuses all further work and Agno stops it.

Files live on the microVM's own disk. AgentCore session storage is NFS, where SQLite can't open a database, so the provider leaves it unused.

Each provider now has its own package. agno.sandbox.docker holds DockerSandbox and DockerCheckpointTransfer, and agno.sandbox.agentcore holds AgentCoreSandbox, AgentCoreCheckpointTransfer and the server that runs in the microVM. The runtime also creates CODEX_HOME and logs Codex in from OPENAI_API_KEY when no stored login matches, because checkpoints leave auth.json out. Both Codex fixes apply on Docker too.

In the team's staging runs, a cold AgentCore session took 11.7 to 13.3 seconds to start, and all 1,000 sessions of a load test paced at 20 per second completed. Here, the release's 55 AgentCore unit tests pass, including a checkpoint round trip into a replacement microVM through the real in-microVM server code.

See the cookbook and its AgentCore setup guide, and learn more about running Claude and Codex as harness agents in the documentation.

Frequently asked questions

Install agno[agentcore-sandbox], deploy the runtime once with cookbook/frameworks/sandbox/agentcore/agentcore_setup.py, and pass sandbox=AgentCoreSandbox(runtime_arn, env=...) to the agent. The agent keeps its PostgresDb; only the turns run on AgentCore.

No. With CLAUDE_CODE_USE_BEDROCK and AWS_REGION in the sandbox's env, Claude Code reaches Bedrock through the runtime's execution role and Agno forwards no Anthropic key. Codex still needs OPENAI_API_KEY in env.

Up to 2 GiB. AgentCoreCheckpointTransfer moves the archive through InvokeAgentRuntime calls of at most 8 MiB each and refuses archive limits above 2 GiB when you build it.

Each provider has its own package. DockerSandbox and DockerCheckpointTransfer come from agno.sandbox.docker, and AgentCoreSandbox and AgentCoreCheckpointTransfer come from agno.sandbox.agentcore.

Shipped around the same time