Amazon Bedrock AgentCore Harness Explained | Fission Labs

October 21, 2026

AgentCore Harness: The Production Layer Every Prototype Agent Was Missing 

Amazon Bedrock AgentCore Harness introduces a managed approach to configuring and executing AI agents, reducing the engineering effort required to integrate the infrastructure needed for production workloads. While AgentCore provides foundational capabilities such as Runtime, Memory, Gateway, Browser, Identity, and Observability, Harness brings these capabilities together through a unified configuration layer. Developers can define an agent’s model, instructions, tools, and skills without repeatedly building and maintaining the underlying execution and integration infrastructure.

Two API Calls, One Running Agent

The entire surface area is two calls: CreateHarness to define an agent, InvokeHarness to run it. That's genuinely the whole entry point , no orchestration code required, no container required, unless you actually want one. Once created, the agent runs in its own isolated environment with a filesystem and shell, so it can read files, run commands, and write code safely. It remembers users and conversations across sessions, picks up skills on demand, browses the web, calls tools through Gateway or MCP, and switches model providers mid-session without losing context. Every step streams back in real time and traces automatically to CloudWatch.

import boto3, uuid
control = boto3.client("bedrock-agentcore-control", region_name="us-west-2")
data    = boto3.client("bedrock-agentcore",         region_name="us-west-2")

# 1. Define
harness = control.create_harness(
    harnessName="MyAgent",
    executionRoleArn="arn:aws:iam::123456789012:role/MyAgentRole"
)

# 2. Invoke
session_id = str(uuid.uuid4()).ljust(33, "0")
response = data.invoke_harness(
    harnessArn=harness["harnessArn"],
    runtimeSessionId=session_id,
    messages=[{"role": "user", "content": [{"text": "Plan a 5-day Tokyo itinerary."}]}]
)

for event in response["stream"]:
    print(event)

That's a real, running agent with memory, an isolated sandbox, and automatic tracing , before a single line of orchestration code gets written.

Any Model, and the Part That Actually Matters: Switching Mid-Session

Different tasks genuinely need different models , plan with one, execute with another, summarize with a third. The harness supports Bedrock-hosted models (Anthropic Claude, Amazon Nova, Meta Llama, and others), direct access to OpenAI's API, Google Gemini, and any third-party provider through LiteLLM. You set a default model on CreateHarness and can override it on any single InvokeHarness call without disturbing the default for every other invocation.

The detail that matters most here isn't the provider list , it's that you can switch providers mid-session and keep context. Plan with Claude Opus, switch to GPT for implementation, switch again to Gemini to summarize, and the conversation continues as one coherent thread instead of three disconnected calls you have to stitch together yourself. If you're using API keys for any provider, they sit in AgentCore Identity's token vault , the agent never sees raw credentials, the same boundary discussed in AgentCore's governance model more broadly.

Tools as Config, Not Glue Code

Wiring tools by hand is the part most teams quietly hate , per-API adapter code, managing MCP server lifecycles, and building a browser sandbox from scratch. On the harness, tools is a list on CreateHarness, and each entry just declares a type and a config block:

"tools": [
  { "type": "agentcore_browser" },
  { "type": "agentcore_code_interpreter" },
  { "type": "remote_mcp",
      "name": "X_tool",
      "config": { "remoteMcp": { "url": "https://mcp.X_tool/mcp" } } },
  { "type": "agentcore_gateway",
      "name": "Y_tool",
      "config": { "agentCoreGateway": { "arn": "arn:aws:bedrock-agentcore:..." } } }
]

agentcore_gateway references an existing Gateway by ARN, and every target it exposes , OpenAPI, Smithy, Lambda, MCP , shows up as a usable tool with auth and credential brokering already handled. remote_mcp connects directly to an already-secured MCP server. agentcore_browser and agentcore_code_interpreter are one-line references to a full browser sandbox and sandboxed Python/Node execution. inline_function is for human-in-the-loop approvals , the harness emits a tool-use event and waits for your response. Every session also gets built-in shell and file operations without you listing them explicitly. On InvokeHarness, you can override the tool list per call, or narrow it down to a focused set with allowed_tools for a single invocation.

Memory That Shows Up Without Being Asked For

