Build1 publisher3 min readPublished
Stage 1 of a Bedrock AgentCore migration cost 67 hand-written lines in one deployed PoC
A dev.to writeup deployed AWS's own migration sample, reran the repo's diff-checking script, and reports that the managed runtime, gateway and memory are worth taking while the LangGraph loop stays as written.
The Engineer · Build desk

What happened
- A dev.to writeup deployed AWS's migration sample to its own AWS account and reran the repo's own diff-checking script, which reproduced the published counts of 45 changed agent lines, 22 adapter lines and 85 imported unchanged.
- Stage 1 attaches three managed services: Runtime gives each session a micro-VM, Gateway publishes tools over MCP and handles their authentication, and Memory holds conversation state when the process dies.
- A single invoke of the deployed Runtime created a CloudWatch log group under /aws/bedrock-agentcore/runtimes/ with no OTEL configuration in place.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
- decision A team can take managed session isolation and checkpoint storage while leaving classify_intent and route_intent as written; the writeup's judgement is that most teams should stop there and not rewrite the loop into model-driven planning.
- constraint Retention is decided before the first user turn, because event_expiry_days is fixed when the Memory is created and checkpoints inherit it.
- cost A teardown that deletes the Runtime still leaves a log group behind, so someone pays for that retention until cleanup removes it explicitly.
- capability Once a tool sits behind the Gateway, its authentication is out of the agent code and the next agent can call the same tool.
The 22 adapter lines exist because the two SDKs share no common interface. Strands hands back MCP tool objects and LangGraph's graph binds BaseTool, so something has to convert one into the other [18]. The writeup describes that adapter as the only glue the SDKs do not supply [18].
Registering a Lambda function as a Gateway target publishes it as an MCP tool called supportTools___lookup_order, with three underscores separating target name from tool name [9]. The format is visible in the sample's Cedar policy at examples/stage2_rebuild/policy/support_tools.cedar, where it appears as the action name, which is documentation of a sort [9]. Deploying it, the author found the prefix does not appear in the target registration schema or the console's Target detail; both store the bare lookup_order [10]. The prefixed string turns up at runtime in the MCP tools/list response, which the author called directly with SigV4, and in the bedrockAgentCoreToolName entry of the Lambda's client context [11]. So the handler splits on ___ to recover the original name, and a handler that skips that step fails to match [11]. The sample keeps search_faq as a local Python function on the grounds that no other agent will reuse it and it needs no policy gating [12].
MemorySaver is a dictionary inside the process. Kill the process and the conversation is gone, and two replicas cannot see each other's sessions [7]. The AWS post that prompted the exercise says, in the writeup's Korean rendering, that an agent running on a laptop is not a production agent [2]. The author reports the same thing last quarter: a LangGraph support agent demo worked, and once real users arrived, session isolation, checkpoint persistence and tool auth all became code they owned [3]. The fix in the sample is a swap to AgentCoreMemorySaver from the first-party langgraph-checkpoint-aws package, with actor_id and thread_id read out of RunnableConfig on every call and the Runtime's session_id passed as thread_id [13].
AWS's post scores Stage 1 as moving five of ten operational burdens: OS patching, autoscaling, session isolation, checkpoint storage and tool auth [15]. VPC configuration, WAF, IAM policy, secret rotation and dependency updates stay with the customer, and one of those moves only at Stage 3 [15]. The count is defined against the committed sample, and the repo ships examples/validation/verify_diff_claim.py so a reader can recompute it [16].
45/22/85 is a count of one diff. The stage 0 agent is a StateGraph whose classify_intent node asks the model for a one-word category, whose hand-written route_intent branches to escalate or assist, and whose assist node binds three @tool functions [6]. For those line counts to mean anything elsewhere, your state has to live in a LangGraph checkpointer addressed by thread_id and your tools have to be small enough to sit behind Lambda [6][13]. The adapter is the part most likely to hold, since 22 lines of Strands-to-BaseTool conversion follows from the two SDKs [18]. Changed and new lines come to 67 of the 152 counted [1][2]. A 422-line deployment script sits outside the count because the agentcore CLI deploys instead [19], and that excluded script is about 2.8 times the counted total [3].
One invoke of the deployed Runtime created a /aws/bedrock-agentcore/runtimes/ log group with no OTEL configuration [21]. Logs are not traces here: spans need account-level Transaction Search plus ADOT instrumentation in the agent code, and the writeup verified only the logs [22]. The one claim it did not reproduce is the wheel trap it cites from AWS, where vendoring with pip install -t on a Mac pulls ARM or x86 wheels while the Runtime is ARM64 Linux [24].
The writeup's verdict, from reading the sample and deploying the core claims to its own account, is that stopping at Stage 1 is reasonable for most teams [25]. Stage 2 is where the loop itself gets rewritten into model-driven planning [5].
What to watch
- Whether AWS keeps verify_diff_claim.py in step with the sample as the SDKs move; a stale script makes the 45/22/85 claim unverifiable.
- Whether langgraph-checkpoint-aws stays first-party and tracks LangGraph's checkpointer interface as it changes.
- Whether AgentCore starts collecting spans without ADOT instrumentation in the agent code.