DEV Community

Cover image for One Open Source Project a Day (No. 191): Strands Agents Harness SDK — From Hand-Rolled Agent Loops to a Production-Ready Agent in One Call
WonderLab
WonderLab

Posted on

One Open Source Project a Day (No. 191): Strands Agents Harness SDK — From Hand-Rolled Agent Loops to a Production-Ready Agent in One Call

Introduction

"Choose Strands when you would otherwise write your own agent loop: it runs in your process with no hosted control plane, and it covers the jobs a hand-rolled loop grows into."

This is the 191st article in the "One Open Source Project a Day" series. Today's project is Strands Agents (repository name harness-sdk).

Writing an AI agent that actually works in production is rarely as simple as "call the model, run the tool." In real usage you quickly run into a set of small but unavoidable problems: what happens when the conversation runs too long? What happens when tool results flood the context window? How do you resume after a session gets interrupted? Do you have to rewrite everything when switching model providers? Most teams' answer is to cobble together their own agent loop, then keep patching it as new problems surface — until that hand-rolled loop has grown session management, context compression, multi-model adapters, guardrails, and a pile of other things that should really be infrastructure, not bespoke code.

Strands Agents is an open-source agent SDK from the AWS team, shipping Python and TypeScript implementations, built to solve exactly this. It's organized in two layers: at the bottom is the Strands SDK, a model-driven, fully customizable agent loop, tool system, and multi-model support; on top of it is Strands Harness, which gives you a fully assembled, production-grade agent with a single create_harness() (or createHarness() in TypeScript) call — already configured with context management, session persistence, long-term memory, and a skill system. And the object you get back is still a plain strands.Agent, meaning everything Harness configures for you can be inspected, overridden, or replaced at will.

8,300+ Stars, 1,200+ Forks, Apache-2.0 License, developed and maintained primarily by the Strands team at AWS.

What You Will Learn

  • The layered relationship between the Strands SDK and Strands Harness: "build your own agent loop" vs. "get a pre-configured production-grade agent"
  • What create_harness() gives you by default: context management, session persistence, long-term memory, skill loading
  • The built-in tool set: shell, file operations, programmatic_tool_caller, and subagent delegation
  • Model portability: switching between Bedrock, Anthropic, OpenAI, and Gemini using the same code
  • MCP integration, interventions (tool-call gating), and subagent delegation patterns

Prerequisites

  • Basic development experience in Python or TypeScript
  • A basic understanding of LLM agent concepts (tool calling, multi-turn conversations)
  • Optional: a basic understanding of MCP (Model Context Protocol)

Project Background

What It Is

Strands Agents describes itself as "a model-driven approach to building AI agents in just a few lines of code." The README states the value proposition directly: "Choose Strands when you would otherwise write your own agent loop: it runs in your process with no hosted control plane, and it covers the jobs a hand-rolled loop grows into." This sentence captures the project's core pitch — it isn't just another thin skin over an "agent framework," it's the infrastructure that hand-rolled agent loops keep reinventing (lifecycle controls, tools, structured output, MCP, multi-agent patterns, memory, sessions, model portability, streaming, guardrails, tracing, evals), already built and ready to use.

This repository (harness-sdk) is a monorepo containing:

  • harness-py/, harness-ts/: the Python/TypeScript Strands Harness, assembled via create_harness() / createHarness()
  • strands-cli/: a CLI to prototype and chat with a harness agent from the terminal
  • strands-py/, strands-ts/: the underlying SDKs — the agent loop, model providers, tool system
  • site/: source for the official documentation site (built with Astro/Starlight)

Team and Background

  • Organization: strands-agents (led by the Strands team at AWS)
  • License: Apache License 2.0
  • Language support: Python 3.10+, TypeScript (Node.js 22+)
  • Distribution: PyPI (strands-agents, strands-harness), npm (@strands-agents/sdk, @strands-agents/harness, @strands-agents/cli)

Project Stats

  • ⭐ GitHub Stars: 8,300+
  • 🍴 Forks: 1,246
  • 📄 License: Apache-2.0
  • 🐛 Open Issues: 837 (high activity level, frequent community feedback)
  • 📅 Created: 2025-05

What It Does

The Problem It Solves

