Claude Managed Agents and AWS Strands + AgentCore solve the same problem — running agents reliably in production — from opposite ends. A deep look at both architectures, the engineering trade-offs, and how to choose for an enterprise.
Writing an agent loop is a weekend project. Send a prompt and tool definitions to a model, read back stop_reason, execute the tool it asked for, append the result, loop until done. A couple hundred lines. The hard part was never the loop — it's everything that surrounds it once real traffic, real money, and real auditors show up:
Both Claude Managed Agents (CMA) and the AWS stack of Strands + AgentCore exist to provide that surrounding scaffolding. They differ fundamentally in who owns it.
Before comparing platforms, it helps to name the seven layers every production agent needs. Both approaches implement all seven — they just draw the ownership boundary in different places.
Claude Managed Agents is Anthropic's batteries-included agent runtime. You declare an agent (model, system prompt, tools, skills), create an environment (a sandboxed Linux filesystem), open a session, and stream events. The reasoning loop, the sandbox, the skill selection, the sub-agent spawning — all run server-side in Anthropic's cloud.
# An agent: identity + model + tools + skills, declared once
agent = client.beta.agents.create(
model="claude-sonnet-4",
system=SYSTEM_PROMPT,
tools=[{"type": "agent_toolset_20260401"}], # built-in sandbox
)
# An environment: the sandboxed filesystem the agent operates in
env = client.beta.environments.create(config={"type": "cloud"})
# Skills: versioned capability bundles, auto-selected by the model
client.beta.skills.create(display_title="reorder-policy", files=[...])
# A session: one conversation; events stream bidirectionally
session = client.beta.sessions.create(agent=agent.id, environment_id=env.id)
with client.beta.sessions.events.stream(session.id) as stream:
for event in stream: ...
You trade control of the data plane for enormous velocity. A capable, sandboxed, memory-backed agent is a few API calls away. The cost is that inference, code execution, and memory all run in Anthropic's cloud — your data crosses that boundary.
The AWS path splits the problem into two cleanly separated pieces:
from strands import Agent, tool
from strands.models import BedrockModel
@tool
def get_stock_level(sku: str, warehouse: str) -> str:
"""Current on-hand quantity for a SKU at one warehouse."""
return ... # typed function + docstring IS the tool schema
agent = Agent(
model=BedrockModel(model_id="us.anthropic.claude-sonnet-4-6", region_name="us-west-2"),
system_prompt=SYSTEM_PROMPT,
tools=[get_stock_level, ...],
)
You trade some velocity for control. Every layer — inference (Bedrock), sandbox (AgentCore), memory, secrets — runs inside your own AWS account, under your IAM, captured by your CloudTrail. More wiring; total data-plane ownership.
| Layer | Claude Managed Agents | Strands + AgentCore |
|---|---|---|
| Agent logic / loop | Managed server-side; declared as agent config | Strands SDK; runs in your process |
| Model inference | Anthropic-hosted Claude | Bedrock (Claude + other model families) |
| Sandboxed code | agent_toolset_20260401 (built in) | AgentCore Code Interpreter (managed microVM) |
| Tools / MCP | Tool schemas + MCP on the agent definition | Strands @tool + AgentCore Gateway + MCP |
| Skills | First-class, auto-selected by description | Your pattern — versioned markdown + a load_skill tool |
| Sub-agents | callable_agents (declarative) | Strands agents-as-tools / graph / swarm |
| Memory | Managed memory store + consolidation | AgentCore Memory (or your own store) |
| Identity / secrets | Managed vault | AgentCore Identity / AWS Secrets Manager |
| Observability | Anthropic console transcripts | CloudWatch / OTEL + CloudTrail |
| Data plane location | Anthropic cloud | Your AWS account / region |
The crucial row is the last one. Everything above it is implementation detail; the data-plane location is the architectural and compliance decision an enterprise actually argues about.
The cleanest way to reason about these stacks is to separate the control plane (how you define and operate agents) from the data plane (where prompts, tool inputs/outputs, code execution, and memory physically live).
For an enterprise in pharma, finance, healthcare, or the public sector, this single distinction frequently decides the platform before any feature comparison happens. "Does customer data leave our AWS account?" has a one-word answer for each stack, and that word is often the whole conversation.
Real workloads decompose into a coordinator and specialist sub-agents. A research coordinator delegates to a web searcher, a document analyst, a synthesizer. An inventory coordinator delegates heavy forecasting to a sub-agent with its own context window.
You declare sub-agents on the coordinator's config; the platform spawns them, isolates their context, and routes results. Sub-agents are addressable by ID and version.
# declarative — platform handles the rest
callable_agents = [
{"type": "agent", "id": forecaster_id, "version": v}
]
client.beta.agents.update(
coordinator_id, callable_agents=callable_agents
)
A sub-agent is a Strands Agent wrapped in a @tool. The coordinator calls it like any other tool; the sub-agent gets its own context window and its own AgentCore resources.
@tool
def forecaster(sku: str) -> str:
"""Delegate a demand forecast."""
sub = Agent(
model=make_model(),
system_prompt=FORECASTER_SYSTEM,
tools=[run_python]
)
return str(sub(f"Forecast {sku}"))
The principle is identical on both stacks — isolate any step that carries its own large, short-lived context so it doesn't crowd the coordinator. CMA expresses it as configuration; Strands expresses it as composition. Configuration is faster to declare; composition is easier to unit-test and version in your own repo.
Memory turns a "goldfish" agent (re-asks everything every session) into a "colleague" (recalls context across sessions).
A managed memory store you attach to a session as a resource, with read or read-write access. A consolidation step can compress historical sessions. Zero infrastructure; lives in Anthropic's cloud.
AgentCore Memory provides short- and long-term memory inside your account. Or implement it yourself — Postgres + pgvector with a recall_facts / persist_fact tool pair — for total control over where memories live and how they're deleted (GDPR right-to-erasure).
| Concern | CMA | Strands + AgentCore |
|---|---|---|
| Secret storage | Managed vault, referenced by ID | AgentCore Identity / AWS Secrets Manager |
| Authorization model | Per-agent tool allow-lists | IAM — task/pod/function roles, least privilege |
| Sandbox isolation | Managed, per-session ephemeral | AgentCore microVM, per-session ephemeral |
| Network controls | Anthropic-managed egress | Your VPC, security groups, PrivateLink |
| Credential audit | Console | CloudTrail (every secret fetch, every model call) |
The AWS stack inherits the entire IAM and VPC apparatus an enterprise already runs. The agent's permissions are ordinary IAM policies; the blast radius is an ordinary role; the network path is an ordinary security group. For a security team, "it's just IAM and a VPC" is reassuring in a way that a separate vendor's access model is not.
The ability to answer "show me every action this agent took, which model version, which data, which credential, on what date" with native cloud logging — no extra vendor in the audit scope — is a recurring deciding factor for the AWS stack.
| CMA | Strands + AgentCore | |
|---|---|---|
| Pricing | Anthropic usage (inference + managed runtime) | Bedrock inference + per-use AgentCore + your AWS infra |
| Ops burden | Near zero — Anthropic operates it | You operate the agent host; AWS operates managed pieces |
| Time to first agent | Hours | Days (more wiring) |
| Billing consolidation | Separate Anthropic bill | Single AWS bill (often a procurement win) |
| Scale to zero | Inherent | Yes for serverless pieces; your call for always-on hosts |
Velocity favors CMA early; an enterprise already standardized on AWS often favors the AWS stack for billing consolidation, existing committed-spend discounts, and not adding a vendor to procurement and security review.
Strip away preference and the choice usually reduces to a handful of hard constraints. Walk them in order; the first hard constraint typically decides.
These are not mutually exclusive across a portfolio. A common, sensible progression:
The two artifacts that make this migration cheap are a portable eval harness (prove parity after re-homing) and methodology-as-skills (markdown files that move between platforms unchanged). Build those well and the runtime beneath them becomes an implementation detail.
CMA and Strands + AgentCore are not competitors so much as two points on a single spectrum of how much of the surrounding scaffolding you want to own.
Optimizes for velocity and minimal operational burden. Fastest path to a capable, sandboxed, memory-backed agent. Its first-class Skills primitive is genuinely pleasant. The trade: a data plane you don't control and a second vendor in your security scope.
Optimizes for control and enterprise fit. Everything runs in your AWS account, under your IAM, captured by your CloudTrail, billed on your AWS invoice. The trade: more wiring and operational ownership.
The patterns that matter — decomposing a monolith into a lean coordinator, isolating heavy work in sub-agents, treating methodology as versioned skills, sandboxing code execution, and measuring everything with evals — are identical on both. Master the patterns, and the platform becomes a choice you make per customer, per constraint, rather than a religion. That portability is the real engineering asset.