In preview, memory meant provisioning an AgentCore Memory resource separately and passing its ARN , a second API call, and an easy thing to forget on the way to production. At GA, omitting memory on CreateHarness provisions managed memory automatically: semantic and summarization strategies, 30-day event expiry, encryption, and multi-tenant isolation by default through namespace templates keyed on actorId. It's a real, customer-owned resource, not a black box , you can query it, attach it to another harness, or hand it to an analytics pipeline.

Three configuration paths cover the range from zero-effort to fully custom:

// Managed memory (default behavior if omitted)
"memory": {
  "managedMemoryConfiguration": {
    "strategies": ["SEMANTIC", "SUMMARIZATION"],
    "eventExpiryDuration": 30
  }
}

// Bring your own existing memory resource
"memory": { "agentCoreMemoryConfiguration": { "arn": "arn:aws:bedrock-agentcore:..." } }

// Stateless agent
"memory": { "disabled": {} }

Switching from managed to your own memory is a single UpdateHarness call , the managed resource disassociates immediately, and it's still a normal AgentCore Memory resource you can keep using elsewhere. Delete the harness and the managed memory cascade-deletes by default; pass deleteManagedMemory: false if you want to keep it.

Skills: Expertise Loaded Only When the Task Calls For It

Skills are bundles of files, scripts, and instructions that give an agent domain-specific know-how , how to format a report a particular way, how to file a ticket the way your team files it. The harness loads skill metadata up front and pulls full content into context only when the task actually needs it, which keeps the agent from carrying a permanent tax on every request for knowledge it rarely uses.

HarnessSkill supports four sources: awsSkills for the AWS-curated bundle, git for a repo pinned to a commit or branch, s3 for your own bucket, and path for something already baked into a custom container. The AWS skills repository is the notable one for teams building on AWS specifically , it covers core skills (SDK usage, IaC, IAM, CloudWatch, Bedrock) down to service-specific deep workflows for analytics, databases, EC2, networking, security, and storage, and GA introduces a zero-plumbing toggle to turn the whole bundle on:

aws bedrock-agentcore-control create-harness \
  --harness-name myAgent \
  --skills '[{"awsSkills": {"paths": ["core-skills/*", "specialized-skills/operations-skills/*"]}}]'

Environment, Filesystem, and Knowing Which Storage Option You Actually Need

Most agents run fine on the default Python-and-bash environment. When that's not enough, a custom container image pushed to ECR gives the agent whatever runtime, dependencies, or CLI tools it needs, and InvokeAgentRuntimeCommand runs deterministic setup , cloning a branch, seeding test data , directly inside the microVM without burning tokens on something that doesn't need a model's reasoning at all.

For persistence, three filesystem options cover different reach: managed session storage persists across stop/resume cycles of the same session, no VPC required. An EFS access point persists across all sessions and is sharable across harnesses, but needs a VPC. S3 Files persist across all sessions and harnesses with full S3 durability and versioning , the agent writes a report through standard file operations, and it shows up in your bucket as it goes. Which one you reach for depends entirely on whether you need working files to survive a restart, shared reference data across harnesses, or durable output that lands directly in storage you already govern.

Observability Without Five Open Tabs

A typical harness invocation crosses runtime, memory, gateway, and a tool or two , stitching that picture together used to mean five separate log groups. At GA, every harness page in the console shows a single observability widget: an aggregate summary across every primitive the harness touched, with per-primitive detail sections. CloudWatch GenAI Observability adds a dedicated Harnesses tab alongside Runtime, letting you drill from a harness into a session into a single trace and see exactly what happened, in what order, and where it failed , with logs from memory, gateway, and browser surfacing inline at the right span instead of requiring you to hop between log groups to reconstruct the story yourself.

Evaluate, Optimize, and Actually Close the Loop

Once an agent is live, the real question shifts from "does it work" to "is it improving." AgentCore Evaluations scores harness traces with built-in LLM-as-a-judge evaluators , helpfulness, faithfulness, safety , or custom ones you author, run online against every session, on-demand against a single trace, in batch over historical traces, or as a simulation against synthetic users before anything goes live. AgentCore optimization reads those scores and generates prompt and tool-description recommendations, then validates them by routing live traffic between variants through Gateway with online scoring and statistical significance reporting , an actual A/B test on real traffic, not a guess. The workflow is genuinely closed-loop: run the harness, capture traces, get scores, get recommendations, test them against the current version, ship the winner.