The typical evolution of a hand-rolled agent loop:
  v1: a simple loop of model.generate() + tool calls
  ↓ conversations get longer → manually truncate history, risking dropped context
  ↓ tool results get too large → write custom summarization logic to fit the prompt
  ↓ need to switch model providers → rewrite the calling layer and parameter mapping
  ↓ need resumable sessions → implement your own session storage and recovery
  ↓ need to remember user preferences → implement your own "memory" storage and retrieval
  ↑ every step reinvents infrastructure, and each team's version is incompatible with everyone else's

Strands' approach:
  Bottom layer SDK: a model-driven agent loop + tool system + multi-model support, ready to use
  ↓
  Top layer Harness: one create_harness() call
  ↓
  Get back an agent pre-configured with context management/sessions/memory/skills
  ↑ the return value is still a plain Agent — everything Harness configures
    can be overridden, extended, or replaced
Enter fullscreen mode Exit fullscreen mode

Use Cases

  1. Quickly building a coding/ops agent that handles long-running tasks

    • The kind of task shown in the official example — agent("Find the slowest test in this repo and explain why it's slow") — requiring multi-step file reading, running shell commands, and analyzing results
  2. Production systems that need model portability

    • Teams may run Bedrock, Anthropic, and OpenAI simultaneously, or need to switch providers later; Strands' provider/model string syntax makes that a one-parameter change
  3. Assistant-style products that need long-term memory and session recovery

    • Harness persists every conversation to disk by default and distills cross-conversation long-term memory via a background task, fitting scenarios like customer support or personal assistants that need to "remember" user preferences
  4. Complex tasks that need to delegate subtasks and keep the main context from flooding with search results or multi-step exploration

    • The built-in subagent tool lets the main agent hand off tasks like "search across many files," "a multi-step change," or "open-ended exploration" to a clean child agent, returning only its final answer

Quick Start

Minimal SDK usage (Python):

pip install strands-agents strands-agents-tools
Enter fullscreen mode Exit fullscreen mode
from strands import Agent
from strands_tools import calculator

agent = Agent(tools=[calculator])
agent("What is the square root of 1764")
Enter fullscreen mode Exit fullscreen mode

Minimal SDK usage (TypeScript):

npm install @strands-agents/sdk
Enter fullscreen mode Exit fullscreen mode
import { Agent } from '@strands-agents/sdk'

const agent = new Agent()
const result = await agent.invoke('What is the square root of 1764?')
console.log(result)
Enter fullscreen mode Exit fullscreen mode

Getting a production-grade agent directly with Harness (Python):

pip install strands-harness
Enter fullscreen mode Exit fullscreen mode
from strands_harness import create_harness

agent = create_harness()
agent("Find the slowest test in this repo and explain why it's slow")
Enter fullscreen mode Exit fullscreen mode

Getting a production-grade agent directly with Harness (TypeScript):

npm install @strands-agents/harness
Enter fullscreen mode Exit fullscreen mode
import { createHarness } from '@strands-agents/harness'

const agent = await createHarness()
await agent.invoke("Find the slowest test in this repo and explain why it's slow")
Enter fullscreen mode Exit fullscreen mode

Prefer not to write code at all? Install the CLI with npm install -g @strands-agents/cli and you get a strands terminal command that chats directly with a Harness agent.

Core Features

1. Layered design: SDK provides the foundation, Harness provides the assembly

The underlying strands.Agent is a set of primitives you can fully assemble yourself; create_harness() composes those primitives into a ready-to-use agent using benchmarked defaults. There's no gap between the two layers — the agent Harness returns is a plain Agent, so every piece it configures can still be overridden after the fact.

2. Production-grade capabilities out of the box

Capability Default behavior
Model Defaults to Claude Opus on Amazon Bedrock; supports Bedrock/Anthropic/OpenAI/Google and more
Tools Comes with shell, file read/write/edit, web_fetch, and programmatic_tool_caller (a sandbox for tool orchestration)
Context management Automatically summarizes older conversation turns and relocates bulky tool results to storage, leaving a short reference behind
Sessions Every conversation is persisted to ./.agent/sessions by default, resumable by session id
Long-term memory Distills user preferences and project facts across conversations, saved as markdown and folded back into context
Caching System prompt, tool definitions, and history are cached automatically wherever the provider supports it

3. A flexible model-selection syntax

A single provider/model string switches between providers using consistent syntax; reasoning effort is also unified into one set of levels (off/minimal/low/medium/high/xhigh/max), with the SDK mapping them to each provider's own parameters:

