# Agent Harnesses by [kirupa](https://www.kirupa.com/me/index.htm) | filed under [AI Fundamentals](https://www.kirupa.com/ai_fundamentals/index.htm) In [How an Agent Like Claude Code Works](https://www.kirupa.com/ai_fundamentals/how_an_agent_works.htm), we watched an agent fix the failing pickup-slots test on the Crumb & Co. bakery's website. Along the way, I called the agent's own code **the harness** and kept right on going. That one word was carrying a lot more weight than I let on. Wren, the bakery's web developer from [Agent Frameworks vs. Calling Model APIs Directly](https://www.kirupa.com/ai_fundamentals/agent_frameworks.htm), now has a pile of choices: Claude Code, Codex, GitHub Copilot, Cursor, and a bunch of open-source agents. On public benchmarks, the same model solves noticeably more or fewer tasks depending on which of these it runs inside, and the difference is the harness. In the following sections, we'll look at what a harness is, what's inside one, why it changes results so much, which harnesses are popular right now, and how Wren picks and tunes one. Onwards! ## The Model Is Only the Engine A language model, on its own, does one thing. It reads text and writes more text. If we ask it to fix a failing test, the best it can do is describe a fix. It can't open `src/pickup.js`, it can't run `npm test`, and it has no idea whether its suggestion works. Put that same model inside a harness, and the story changes: ![Both get the same request: fix the failing test. On its own, the model can only send back text, a suggested fix. In a harness, the same model works in a loop with tools like Read, Edit, and Bash, so the request ends with the test actually fixed and passing.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_engine.png) Look at the yellow box in the bottom row. When the model asks for a tool like Read, Edit, or Bash, the harness runs it and sends the result back, around and around until the job is done. That's the loop from How an Agent Works. [Claude Code's documentation](https://code.claude.com/docs/en/how-claude-code-works) describes Claude Code itself as the layer around the model that provides the tools and manages the context the model sees, and it says that layer is what the term ***"agentic harness"*** refers to. [VS Code's docs](https://code.visualstudio.com/docs/agents/overview) put it even more simply: ***"A harness provides the tools and workflow around a model."*** So the model is the engine, and the harness is the rest of the car. (The word itself comes from the straps that hook a horse up to a cart, which is a nice picture too.) ## What's Inside a Harness So what exactly is the rest of the car? Different harnesses slice it up differently, but nearly all of them have the same parts. Here they are, sorted by the job they do: ![The model, the engine, sits inside the harness. Below it are four groups of parts. What the model reads: the system prompt, the tool list, instruction files, and skills. What it can do: tools, MCP servers, and subagents. What keeps it safe: permissions, a sandbox, hooks, and checkpoints. What keeps it going: the loop, compaction, and memory. At the bottom is where we use it: a terminal, an editor, the cloud, or an app.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_parts.png) Start with the blue group, ***What the model reads***. On every trip around the loop, the harness builds a request out of its own [system prompt](https://www.kirupa.com/ai_fundamentals/system_prompts_vs_user_prompts.htm), a short description of every tool, and our project's **instruction files**, like `CLAUDE.md` or `AGENTS.md`. It also lists our **skills**, which are folders of know-how that the agent reads only when a task needs them. We'll build one from scratch in [Teaching Your Agent New Skills](https://www.kirupa.com/ai_fundamentals/teaching_your_agent_new_skills.htm). The yellow group is ***What it can do***. Built-in tools read files, edit them, and run commands. **MCP servers** plug in tools that somebody else wrote, like a connection to the bakery's order system, using a shared standard called the [Model Context Protocol](https://www.kirupa.com/ai_fundamentals/model_context_protocol.htm). [Subagents](https://www.kirupa.com/ai_fundamentals/ai_agents.htm) are extra copies of the loop, each with its own fresh context window, that the harness can send off on side jobs. The green group is ***What keeps it safe***. **Permissions** decide which tool calls run on their own and which wait for us, like the checkpoint from [Human Approval for Risky Actions](https://www.kirupa.com/ai_fundamentals/human_approval_for_risky_actions.htm). A **sandbox** is a walled-off space that limits which files and network addresses commands can reach. **Hooks** are our own scripts that the harness runs at fixed moments, such as right before a tool runs or right after a file changes. **Checkpoints** are snapshots of our files, so we can undo what the agent did. The last group is ***What keeps it going***: the loop itself, **compaction** (summarizing older turns when the [context window](https://www.kirupa.com/ai_fundamentals/context_window_limits.htm) fills up), and memory that lasts from one session to the next. Underneath it all is where we use the harness: a terminal, an editor, the cloud, or an app. ## One Trip Through the Harness A list of parts only goes so far, so let's watch them work together. Wren is back on the pickup-slots bug in Claude Code. This time, Wren has the harness ask before every edit. Here's the one trip where the model decides to change `src/pickup.js`, from top to bottom: ![One trip around the loop for Wren's pickup-slots fix, top to bottom. Context: the harness builds the request from the prompt, AGENTS.md, and the tools. Model: it asks for Edit on src/pickup.js. Permission: the harness asks Wren to allow the edit. Tool: Edit changes the file. Hook: Prettier tidies the edited file. Checkpoint: the edit is tracked so /rewind can undo it. Loop: the result goes back into the context, and the next trip begins.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_one_trip.png) Notice that the model shows up in just one row. The harness handles the other six. In the hook row, Wren's script runs Prettier, a code formatter, on the edited file. In the checkpoint row, Claude Code [tracks every edit](https://code.claude.com/docs/en/checkpointing) its file tools make, so if Wren hates the change, `/rewind` puts the old file back. Why use a hook instead of a line in an instruction file that says ***always run Prettier***? The model can skip an instruction even while it's sitting right there in the context. A hook doesn't depend on the model at all. The harness runs it after every Edit or Write call, whether the model remembers or not. Asking before every edit is a choice Wren made, too. [Claude Code's permission modes](https://code.claude.com/docs/en/permission-modes) range from Manual, which asks before most edits and commands, to auto mode, where a second AI model reviews riskier actions, like shell commands, instead of us, while ordinary reads and edits in the project go ahead on their own. At the time of writing, auto mode is where new terminal and VS Code sessions start. The [sandbox](https://code.claude.com/docs/en/sandboxing) covers only shell commands like `npm test`, is off until we turn it on with `/sandbox`, and doesn't wrap the Edit tool at all. Every harness draws these lines a little differently, so it's worth reading the security page of whichever one we use. ## Harness vs. Framework vs. Model In Agent Frameworks, Wren wrote Rye's loop by hand and then rebuilt it with a framework. So how is a harness different from a framework? Here's how I think about the three pieces: ![Three columns. A model is the engine: text in, text out, like Claude, GPT, or Gemini. A framework is a kit of parts that we build an agent with, like the AI SDK or LangGraph. A harness is a finished car: an agent we use and tune, like Claude Code or Codex. Below, an arrow from the harness to the framework column shows SDKs like the Claude Agent SDK and the Codex SDK, which let us put a finished harness inside our own app.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_vs_framework.png) Read the columns from left to right. The model is the engine, where text goes in and text comes out. A framework, like Vercel's AI SDK or LangGraph, is a kit of parts. We still build the agent ourselves, and we decide its tools, its prompts, and its rules. A harness is a car that somebody already built and tested. We get in, adjust the seat and mirrors with instruction files, permissions, and skills, and drive. The arrow at the bottom is where the line gets blurry, because several harnesses now come as libraries that we can build into our own apps. At the time of writing, here's what the big ones offer: - The [Claude Agent SDK](https://code.claude.com/docs/en/agent-sdk/overview) gives us ***"the same tools, agent loop, and context management that power Claude Code"***, in Python and TypeScript. - The [Codex SDK](https://learn.chatgpt.com/docs/codex-sdk) lets our code start, continue, and resume Codex threads, from TypeScript or Python. - The [GitHub Copilot SDK](https://github.com/github/copilot-sdk) ***"exposes the same engine behind Copilot CLI"***, and its README says it's becoming the Microsoft Copilot SDK. - Cursor and Cline offer the same idea with the [Cursor SDK](https://cursor.com/docs/sdk/typescript) and the [Cline SDK](https://docs.cline.bot/sdk/overview). So a framework is for when we want our own ideas about how the agent should work. An embedded harness is for when we'd rather borrow Claude Code's or Codex's ideas, which a lot of people have already battle-tested, and run them inside our product. ## Same Model, Different Harness Here's the part that surprised me the most. If the model is the engine, shouldn't the same engine perform the same everywhere? To find out, let's compare what one model gets in two very different harnesses. The first is Terminus 2, which the team behind the Terminal-Bench benchmark built as a [neutral way to compare models](https://arxiv.org/abs/2601.11868). The second is Claude Code: ![Two harnesses that could run the same model on the same task, compared row by row. To edit a file, Terminus 2 types shell commands, like echo or vim, while Claude Code calls its own Edit tool. Terminus 2 has one tool, a terminal, while Claude Code has Read, Edit, Bash, and more. Before risky steps, Terminus 2 never asks, while in Claude Code a second model checks the step, or it asks you. Terminus 2 was built by the benchmark team as a neutral test, and Claude Code was built by Anthropic for Claude models.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_same_task.png) Picture each one fixing Wren's pickup bug. In Terminus 2, the model has to change `src/pickup.js` by typing shell commands, the same way we would if all we had was a terminal and `vim`. In Claude Code, the model calls an Edit tool that was designed for exactly that job. In a post about [improving Cursor's harness](https://cursor.com/blog/continually-improving-agent-harness), Cursor's team explains that OpenAI's models are trained to edit files with patches, while Anthropic's models are trained on string replacement. Giving a model the edit tool it didn't train on costs it extra thinking and leads to more mistakes, so Cursor hands each model the tool it knows. We can see the effect in public numbers. **Terminal-Bench 2.0** is a benchmark of hard, realistic tasks that an agent has to complete in a terminal, and its [leaderboard](https://www.tbench.ai/leaderboard/terminal-bench/2.0) lists every result as a harness and model pair. Here are some runs that the benchmark marks as verified, at the time of writing: ![Terminal-Bench 2.0 results from verified runs, as the percentage of tasks solved. GPT-5 solved 49.6% in Codex CLI, 43.8% in OpenHands, 35.2% in Terminus 2, and 33.9% in Mini-SWE-Agent. Claude Opus 4.6 solved 62.9% in Terminus 2 and 58.0% in Claude Code.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_bench.png) Look at the four GPT-5 bars first. The model is identical in all of them, and its score goes from 33.9% in Mini-SWE-Agent to 49.6% in Codex CLI, which is OpenAI's own harness. That's a 15.7-point swing for the same model. Now look at Claude Opus 4.6. Anthropic's own harness, Claude Code, scored 58.0%, which is a bit below the neutral Terminus 2 at 62.9%. So a model company's own harness isn't automatically the best one for every job. A benchmark also measures one kind of work, done with nobody watching, so it can't tell us how a harness feels to use every day. Two more details keep this honest. First, the [Terminal-Bench paper](https://arxiv.org/abs/2601.11868) found that picking the model usually matters more than picking the harness. In its runs, Codex CLI's score rose by 52% when it switched from the much smaller GPT-5-Nano to GPT-5.2, while Gemini 2.5 Pro gained 17% from switching harnesses. Second, the leaderboard also lists unverified submissions, where custom harnesses report even higher scores for these same models. I'd treat those as claims until somebody reproduces them. ## Popular Harnesses There are a lot of harnesses, and they change quickly. Here are the ones you're most likely to run into, with details from each one's own docs and repositories at the time of writing (November 2026). In the last column, plugins and extensions are add-on packages that bundle things like skills, hooks, and MCP servers, and goose's recipes are saved, reusable workflows. A dash means I couldn't confirm that detail in the official docs: | Harness | Where it runs | Open source? | Instruction file | Guardrails | Extends with | |---|---|---|---|---|---| | [Claude Code](https://code.claude.com/docs/en/overview) Anthropic | Terminal, VS Code and JetBrains, desktop app, web | No | `CLAUDE.md`, or `AGENTS.md` when there's no `CLAUDE.md` | Permission modes, including auto mode with a reviewer model, plus an optional sandbox for shell commands | MCP, skills, hooks, subagents, plugins | | [OpenAI Codex](https://learn.chatgpt.com/docs/open-source) OpenAI | CLI, IDE extension, ChatGPT desktop app, Codex cloud | The CLI and SDK are (Apache-2.0); the IDE extension and cloud aren't | [`AGENTS.md`](https://learn.chatgpt.com/docs/agent-configuration/agents-md) | An [operating-system sandbox](https://learn.chatgpt.com/docs/sandboxing) (Seatbelt on macOS) plus an approval policy | MCP, skills, hooks, subagents, plugins | | [GitHub Copilot](https://docs.github.com/en/copilot/concepts/copilot-surfaces/copilot-cli) GitHub | Copilot CLI, VS Code and other editors, the GitHub Copilot app, cloud agent on GitHub | The CLI isn't; the Copilot SDK is (MIT) | [`.github/copilot-instructions.md`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-custom-instructions), `AGENTS.md`, `CLAUDE.md`, `GEMINI.md` | Tool allow and deny lists, an optional local sandbox, and a firewall for the cloud agent | MCP, skills, hooks, custom agents, plugins | | [Gemini CLI](https://github.com/google-gemini/gemini-cli) Google | Terminal | Yes (Apache-2.0) | `GEMINI.md`, and `AGENTS.md` if we configure it | Approval modes, plus an [optional sandbox](https://geminicli.com/docs/cli/sandbox/) (Seatbelt, Docker, or Podman) | MCP, skills, hooks, subagents (experimental), extensions | | [Cursor](https://cursor.com/docs/cloud-agent) | Editor, CLI, and Cloud Agents in their own virtual machines | No | [`.cursor/rules`](https://cursor.com/docs/rules), `AGENTS.md` | [Run modes](https://cursor.com/docs/agent/security/run-modes): auto-review with a sandbox, an allowlist, or run everything | MCP, skills, hooks, subagents, plugins | | [OpenHands](https://docs.openhands.dev/overview/introduction) The OpenHands community, backed by All Hands AI | Browser app, its SDK, OpenHands Cloud | Yes (MIT) | [`AGENTS.md`](https://docs.openhands.dev/overview/skills), plus `CLAUDE.md` and `GEMINI.md` | Docker and other sandboxes, plus a confirmation policy | MCP, skills, hooks, plugins, sub-agents | | [Aider](https://aider.chat/) Aider-AI | Terminal | Yes (Apache-2.0) | [`CONVENTIONS.md`](https://aider.chat/docs/usage/conventions.html), loaded with `/read` or a config file | [A Git commit for every edit](https://aider.chat/docs/git.html), with `/undo` | - | | [Cline](https://docs.cline.bot/cline-overview) | Editor extension, CLI, desktop app, cloud agents | Yes (Apache-2.0) | [`.clinerules`](https://docs.cline.bot/customization/cline-rules), `AGENTS.md` | Asks before every action by default, with optional auto-approve | MCP, skills, hooks, subagents, checkpoints | | [goose](https://github.com/aaif-goose/goose) The Agentic AI Foundation, started at Block | Desktop app, CLI | Yes (Apache-2.0) | [`AGENTS.md`](https://goose-docs.ai/docs/guides/context-engineering/using-goosehints), `.goosehints` | [Permission modes](https://goose-docs.ai/docs/guides/managing-tools/goose-permissions), from fully autonomous (the default) to manual approval | MCP extensions, skills, recipes | A few rows in that table changed recently, which shows how fast all of this moves. Google moved free and Google AI Pro and Ultra users from Gemini CLI to its new [Antigravity CLI](https://developers.googleblog.com/an-important-update-transitioning-gemini-cli-to-antigravity-cli/) on June 18, 2026, and Gemini CLI now serves enterprise Code Assist users. GitHub's Copilot coding agent is now called the [Copilot cloud agent](https://github.blog/changelog/2026-04-01-research-plan-and-code-with-copilot-cloud-agent/). The [OpenHands docs](https://docs.openhands.dev/openhands/usage/cli/quick-start) say its CLI is no longer actively maintained, and Aider's most recent release, version 0.86.0, came out in August 2025. ## Choosing a Harness With that many options, how does Wren pick one? I'd start with these five questions: ![Five questions for choosing a harness. Where do I work all day: a terminal, an editor, or GitHub? Which models do I want: one company's, or my pick? How much should it do alone: approvals, a sandbox, or a cloud machine? Do I need to read its code: open source, or not? Will my setup carry over: AGENTS.md, skills, and MCP?](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_choose.png) The first two questions are about habits. If we live in a terminal, Claude Code, Codex, Copilot CLI, and Aider feel at home, and if we live in an editor, Cursor, Cline, and VS Code's agents do. Claude Code and Codex are built around their own company's models, while Copilot, Cursor, Cline, OpenHands, and goose let us choose from several companies' models. The third question is about trust. An agent on our own computer can touch whatever we can, so its approvals and sandbox are what protect our files. A cloud agent starts out walled off in its own machine, which makes long runs safer, as long as we're careful about what we connect it to ([Least-Privilege Access for Tools](https://www.kirupa.com/ai_fundamentals/least_privilege_tools.htm) goes deeper). The last two questions are about the future. Open source means we can read exactly what the harness sends to the model, and shared standards mean our setup comes with us if we switch. Wren sticks with Claude Code, since it fixed the pickup-slots bug the first time. But Wren wants the project's setup to keep working if the bakery tries a different harness later. ## Tuning a Harness Out of the box, a harness knows nothing about the bakery. Tuning it mostly means adding a few files to the project. Here's Wren's project after an afternoon of setup: ![Wren's project folder, crumb-site. AGENTS.md holds how we build and test. .mcp.json connects the order system. Inside the .claude folder, settings.json holds permissions and hooks, and skills/pickup-hours/SKILL.md holds how pickup hours work.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_folder.png) Back in How an Agent Works, the project's rules lived in `CLAUDE.md`. Wren moves them into `AGENTS.md`, because most harnesses in the table read it on their own (Gemini CLI needs a setting, and in Aider we load it by hand). By default, Claude Code reads it only when there's no `CLAUDE.md` or `CLAUDE.local.md` in the project or the folders above it, according to [its memory docs](https://code.claude.com/docs/en/memory). (A `CLAUDE.md` that imports `AGENTS.md` works too.) The same docs suggest keeping these files under 200 lines. Wren's is a lot shorter than that: ```markdown # Crumb & Co. website - Install with `npm install`. Run the tests with `npm test`. - Pickup hours live in src/pickup.js. Saturday pickups are at 9:00 and 11:00. - Never edit anything in vendor/. It's copied from another project. - Run `npm test` before saying a change is done. ``` Next come the permissions. Wren wants the tests to run without a prompt, a `git push` to wait for a yes, and the secrets file and the vendor folder to be off-limits. Here are those rules, sorted by what each one does: ![Wren's permission rules in three rows. Allow, which runs without asking: npm test and git diff. Ask, which waits for Wren: git push. Deny, which never runs: reading the .env file and editing anything in the vendor folder.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_rules.png) In Claude Code, those rules go in `.claude/settings.json`, using the [permission rule format](https://code.claude.com/docs/en/permissions) from its docs. The same file holds the Prettier hook from our trip, written the way Claude Code's [hooks guide](https://code.claude.com/docs/en/hooks-guide) shows it: ```json { "permissions": { "allow": ["Bash(npm test *)", "Bash(git diff *)"], "ask": ["Bash(git push *)"], "deny": ["Read(./.env)", "Edit(./vendor/**)"] }, "hooks": { "PostToolUse": [ { "matcher": "Edit|Write", "hooks": [ { "type": "command", "command": "f=$(jq -r '.tool_input.file_path') && npx prettier --write --ignore-unknown \"$f\"" } ] } ] } } ``` Those same docs include a warning. A rule like `Bash(git push *)` matches the command text the model writes, so a push written another way, like `git -C . push`, slips past it. So the rule catches the usual way of pushing, and that's all. Wren also turns on the sandbox, which limits which files and network addresses commands can reach. And for something Wren truly never wants to happen without a yes, like pushing code, the safest move is to not give the agent the credentials to do it at all, which is [least privilege](https://www.kirupa.com/ai_fundamentals/least_privilege_tools.htm) at work. The last two files add know-how and reach. The `pickup-hours` skill explains how the bakery's pickup schedule works, and the agent reads it only when a task touches pickups. The `.mcp.json` file connects an MCP server for the bakery's order system, so the agent can look up real orders instead of guessing. Other harnesses keep these settings in their own files, but the ideas carry over. Here are the habits I'd boil it all down to: - When the agent keeps getting something wrong, add a line to `AGENTS.md`. - Turn prompts you always approve into allow rules, and things that must never happen into deny rules. - Use a hook for anything that has to happen every time. - Move long, task-specific know-how into a skill. - Add MCP servers one at a time, with as few tools as possible. - Turn on the sandbox before the agent works alone for long stretches. ## Where Harnesses Are Headed The trend that helps Wren the most is that the files from the last section are turning into shared standards, so a setup made for one harness works in others: ![On the left, one project holds three shared pieces: AGENTS.md for instructions, SKILL.md folders for skills, and MCP for connections. An arrow points to many harnesses that read them, including Claude Code, Codex, Copilot, Cursor, Gemini CLI, Cline, goose, OpenHands, and Antigravity CLI. All three standards are hosted by the Agentic AI Foundation.](https://www.kirupa.com/ai_fundamentals/images/agent_harnesses_standards.png) Start with the left box. `AGENTS.md` came from OpenAI in August 2025, and [its site](https://agents.md) calls it ***"a README for agents"*** that over 60,000 open-source projects use. MCP came from Anthropic. Agent Skills, the `SKILL.md` format, came from Anthropic too, and Anthropic's [donation announcement](https://www.anthropic.com/news/donating-agent-skills-to-the-agentic-ai-foundation) says more than 70 agent platforms support it. None of the three belongs to a single company anymore. The Linux Foundation [formed the Agentic AI Foundation](https://www.linuxfoundation.org/press/linux-foundation-announces-the-formation-of-the-agentic-ai-foundation) on December 9, 2025, with MCP, goose, and AGENTS.md as its founding projects, and Anthropic donated Agent Skills to it on October 22, 2026. The harnesses still compete on their tools, prompts, and permissions, while the files that hold our project's setup become common ground. The harnesses themselves are spreading across surfaces. [VS Code](https://code.visualstudio.com/docs/agents/overview) now lets us pick the Copilot, Claude, or Codex harness from the same chat panel, Microsoft says its [Copilot harness](https://blogs.microsoft.com/blog/2026/10/28/introducing-the-microsoft-copilot-harness-unlocking-the-potential-of-truly-multi-model-agentic-work/) powers the GitHub Copilot app, the CLI, and VS Code, and Google says Antigravity CLI shares its harness with the Antigravity desktop app. I can't tell you which harness will be on top a year from now, but I'm fairly confident the parts list from earlier will still describe it. ## Conclusion We started with a model that could only describe a fix. The harness is what turned it into an agent that actually fixed the pickup-slots bug. It decides what the model reads, which tools it can use, what's allowed without asking, how the context gets trimmed, and where we work with it. That's also why the same model scored anywhere from 33.9% to 49.6% on Terminal-Bench 2.0 depending on the harness around it. Picking a harness comes down to the five questions from Choosing a Harness. Tuning one comes down to a short `AGENTS.md`, allow and deny rules, a hook or two, skills, and carefully chosen MCP servers. Next, we'll take a closer look at one of those pieces in [Teaching Your Agent New Skills](https://www.kirupa.com/ai_fundamentals/teaching_your_agent_new_skills.htm), where a folder of know-how teaches an agent to draw.