
LangChain's Vivek Trivedy defines a harness as "every piece of code, configuration, and execution logic that isn't the model itself" ("The Anatomy of an Agent Harness," 2026-03-10), and that definition explicitly includes bundled infrastructure such as filesystem, sandbox, and browser. The working equation is Agent = Model + Harness: swap the model and the agent gets smarter or dumber, but swap the harness and what the agent can finish changes.
The term is new, the mechanism is not. ReAct (Yao et al., 2023) described the reason, act, observe loop years before anyone called the surrounding code a harness. Three authorities now disagree on where the harness ends and the runtime begins: Microsoft Learn calls a harness "the runtime scaffolding that turns a language model into an agent," Fiddler AI says the harness "is the runtime," and AWS sells Runtime as a separate layer that hosts the harness.
This article does three things in order. It works through what a harness actually is, then builds a minimal one, then compares the harnesses you can adopt today. The environment slot, the browser or sandbox the agent acts through, gets its own section, and ego (lite) is one option there. The goal is a clear picture of which layer you are changing when you change something.
What an agent harness is
A harness is every piece of code, configuration, and execution logic that isn't the model itself. That definition comes from Vivek Trivedy's "The Anatomy of an Agent Harness" (LangChain, 2026-03-10). Trivedy's component list explicitly includes bundled infrastructure: filesystem, sandbox, browser.
The shorthand is Agent = Model + Harness. Swap the model and the agent gets smarter or dumber. Swap the harness and what the agent can finish changes. Wikipedia's "Agent harness" entry (last edited 2026-09-12) says a harness "manages tool use, memory, state persistence, execution environments and feedback loops," and notes it is also called agent scaffolding.
Why a raw model cannot act
A raw model is stateless. It emits text. It does not run a loop, call a tool, or remember what happened on the previous turn unless something outside the model supplies that state and feeds it back.
That something is the harness. It holds the conversation state, decides when to call a tool, executes the call, and returns the result to the model. Without a harness, a model can describe an action. It cannot take one.
The reason, act, observe loop
ReAct (Yao et al., 2023) described the reason, act, observe loop. The model reasons about what to do, takes an action through a tool, observes the result, and repeats. The mechanism predates the term "harness."
The loop is what turns a text generator into something that can finish a task. Each observation becomes input for the next reasoning step. The harness runs the loop and owns the state between steps.
Harness vs framework vs runtime vs scaffold
Three authorities disagree on what a harness is. Microsoft Learn calls a harness "the runtime scaffolding that turns a language model into an agent." Fiddler AI says the harness "is the runtime." AWS sells Runtime as a separate layer that hosts the harness, with AWS Bedrock AgentCore Runtime and its microVM as the product-level example.
The resolution is by tense. A framework (LangGraph, CrewAI, Microsoft Agent Framework) is a build-time toolbox you may use to assemble a harness. You can write a harness directly on an SDK without one. A harness is the run-time execution layer. A runtime is the hosting layer: session isolation, scaling, identity, persistence.
The one-line test: change the runtime and behavior does not change; change the harness and the same model on the same machine behaves differently. A scaffold is separate again. It is the material the model works from: system prompt, tool descriptions, response format. HuggingFace's split is that scaffold is what the model reads, harness is what executes.
The built-in harness and the outer harness
Birgitta Böckeler (Thoughtworks, martinfowler.com, 2026-04-02) draws the useful line here. The built-in part is what the vendor ships: system prompt, built-in tools, compaction, retrieval. Böckeler does not name it an inner harness, and she records the objection that wrapping harnesses around harnesses is a strained metaphor. You cannot change it.
The outer harness is what you assemble on top: AGENTS.md or CLAUDE.md, skills, MCP servers, hooks, and the tools and environment you plug in. Böckeler adds a second axis: guides (feedforward, shape the work before it happens) versus sensors (feedback, check after), each either computational (deterministic: lint, tests, types) or inferential (semantic: LLM-as-judge). She also writes: "Engineering a user harness for a coding agent is a specific form of context engineering."
Why product docs call the whole agent a harness
Product docs often use the word to mean the whole agent. Claude Code's own documentation states: "Claude Code serves as the agentic harness around Claude."
Our own product docs use the word the same way. That is worth saying plainly. When we say ego lite is a browser harness, we mean the layer that executes browser actions for the agent, not the model and not the runtime that hosts it.
The eight parts of a harness, and the failure each one prevents
A harness is every piece of code, configuration, and execution logic that isn't the model itself, according to LangChain's Vivek Trivedy (2026-03-10). The shorthand is Agent = Model + Harness. Swap the model and the agent gets smarter or dumber. Swap the harness and what the agent can finish changes.
Wikipedia's "Agent harness" entry (last edited 2026-09-12) says a harness manages tool use, memory, state persistence, execution environments and feedback loops. It is also called agent scaffolding. The eight parts below are the working decomposition. Each one exists because a specific failure shows up without it.
| Part | What it does | The failure it prevents |
|---|---|---|
| Loop | Runs the reason, act, observe cycle that ReAct (Yao et al., 2023) described, so the model can take a step, see the result, and decide the next step. | A single completion that cannot react to what the tool returned. |
| Tools | Defines the callable actions and their schemas, so the model can affect something outside its own text. | An agent that can describe a fix but cannot run it. |
| Context and compaction | Manages what stays in the window and what gets summarized or dropped as the session grows. | A run that stalls or degrades once the transcript exceeds the context limit. |
| Filesystem and state | Gives the agent a place to read and write files and to persist state across steps. | Work that vanishes between turns because nothing outside the context window survived. |
| Environment | Provides the execution surface the agent acts in, such as a sandbox, a browser, or a shell, and this is the part with the least written about it. | An agent that can plan but has nowhere to run the plan. |
| Memory | Carries facts and prior decisions forward beyond the current context window. | The agent relearning the same project constraint on every task. |
| Guardrails | Constrains what the agent is allowed to do, including permissions, approvals, and blocked actions. | An agent taking an irreversible action that no one authorized. |
| Observability | Records what the agent did, which tools it called, and what came back. | A failure you cannot diagnose because the run left no trace. |
Harness engineering: guides, sensors, and the ratchet
Birgitta Böckeler (Thoughtworks, martinfowler.com, 2026-04-02) separates the part of the harness that ships with the agent from the outer harness you assemble yourself. The built-in part is what the vendor ships: system prompt, built-in tools, compaction, retrieval. Böckeler does not name it an inner harness, and she records the objection that wrapping harnesses around harnesses is a strained metaphor. You cannot change it. The outer harness is what you assemble on top. Her own examples are AGENTS.md and Skills; in practice it also covers MCP servers, hooks, and the tools and environment you plug in.
She then gives two axes for the outer harness. The first is guides versus sensors. The second is computational versus inferential. Addy Osmani adds a practice on top: the ratchet, where every mistake becomes a permanent rule so the agent cannot repeat it.
Feedforward guides versus feedback sensors
Guides are feedforward. They shape the work before it happens. A style guide, a plan template, or an AGENTS.md file is a guide. Sensors are feedback. They check after the work. A test suite, a linter, or an LLM-as-judge is a sensor.
The distinction matters because the two fail differently. A missing guide produces work in the wrong shape from the start. A missing sensor lets wrong work pass without anyone noticing. Böckeler writes that engineering a user harness for a coding agent is a specific form of context engineering.
Computational versus inferential
Each guide and each sensor is either computational or inferential. Computational means deterministic: lint, tests, types. Inferential means semantic: an LLM-as-judge.
Computational checks are cheap, repeatable, and give the same answer twice. Inferential checks cover what rules cannot express, and they cost a model call and can disagree with themselves. A harness usually needs both, because types will not catch a wrong plan and a judge will not catch a missing semicolon.
The ratchet
Addy Osmani describes the ratchet: every mistake becomes a permanent rule so the agent cannot repeat it. The failure happens once, then a rule is written, and the rule stays.
The ratchet is how a harness gets better without retraining anything. It is also how a harness gets bloated. Every rule is context the model reads on every run, so the ratchet trades tokens for reliability, and someone has to prune it.
Where the framework stops
This two-by-two covers what you assemble around the model. It does not cover the boundary between the agent and the outside world. Where the harness executes commands, what it can reach, and whether the host or a sandbox runs them are separate questions. That boundary is the next section.
What the agent actually sees on the web
Every harness has to answer one question for the web: when the agent needs a page, what comes back? The answer is not the page. It is a representation of the page, and the choice of representation sets what the agent can do next.
Three answers are common. A headless browser is cheap and reproducible, and it stops at the login wall. A vendor extension inherits the session, and it takes over the window you were working in. An MCP browser server returns a full accessibility snapshot at every step, which on a complex page can run past 50,000 tokens; Provar reported one Salesforce accessibility tree at 114K tokens.
The cost is measurable. Microsoft's Playwright CLI release reported 114K tokens per test through MCP against 27K through the CLI. That is the same page, the same task, and a different observation layer.
Login state is a harness problem, not a site problem
Login state is a harness problem, not a site problem. The site is behaving normally. The harness decides whether the agent arrives with a session or without one.
A harness that starts from a blank profile makes the agent look like a new device on every run. That is what produces the 2FA prompts and SSO redirects people blame on the site. The site sees a new device because the harness presented one.
Sites can still require a CAPTCHA or another check, and no arrangement bypasses one.
Every observation is a context-budget decision
Every observation is a context-budget decision. Provar reported one Salesforce accessibility tree at 114K tokens. Anthropic's "Code execution with MCP" reports 150,000 tokens down to 2,000 tokens, a 98.7% saving.
Both numbers describe the same trade: what the harness hands the model at each step. A full snapshot is faithful and expensive. A reduced observation is cheaper and loses detail. The harness picks, and the context window pays.
Filling the environment slot with ego (lite)
There is a fourth answer, and we build it, so read this with that in mind. ego (lite) is a Chromium browser that a harness drives with one shell command. It is not a framework and not an agent. It occupies the environment slot in Böckeler's outer harness, which is why it belongs in this article at all: you keep whatever harness you already have and replace only the part that decides what a page looks like when it arrives.
What the agent gets back is a Snapshot, an accessibility tree with stable @N references rather than raw HTML, and it can run several actions on the page with a few lines of JavaScript in one round trip instead of one tool call per click. Because the browser can import your Chrome profile, the agent starts from a session that is already signed in, so 2FA prompts and SSO redirects come up far less often than they do from a blank profile. Sites can still require a CAPTCHA or another check, and nothing here bypasses one. Agent work happens in its own Space, so a background task does not take the tab you are reading.
The connection question is a harness question, which is the useful part for this article. Our docs tell you to ask where your harness executes commands before anything else, because there are three answers and they are not equivalent. If commands run directly on the machine, ego-browser launches the local app and no extra permission exists to grant. If the agent runs inside a local sandbox, the harness has to provide an official host-execution or host-bridge capability. If the agent runs in a container, a VM, a remote server or a cloud runtime, installing the skill inside that environment is not enough, because the skill is instructions and it does not move where commands execute.
The check is command -v ego-browser from the same session that will do the browser work, and the docs are explicit that this only proves the session can find the binary. It does not prove commands reach the host. The docs also separate two controls that are easy to confuse: host execution and no-approval mode are different things with different risks, and turning off approval prompts does not mean the agent escaped a sandbox. That distinction is a harness property, not a browser one, which is a reasonable summary of why the environment slot deserves more attention than it gets.
| If this is your situation | Do not use ego (lite). Use this instead |
|---|---|
| Unattended runs in a CI pipeline | Playwright or Puppeteer. ego (lite) has no headless CI mode. |
| Compatibility checks on Firefox or WebKit | Playwright. We do not do cross-browser testing. |
| Many browsers scaled out on servers with no desktop | Browserbase or another cloud browser. |
| Breakpoints, network waterfalls, performance profiles | Chrome DevTools MCP. ego (lite) has no debugging panel. |
| A harness that cannot execute shell commands on this machine | An MCP browser server, or a harness bridge that can. The skill alone will not move execution. |
| Static HTML with no login and no interaction | Plain HTTP or a scraping API. Do not start a browser. |
| Deep customization or audit of the harness itself | Only the ego-browser layer is open source. |
What changes when you swap only the harness
We ran a controlled comparison on 2026-08-19. The setup was 31 tasks, 5 tools, one coding agent (pi), one model (ChatGPT 5.6 Sol at max effort), and one judge. The raw data is public at citrolabs/ego-browser-benchmark-framework.
ego lite (ego-browser) finished 93.5% of tasks at $1.64 average cost per task, which is $1.75 per completed task. Browser Harness (the local Browser Use build) finished 77.4% at $2.43 average, or $3.14 per completed task. playwright-cli finished 71.0% at $3.42 average, or $4.82 per completed task. agent-browser finished 62.9% at $2.66 average, or $4.23 per completed task. chrome-devtools-cli finished 61.3% at $4.95 average, or $8.08 per completed task.
The limit is precise. The bench holds the agent, model, effort, judge, and task set fixed and swaps only the browser layer. It shows the environment slot moves completion rate and cost per completed task. It does not isolate tokens as the cause.
Build a minimal harness in 40 lines, no framework
A harness is every piece of code, configuration, and execution logic that is not the model itself, according to LangChain's Vivek Trivedy (2026-03-10). You do not need a framework to build one. A framework is a build-time toolbox you may use to assemble a harness, but you can write a harness directly on an SDK.
The minimal harness below has four parts: a loop, two tools, a context rule, and a stop condition. It runs on a shell and a browser. The browser is the environment slot you can swap.
The loop
The loop is reason, act, observe. ReAct (Yao et al., 2023) described this cycle before the term harness existed. The model reads the current state, picks a tool, runs it, and reads the result.
Keep the loop small. One turn is one model call, one tool call, one observation. Stop when the model returns a final answer or when a turn limit is reached. The harness owns the loop, not the model.
import json, subprocess, sys
from anthropic import Anthropic
client, model = Anthropic(), "claude-opus-4-5"
TOOLS = [
{"name": "bash", "description": "Run a shell command. Returns stdout, truncated.",
"input_schema": {"type": "object", "properties": {"cmd": {"type": "string"}}, "required": ["cmd"]}},
{"name": "browser", "description": "Drive the browser. Pass a JS program; returns its output.",
"input_schema": {"type": "object", "properties": {"js": {"type": "string"}}, "required": ["js"]}},
]
def run(name, args):
cmd = args["cmd"] if name == "bash" else f"ego-browser eval {json.dumps(args['js'])}"
out = subprocess.run(cmd, shell=True, capture_output=True, text=True, timeout=180)
text = (out.stdout or "") + (out.stderr or "")
if len(text) > 4000: # the whole budget question, in one line
open("last_output.txt", "w").write(text)
text = text[:2000] + "\n...truncated, full output in last_output.txt...\n" + text[-2000:]
return text
messages = [{"role": "user", "content": sys.argv[1]}]
for turn in range(40): # a hard stop is part of the harness
r = client.messages.create(model=model, max_tokens=4096, tools=TOOLS, messages=messages)
messages.append({"role": "assistant", "content": r.content})
calls = [b for b in r.content if b.type == "tool_use"]
if not calls:
print("".join(b.text for b in r.content if b.type == "text")); break
messages.append({"role": "user", "content": [
{"type": "tool_result", "tool_use_id": c.id, "content": run(c.name, c.input)}
for c in calls]})
else:
print("stopped at the turn limit without finishing")Two tools are enough
Two tools are enough for most tasks: bash and browser. Bash runs shell commands. The browser tool returns a page snapshot and runs actions on the page.
ego lite installs a shared ego-browser Skill at ~/.agents/skills/. Any harness that can run the shell command ego-browser on the machine where ego (lite) is installed can drive it. No SDK is required. The deciding question is where the harness executes commands. If commands run directly on the machine, it works with no extra permission. If the agent runs in a local sandbox, the harness must provide an official host-execution or host-bridge capability. If the agent runs in a container, VM, remote server, or cloud runtime, installing the skill inside that remote environment is not enough without a host bridge. The docs' check is command -v ego-browser, but that only proves the session can find the binary, not that commands run on the host. Host execution and no-approval mode are different controls with different risks. Turning off approval prompts does not prove the agent has host execution.
Where the context goes
Large tool outputs fill the context window. A single Playwright MCP page snapshot can exceed 50,000 tokens on a complex page. Provar reported one Salesforce accessibility tree at 114K tokens. Microsoft's Playwright CLI release reported 114K tokens per test through MCP against 27K through the CLI. Anthropic's Code execution with MCP reports 150,000 tokens down to 2,000 tokens, a 98.7% saving.
Write large outputs to disk. Return only the head and tail to the model. The model sees enough to decide the next step, and the full output stays available for later reads. This is context engineering, not a model change.
Stopping and verifying
The agent will report success. Do not trust that report. Verify outside the agent with a deterministic check: a test, a lint, a type check, or a direct read of the result.
Böckeler (Thoughtworks, martinfowler.com, 2026-04-02) splits guides (feedforward, shape the work before it happens) from sensors (feedback, check after). Each can be computational (deterministic: lint, tests, types) or inferential (semantic: LLM-as-judge). A minimal harness needs at least one computational sensor. Addy Osmani describes the ratchet: every mistake becomes a permanent rule so the agent cannot repeat it.
Swap the browser tool and re-run
Swap the browser tool and re-run the same tasks. Keep the agent, model, effort, judge, and task set fixed. Change only the browser layer. This is how the 2026-08-19 bench was built.
The bench used 31 tasks, 5 tools, one coding agent (pi), one model (ChatGPT 5.6 Sol at max effort), and one judge. The raw data is public at citrolabs/ego-browser-benchmark-framework. ego lite (ego-browser) finished 93.5% at $1.75 per completed task. Browser Harness finished 77.4% at $3.14. playwright-cli finished 71.0% at $4.82. agent-browser finished 62.9% at $4.23. chrome-devtools-cli finished 61.3% at $8.08. The bench shows the environment slot moves the outcome. It does not isolate tokens as the cause.
Which harness should you pick?
The choice depends on what you already have, not on a ranking. If you want a coding agent today, adopt a shipped one and shape its outer harness. Birgitta Böckeler (Thoughtworks, martinfowler.com, 2026-04-02) observes that part of the harness ships with the agent, through the system prompt, the retrieval mechanism or an orchestration system, and calls the part you assemble yourself the outer harness. Her own examples of that layer are AGENTS.md and Skills; in practice it also covers MCP servers, hooks, and the tools and environment you plug in. Claude Code's own documentation states: "Claude Code serves as the agentic harness around Claude." Addy Osmani describes the ratchet: every mistake becomes a permanent rule so the agent cannot repeat it.
If you are building a product, a framework saves you the loop but not the environment. LangGraph, CrewAI, and Microsoft Agent Framework are build-time toolboxes you may use to assemble a harness. You can write a harness directly on an SDK without one. The framework gives you the reason, act, observe loop that ReAct (Yao et al., 2023) described. It does not give you the filesystem, sandbox, or browser that LangChain's Vivek Trivedy (2026-03-10) lists under "Bundled Infrastructure" in "The Anatomy of an Agent Harness." That environment is yours to build or buy.
If your needs are narrow, forty lines beats a dependency. A harness is every piece of code, configuration, and execution logic that isn't the model itself (Trivedy, 2026-03-10). For one tool and one loop, that can be a small script. Wikipedia's "Agent harness" entry (last edited 2026-09-12) says a harness "manages tool use, memory, state persistence, execution environments and feedback loops." You can implement those directly. The test from our resolution applies: change the runtime and behavior does not change; change the harness and the same model on the same machine behaves differently.
Harness engineering vs context engineering
Birgitta Böckeler (Thoughtworks, martinfowler.com, 2026-04-02) writes: "Engineering a user harness for a coding agent is a specific form of context engineering." Databricks and Wikipedia put the containment the other way, treating context engineering as one part of the harness. The practical split is one sentence: context engineering governs what the model sees this turn, harness engineering governs every mechanism outside that turn.
That includes the loop, the tools, the environment, the persistence, and the feedback sensors. The full adjudication is a separate article.
Where the term came from
The term comes from software testing. A test harness is the code and configuration that runs a test suite, feeds inputs, and checks outputs. It is not the code under test. The same shape applies here: the harness is not the model.
The 2025 to 2026 shift came as agents shipped. LangChain's Vivek Trivedy (2026-03-10) defined the agent harness as "every piece of code, configuration, and execution logic that isn't the model itself." Wikipedia's "Agent harness" entry (last edited 2026-09-12) says a harness "manages tool use, memory, state persistence, execution environments and feedback loops," and is also called agent scaffolding. The mechanism predates the term. ReAct (Yao et al., 2023) described the reason, act, observe loop before "harness" was common.
Frequently asked questions
What is an agent harness?
LangChain's Vivek Trivedy (2026-03-10) defines it as "every piece of code, configuration, and execution logic that isn't the model itself." Wikipedia's "Agent harness" entry (last edited 2026-09-12) says it "manages tool use, memory, state persistence, execution environments and feedback loops." The formula is Agent = Model + Harness. Swap the model and the agent gets smarter or dumber. Swap the harness and what the agent can finish changes.
What is the difference between an agent harness and an agent framework?
A framework is a build-time toolbox you may use to assemble a harness. LangGraph, CrewAI, and Microsoft Agent Framework are examples. You can write a harness directly on an SDK without one. The harness is what runs at run time. The framework is what you use to build it.
What is the difference between an agent harness and an agent runtime?
A runtime is the infrastructure that hosts a harness: session isolation, scaling, identity, persistence. AWS Bedrock AgentCore Runtime with its microVM is the product-level example. AWS sells Runtime as a separate layer that hosts the harness. The test: change the runtime and behavior does not change; change the harness and the same model on the same machine behaves differently.
Do I need a framework to build an agent harness?
No. A framework saves you the loop but not the environment. You can write a harness directly on an SDK. For narrow needs, forty lines beats a dependency. The environment (filesystem, sandbox, browser) is yours to build or buy either way.
Which agent harness is best?
There is no single winner. Compare on your own tasks, with your own model and judge. Our bench (31 tasks, 5 tools, one coding agent, one model, one judge, run 2026-08-19) found that swapping only the browser layer changes completion rate and cost per completed task. It does not isolate tokens as the cause. The only superlative allowed is "fastest," and only with the bench cited.