create_harness(model="anthropic/claude-opus-5")
create_harness(model="openai/gpt-5.6-sol")
create_harness(model="bedrock/global.anthropic.claude-opus-5")  # the default
Enter fullscreen mode Exit fullscreen mode

4. Fine-grained control over built-in tools

builtin_tools supports two shapes: a list pins exactly the tools named, while a mapping edits the default set — False removes a tool, True adds one, and a config dict both enables and configures it:

create_harness(builtin_tools=["read"])                     # keep only read
create_harness(builtin_tools={"subagent": False})          # defaults minus subagent delegation
create_harness(builtin_tools={"web_fetch": {"model": "openai/gpt-5-mini"}})  # configure web_fetch's own model
Enter fullscreen mode Exit fullscreen mode

5. Two subagent delegation patterns

The built-in subagent tool lets the main agent hand a subtask off to a full Harness child that inherits the parent's model, tools, skills, and intervention policies; alternatively, Agent.as_tool() wraps any dedicated agent into a tool — useful when you need a fixed role (like a "reviewer" agent that only reviews code). Both can coexist.

6. Native MCP and web access support

Point mcp_servers at a standard mcpServers config (a JSON file or an inline dict) and Harness connects each server, discovers its tools, and adds them to the tool list automatically; web_fetch is on by default, web_search turns on or off automatically depending on whether the model provider natively supports it, and can also be explicitly routed through Exa as a third-party search backend.

7. Agent Skills and interventions

Drop Agent Skills into ./.agent/skills and Harness loads them automatically; the interventions parameter supports "ask", "smart", a custom policy string, or even a .cedar policy file — a gate you can put in front of tool calls for approval or validation.

Project Advantages

Dimension Hand-rolling an agent loop from scratch Using only the underlying SDK (strands-py/ts) Strands Harness
Time to first result Slow — reinventing infrastructure Moderate — loop and tool primitives already in place Fast — one call gets you a full default configuration
Customizability Fully open High High (the return value is still a native Agent — override anything)
Context/session/memory management Build it yourself Wire it in yourself Built in by default
Model portability Build your own adapter layer Multi-provider support already exists at the SDK layer One string parameter switch
Production readiness Depends on the team Depends on how much you fill in yourself Defaults are "benchmarked and tested" out of the box

Why choose this project?

  • Led by the AWS team, with active updates and issue response (837 open issues signals a real, actively-used user base)
  • Consistent API design across Python and TypeScript — mixed-stack teams don't need two mental models
  • A "layered but not locked in" philosophy — Harness gives you defaults, not a closed framework you're boxed into

A Deeper Look

What Harness Actually Assembles

The parameter list of create_harness() reads like a checklist of "what a production-grade agent needs":

create_harness(
    model="bedrock/global.anthropic.claude-opus-5",  # model provider and version
    effort="auto",                          # reasoning effort
    instructions=None,                      # domain instructions appended to the system prompt
    tools=None,                             # custom tools
    mcp_servers=None,                       # MCP server configuration
    plugins=None,                           # custom plugins
    builtin_tools=None,                     # add/remove/edit the built-in tool set
    background_tasks=None,                  # background task policy
    builtin_plugins=["todos", "environment"],  # built-in feature plugins
    caching="auto",                         # context caching
    context_manager="auto",                 # context management policy
    session=True,                           # session persistence
    skills=True,                            # skill loading
    memory=True,                            # long-term memory
    interventions=None,                     # tool-call intervention policy
    **agent_kwargs,
)
Enter fullscreen mode Exit fullscreen mode

The logic behind this list is clear: every capability that a hand-rolled agent loop eventually grows into — lifecycle controls, context compression, session recovery, cross-conversation memory, approval gates — is already implemented with a benchmarked default, rather than being left for each user to rediscover on their own.

Context Management: Summarization Plus Externalized Storage

The easiest thing to lose control of in a long-running task is the context window. Harness's default strategy is two-pronged: automatically summarize older conversation turns, while relocating bulky tool results (say, the large volume of file content returned by a search) to external storage, leaving only a short reference in the context. This means the context doesn't grow linearly no matter how many turns a task runs for — when an old result is actually needed, the agent can pull it back by reference instead of every turn carrying the full history.

Subagent Delegation: Two Modes for Two Different Needs

