LLM Systems Engineering · Chapter 9 of 20
AgentCore in practice — the contract, the code, the limits
What your container must actually do, how it is deployed and configured, and the numbers to know before you commit.
AgentCore reached general availability on 13 October 2025, and the older product it replaces — now called Bedrock Agents Classic — closes to new customers on 30 July 2026 with a documented migration path. So this is the successor product, not an add-on, and material written before late 2025 describes something else.
The contract your code has to satisfy
For the common HTTP case, the SDK wrapper implements /ping and /invocations for you, so the whole contract collapses to one decorated function:
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent
app = BedrockAgentCoreApp()
agent = Agent()
@app.entrypoint
def invoke(payload):
user_message = payload.get("prompt", "Hello")
result = agent(user_message)
return {"result": result.message}
if __name__ == "__main__":
app.run()That agent() call is the whole point. It could equally be a LangGraph .invoke(), a CrewAI .kickoff(), or a hand-written loop. AgentCore does not care — which is exactly why “it supports my framework” is a weaker claim than it sounds, and true of all three providers.
Deploying it
The current documented path is the agentcore CLI, which uses AWS CDK — the Cloud Development Kit, which turns code into AWS templates — underneath, and supports two build types: a zip file to storage, needing no Docker, or a container image — and only ARM64 images will run.
npm install -g @aws/agentcore
agentcore create --name MyAgent --framework Strands --model-provider Bedrock
# writes agentcore/agentcore.json (configuration)
# agentcore/aws-targets.json (account and region)
# app/MyAgent/main.py (the entrypoint above)
agentcore dev # local server on :8080, mimics the runtime contract
agentcore deploy # synthesises and applies CloudFormation via CDKThen invoke it from your own code like any other AWS service:
import boto3, uuid, json
client = boto3.client("bedrock-agentcore")
response = client.invoke_agent_runtime(
agentRuntimeArn = "arn:aws:bedrock-agentcore:...:runtime/MyAgent",
runtimeSessionId = str(uuid.uuid4()), # the session boundary — see below
payload = json.dumps({"prompt": "summarise this ticket"}),
)Note the tooling churn, because it tells you something.
Material published only months ago shows a separate Python bedrock-agentcore-starter-toolkit with agentcore configure and launch commands. Both exist; the npm and CDK path is what current documentation points to.
The deployment tooling changed inside thirteen months of GA. That is not a criticism — it is the expected state of a one-year-old category — but it means you should check the current quickstart rather than trusting a tutorial, including this one.
Sessions, and the numbers that decide your design
Every session runs in its own microVM, not a shared container. That is the isolation you are paying for, and it is why the limits below are per-session rather than per-service.
| Dimension | Value | Why it matters |
|---|---|---|
| Idle timeout | 15 min, configurable | When a session is reclaimed |
| Max session lifetime | 8 hours | The real answer to “can it run a long task” |
| Synchronous request | 15 minutes, hard | Anything longer must be async or streamed |
| Streaming connection | 60 minutes | — |
| Asynchronous job | 8 hours | The ceiling to quote in a design review |
| Hardware | 2 vCPU / 8 GB, fixed | Not configurable. A hard ceiling, not a default |
| Payload | 100 MB (10 MB per stream chunk, 64 KB per WebSocket frame) | — |
| Session storage | 1 GB | — |
And watch the quota trajectory rather than the quota. InvokeAgentRuntime went from 25 requests per second at launch, to 200, to 1,000 within a year; concurrent sessions went from 1,000 to 5,000 in the largest regions. A service whose limits triple twice in twelve months was under-provisioned for real traffic at launch, which is worth knowing before you plan against today's number.
The rest of the suite, briefly
- Memory — short-term events retained 7 to 365 days, plus long-term records produced by strategies you attach: semantic, user-preference, summarisation, episodic. A background process extracts from the short-term stream into a namespace you define. Maximum six strategies per memory resource.
- Gateway — turns your existing functions and web APIs and existing tool servers into one endpoint an agent can call. It speaks MCP, the Model Context Protocol — the emerging standard for how an application offers tools to a model. Its genuinely useful feature is that it handles authentication in both directions: it checks who is calling in, and it signs in to the backend service on that caller's behalf on the way out.
- Identity — every agent is a workload identity, with three token functions covering machine-to-machine and two on-behalf-of-user paths. Three-legged OAuth is the recommended pattern for acting as a user, because it forces explicit consent and scoped delegation rather than the agent inheriting broad access.
- Browser and Code Interpreter — sandboxed, ephemeral environments, billed like Runtime. These exist because “give the model a computer” is a recurring pattern that is expensive and risky to build from raw containers. That is the value, not novelty.
- Observability — built on OpenTelemetry, the open standard for traces and metrics, feeding CloudWatch. Strands, LangChain and CrewAI already emit it in the agreed format, so those work with almost no extra code of your own.
One design note worth taking from the changelog: as of July 2026 spans can go to a per-agent CloudWatch log group rather than a shared one. That change exists because the shared-log-group design did not survive contact with enterprise access control — if several teams' agents write to one log group, you cannot scope permissions or encryption per team. Worth designing for on day one.
Check yourself