Version, Roll Back, and Never Redeploy in a Panic

Every UpdateHarness call creates an immutable version capturing the full configuration , model, prompt, tools, memory, skills, environment, execution limits. Rollback is just pointing an endpoint at an earlier version:

# Create PROD pinned to version 2
aws bedrock-agentcore-control create-harness-endpoint \
  --harness-id my-harness-xxx --endpoint-name PROD --harness-version 2

# Promote version 5 (or roll back to version 4)
aws bedrock-agentcore-control update-harness-endpoint \
  --harness-id my-harness-xxx --endpoint-name PROD --harness-version 5

The DEFAULT endpoint auto-advances on every update; named endpoints like PROD and STAGING stay pinned until explicitly promoted , which is what lets a team test a change on staging traffic without a single production user noticing anything changed.

Graduating Without Starting Over

When a use case genuinely outgrows configuration , custom orchestration, multi-agent coordination, instrumentation deeper than the harness exposes , one CLI command exports the harness as Strands-based code:

agentcore export harness --name myHarness-6dk4df --output ./my-agent

The exported project keeps the same model, prompt, tools, memory wiring, skills, and container environment, and runs on the same compute and observability primitives. It's a config-to-code translation, not an architecture switch , which matters, because it means the decision to start with the harness doesn't foreclose the option to graduate later without a rebuild. Strands is the first supported export target, with Claude Agent SDK integration planned to accommodate teams operating within different agent development ecosystems.

What the Same Two API Calls Actually Build

Three genuinely different agents, same harness, same two calls , only the configuration changes. A research and writing agent needs agentcore_browser, a Gateway target exposing web search, and a git-sourced skill bundle for document generation; memory is on by default, so nothing else needs configuring. An AWS data and analytics agent needs the awsSkills bundle scoped to analytics and database workflows, plus an execution role scoped to the right AWS APIs , add the code interpreter if it also needs to chart what it pulls. A coding agent needs a custom container with the team's repo and toolchain, a Gateway target wired to source control, and InvokeAgentRuntimeCommand for the deterministic git operations that don't need a model to reason through them.

Pay Only for What Actually Runs

There's no separate harness fee , you pay for the underlying capability based on actual consumption. Runtime compute bills per second of active use ($0.0895 per vCPU-hour, $0.00945 per GB-hour), which matters because agentic workloads spend real time waiting on model and tool I/O, and Runtime only bills when CPU is actually being consumed during that wait. Browser and Code Interpreter follow the same active-consumption model; Gateway bills per 1,000 invocations and search queries; Memory bills per 1,000 events, records, and retrievals; Observability follows standard CloudWatch pricing; model inference bills at the provider's standard rate. Each meter is independent , use one capability or all of them, and a 60-second agent that calls two tools costs accordingly less than an hour-long, compute-heavy one.

Where This Still Needs Judgment

A couple of things worth flagging honestly. The managed-memory defaults (30-day expiry, semantic plus summarization strategies) are sensible starting points, not universal ones , a use case with different retention or compliance requirements needs someone to actually check those defaults rather than assume they're already correct for a regulated workload. And the export-to-code path currently targets Strands specifically; teams standardized on a different framework get a real graduation path once Claude Agent SDK support lands, but not before, which is worth factoring into a decision to adopt the harness if framework choice is already fixed elsewhere in the stack.

Takeaway

The bottleneck in getting agents to production was never how capable the model was , it was everything standing between a working prototype and something serving real traffic safely. AgentCore harness doesn't remove that work; it collapses it into configuration on top of primitives that already existed, so a team's engineering effort goes into what the agent actually does rather than how it gets permission to do it, where its state lives, or how its telemetry gets stitched together. Same two API calls, three different agents, only the config changed. That's the actual pitch.

References

Fission Labs uses cookies to improve functionality, performance and effectiveness of our communications. By continuing to use this site, or by clicking “I agree” you consent to the use of cookies. Detailed information on the use of cookies is provided on our Cookies Policy”