The project distinguishes between two delegation patterns, reflecting two different intents:

  • The built-in subagent tool: the model autonomously decides to delegate a task to a full Harness child that inherits the parent's entire configuration (model, built-in tools, plugins, skills, intervention policies). The child can narrow the tools granted by the parent, but never widen them — a deliberate safety boundary. Delegation depth is bounded by default to prevent unbounded recursive delegation.
  • A dedicated agent wrapped via Agent.as_tool(): suited for a fixed role with a single responsibility (like a reviewer that only does code review). Each call runs from a fresh conversation, making it a clean, focused delegate rather than a shared session.

The two can coexist: the built-in subagent handles general-purpose "exploratory" delegation, while as_tool() handles expert delegation with a fixed role and prompt. This distinction reflects two different understandings of "delegation" — one where the model judges when to hand off work itself, and one where the engineer pre-defines the role boundaries.

Built-in Tools and Sandboxed Orchestration: programmatic_tool_caller

One notable design choice in Harness's default tool set is programmatic_tool_caller — a sandbox where the agent writes code to chain, loop over, and parallelize its other tools, instead of going through a full "model generates call parameters → executes → model reads the result → decides next step" reasoning cycle for every single tool call. For batch, mechanical operations — like "read 50 files and count how often a pattern appears" — this kind of orchestration is far more efficient than calling tools one at a time, and it saves on unnecessary model reasoning overhead.

How Model Portability Is Implemented

The provider/model string is a thin alias mapping (bedrock, bedrock-mantle, anthropic, openai, google, ollama, litellm); for any provider outside that list, you simply pass a Model instance and the SDK uses it as-is. The effort parameter follows the same philosophy: unified into one set of enumerated levels, with the SDK mapping them to each provider's own native parameter names — but if a requested level isn't offered by a given provider, the SDK raises rather than silently degrading, avoiding the hidden failure mode of "thinking you turned on high-effort reasoning when it silently didn't take effect."

Compared to Building From Scratch: Layered but Not Locked In

Strands' design philosophy can be summarized as "layered but not locked in." Most agent frameworks give you either a set of fully free primitives that you have to assemble entirely yourself, or a tightly integrated black box that's hard to escape when you need custom behavior. Strands tries to have both: the Harness layer gives you a benchmarked, deploy-ready default configuration, but what it returns is a completely ordinary Agent — meaning you can bypass Harness's defaults at any time and reach directly into the underlying SDK's hooks, intervention mechanisms, and custom session backends, without paying the cost of "escaping the framework" through an expensive rewrite.


Project Links and Resources

Official Resources

Related Resources


Summary

Key Takeaways

  1. A layered architecture: the underlying SDK provides a fully customizable agent loop and tool primitives, while Harness on top provides a one-call, production-grade default configuration, with no gap between the two layers
  2. Defaults cover the common pain points of hand-rolled loops: context management, session persistence, long-term memory, and caching optimizations all work out of the box
  3. Model portability is a first-class concern: a unified provider/model syntax and reasoning-effort levels let you switch model providers without rewriting business logic
  4. Two subagent delegation patterns serve different intents: the built-in subagent supports model-driven autonomous delegation, while Agent.as_tool() supports engineer-defined expert roles
  5. Led by the AWS team, with strong activity: 8,300+ Stars and 837 open issues indicate a project that's genuinely in use and actively iterated on

Who This Is For

  • Teams about to write their own agent loop, but haven't yet gotten to sessions, memory, or context compression: can skip straight past the "reinvent infrastructure" phase
  • Teams that need to stay flexible across multiple model providers: the unified model-switching syntax reduces provider lock-in risk
  • Developers wanting to quickly build a coding/ops agent that handles long-running, multi-step operations: Harness's default tool set (shell, file operations, orchestration sandbox) covers most scenarios
  • Teams mixing Python and TypeScript stacks: both SDKs keep a consistent API design, avoiding two separate mental models

One-Line Verdict

Strands Agents doesn't wrap "building an agent" into a closed black box — it first honestly builds out the infrastructure that a hand-rolled loop would eventually need to add anyway, then lets you decide whether to start from it.


Check out PrimeSkills — a curated marketplace of AI agents and skills that have been validated in real-world, enterprise-grade workflows. No fluff, just what actually works.

Find more useful knowledge and interesting products on my Homepage

Top comments (0)