Book a call
LESSON12mVERIFIED 2026-08-02 · CLAUDE CODE 2.1.220 · CODEX CLI 0.144.1 · GITHUB COPILOT CLI 1.0.77 · ANTIGRAVITY CLI 1.1.9 · KIMI CODE CLI 1.49.0

What a harness is, and why most "model quality" is harness quality

Two engineers run the same model and file opposite reviews. The difference is the harness — the scaffolding around the model, and the half of the system you can actually change.

Two people, one model, opposite reviews

So we recently heard that an agent rewrote an entire service over the weekend with a tidy diff, and then another developer told us it must have hallucinated a non-existent function and removed a test out of nowhere — same model, same week, both stories accurate.

But in neither of these was mentioned which harness it was, what version it is, no link to the marketing page. That's a problem because the model gets both the credit and the blame. In fact, every "wow, this thing is so good" we've heard is mostly "wow, this pair is really good."

It's actually the key lesson all the rest of the Academy builds on. Everything that follows is harness work.

What the harness is

So what is a harness? The way Anthropic defines it is: "the software scaffolding around a model: the loop, tools, context management, and guardrails that turn raw intelligence into a working agent". Underneath there's a model — which is stateless, meaning it takes text in, outputs text, has no memory of the previous call, and can't read or run anything on its own. In terms of research, the task is a control problem: the model is an open-loop policy, and the harness is the controller that closes the loop, so everything that determines what's the input text and what's the output text is the harness. There are four things:

  • What it sees — what files it reads, what instruction files it loads, what survived from the last compaction, what was silently discarded once the window filled, etc. Most of it not deliberately chosen by anyone, and almost never looked at.

  • What it can do — the list of tools, as well as their descriptions; if a model doesn't know about a tool, it's as if this tool doesn't exist; if a tool is badly described, the model will invoke it in the wrong way.

  • What it's allowed to do — approvals, allow-lists, sandboxes; not a single toggle: tools, file paths and network access are probably gated separately, depending on what the operator was aware of.

  • When it stops — the loop; how many times it goes, based on what and when the session should stop.

If you change any of these four, you changed the system without touching the model.

The measurement

The thing is that people measure it — not in a "yeah, I feel" kind of way, but in a "I can prove it to you" way.

For example, May 2026 position paper Stop Comparing LLM Agents Without Disclosing the Harness argues that when it comes to long-horizon tasks, between comparable frontier models, the harness is often a more significant factor than the model in terms of the agent's performance. We say "often" because this isn't a general statement that harnesses are better than models; it's about the point where people compare two current-edge models on a long task, and then the loud variable is exhausted so the quiet one comes into play. The paper further shows that harness-related variance can be significant, sometimes exceeding model-related variance (including cases when changing the harness inverts which of the compared models appears to be better).

For example, it mentions that based on independent monitoring, it's up to 11–15 percentage points of scaffold-only variation on SWE-bench Verified, and also emphasises that choice of the scaffold is the most important factor influencing the overall performance — more than a few model releases combined. The paper's conclusion is that as long as harnesses are not disclosed, agent leaderboard comparisons should be considered incomplete and potentially misleading.

This is why for example Artificial Analysis publishes its Terminal-Bench methodology using Terminus 2 agent harness inside e2b sandbox (which it names because the figure doesn't make sense without this). It shows that an agentic benchmark percentage is the score of a pair, and usually only half of it appears in the headline.

Why it shows up as "the model got dumber"

So what happens is that every few months we see a wave of posts saying that some model was stealthily dumbed down, which sometimes is true, but often isn't. Usually it's because the harness is mostly invisible: few tools visualise the assembled window, what the tool list looked like at the start of the session or when the last compaction threw away a constraint you've explained forty minutes earlier; the model on the other hand has a name and version and is present in every session. If the output is worse and you can see one variable, you point the finger at the variable you can see.

What actually changed:

  • The session was long, so early context (including the explanation of what you wanted) got condensed into something shorter and flatter.

  • Three MCP servers were added; most clients preload every tool's definition, so now there are dozens of additional descriptions on top before it reaches your question; some harnesses started deferring this recently — which is a change to the harness everyone will experience as the model getting better.

  • The instruction file has been growing for six months without anyone ever removing a line, so the standing prompt is now outdated advice.

  • The code moved to a messier part of the repo; same model, same prompt — much worse inputs.

None of these is about the model, all of these are things you can address in an hour.

The half you can change

What's more important though is that you can't improve the model, it's another company's roadmap on their own schedule. The other half is entirely yours and you have leverage in not-so-sexy places: a properly up-to-date instruction file, a short tool list, gate for things you wouldn't want it to do unsupervised, and a way for it to find its own mistakes before you do.

What this means is that when it comes to harnesses, it's more productive to focus on the scaffolding rather than the model — most can point to multiple models, and the model is the component that's the most likely to change under your feet; durable differences are in how instruction files load, the gate design, whether there are hooks, and context management when the window fills.

Also, harness quality is partly your responsibility as you need to remember that the vendor provides you with the loop and the default toolset, but the context's contents (which tools it contains), what it can do (what paths it can access, which URLs) is up to you; we've seen teams that have done this work and ones that haven't — they run measurably different systems on the same subscription.

What a harness cannot do

Okay, but we get it, that sounds exaggerated, so let's hear the contrarian view: a harness can't raise the ceiling of the model — if you provide it with better context and tools, its thinking is not going to improve, only the frequency of it attempting a serious try will increase. So what it really comes down to is that a harness stops a model being wrong for uninteresting reasons — no context, no tool, no way for it to validate itself; much more low-key than "prompt engineering solves everything", and the part worth acting on.

Second thing is that harnesses degrade in one direction — as Anthropic puts it, harnesses "encode assumptions about what Claude can't do on its own, but those assumptions grow stale as Claude gets more capable". So the scaffolding around a gone limitation is now just noise in the context window; maintenance-wise, this means asking yourself not only "what to add", but also "what to stop doing" — an "add-only" harness accumulates workarounds for problems that no longer exist.

IN YOUR HARNESS

Seeing it in Claude Code

The quickest way to see what the harness is is the flag that disables it: claude --bare, which the vendor documents as minimal mode in which it doesn't run hooks, LSP, plugin sync, attribution, auto-memory, background prefetches, keychain reads, and CLAUDE.md auto-discovery. That's the harness listed by the vendor, all of these enabled by default, not part of the model, most of them never thought about.

The same flag's documentation also shows how to re-enable the components individually: --system-prompt, --add-dir, --mcp-config, --settings, --agents, --plugin-dir; it's probably as close as it gets to an exploded view.

  • What it sees: CLAUDE.md is auto-discovered up- and down-tree, and whatever tools it reads during the session. /context visualises the window as a coloured grid.

  • What it can do: built-in tools plus MCP servers (from /mcp), plus skills per-name under .claude/skills/<name>/SKILL.md.

  • What it's allowed to do: allow / ask / deny rules in .claude/settings.json, or a per-session --allowedTools option.

  • When it stops: the loop, with hooks that can interrupt it.

Gotcha: --dangerously-skip-permissions isn't a productivity feature, but removing one of the four jobs; always use scoped allow-rules first, we have a whole lesson on this later in the course.

Seeing it in Codex CLI

What's also interesting is the codex doctor command — it lists the harness's own components, rather than anything about the model: runtime, installation method, config, authentication, and what binaries it runs. On our machine it shows ripgrep 15.1.0 (system, rg) and git version 2.39.5. What's important here is that part of the harness lies on PATH, not in the config; so two engineers using the same version of Codex with different search tooling run different harnesses and nobody says anything about it — you need to ask.

  • What it sees: AGENTS.md and whatever it reads during the session. The codex debug prompt-input command emits the model-visible prompt input as JSON, so you can actually see the assembled context literally rather than mind-read it. Not many in this space do it.

  • What it can do: built-in tools, MCP servers (codex mcp), plugins (codex plugin).

  • What it's allowed to do: sandboxing and approvals configured in ~/.codex/config.toml; codex sandbox runs a command in the same sandbox as the agent — the honest way of checking what it actually can do.

  • When it stops: the loop, or codex exec for the non-interactive form.

Gotcha: the -c key=value option replaces any config value for a single run, including a dotted path (-c model="o3"); so you can run a harness that isn't documented in any file. Useful if you can't reproduce a colleague's outcome.

Seeing it in GitHub Copilot CLI

Let's start with permission flags, because this is how the Copilot CLI separates them: --allow-all is equivalent to --allow-all-tools --allow-all-paths --allow-all-urls — three independent gates over tools, filesystem and network. We say it because what people usually do when one of these is annoying is replacing it with a single flag that allows everything, but then they have far more surface area than they wanted.

  • What it sees: three separate instruction surfaces: .github/copilot-instructions.md for the repo, path-specific rules under .github/instructions/**/*.instructions.md, and AGENTS.md; the docs list all of them and say there's no precedence, good to know before you create conflicting rules in two of these. /context shows a visual token-usage report, /compact compresses history manually.

  • What it can do: built-in tools plus MCP servers from ~/.copilot/mcp-config.json (the entire directory is relocatable using COPILOT_HOME), managed through /mcp add.

  • What it's allowed to do: the three gates above, a per-tool --allow-tool option, and --add-dir to extend file access.

  • When it stops: the loop; /usage reports session statistics including GitHub AI Credits consumed.

Gotcha: three instruction surfaces means three places to look when you want to find a rule you can't locate, but the agent obeys. Have a look at path-specific files first — they silently apply invisibly only when a file with a matching path is accessed.

Seeing it in Cursor

What's interesting about the Cursor is that it's unusual in that its GUI and CLI share the same harness; so what you tune in the IDE is what you get on the command line, which is a real benefit as it means you can improve the CLI experience in the GUI. But it also means that changing one surface silently changes the other.

  • What it sees: .cursor/rules, and the CLI additionally reads AGENTS.md and CLAUDE.md at the project root and applies them as rules; if your repo contains all of these, it has all of these active.

  • What it can do: built-in tools plus whatever mcp.json sets up; the docs say it directly that the CLI inherits the editor's file.

  • What it's allowed to do: allow/deny lists and hooks in .cursor/hooks.json, which the docs describe as running before or after defined stages of the agent loop and capable of observing, blocking or modifying behaviour. Precedence is Enterprise, Team, Project, User.

  • When it stops: the loop, with 18 hook points to interrupt it at, including stop, sessionEnd and preCompact.

Gotcha: nothing tells you what rules were actually loaded; /mcp lists servers and their tools and /about shows version and account, but neither mentions rules. And rules can be scoped to particular files — which is powerful and makes "why didn't we adhere to our convention" a really complex problem to debug, so keep your always-on rule short enough to memorise.

Seeing it in Antigravity CLI

The binary is agy, and the first thing worth knowing is that the CLI and the Antigravity 2.0 desktop app run the same agent core and share settings — the docs say a permission rule changed in one immediately updates the other. So on this one the harness isn't even per-surface: you can widen what the terminal is allowed to do by clicking something in a GUI.

Its instruction layer is unusually forgiving about names. It parses both GEMINI.md and AGENTS.md from your working directory, plus a global ~/.gemini/GEMINI.md. Convenient, and the reason to check rather than assume: a repo carrying both files has both of them loaded, which is two standing instructions competing, not a fallback chain.

  • What it sees: those context files plus session history; /context opens a context-usage visualisation panel.

  • What it can do: /mcp opens the server manager, /skills lists the loaded local and global skills, /hooks shows active pre- and post-tool hooks. Skills are markdown in .agents/skills/ per repo, or ~/.gemini/antigravity-cli/skills/ globally, and each one becomes a slash command.

  • What it's allowed to do: action(target) permission rules in ~/.gemini/antigravity-cli/settings.json, an execution mode, and an OS-level terminal sandbox that is off by default.

  • When it stops: the loop; /rewind walks the conversation back, /fork branches it.

Gotcha: a very big window makes a long memory file feel cheap — it competes for your attention with the actual task, and its downside is not truncation but dilution; nothing gets cut, so you can't tell anything is wrong.

Seeing it in Kimi Code CLI

It's good to get familiar with the Kimi Code CLI as it's a bit different — as it says about itself in its README: an "agent that runs in your terminal — it can read and edit code, run shell commands, search files, fetch web pages, and choose the next step based on the feedback it receives". The last part is the loop vocalised; not many product pages say that much.

  • What it sees: AGENTS.md (the most popular thing in the industry these days), plus session history.

  • What it can do: built-in tools, MCP servers added conversationally using /mcp-config, and subagents coder, explore and plan running in separate contexts; subagents are as much a context thing as a parallelism thing — as the docs put it, they keep the main chat tidy.

  • What it's allowed to do: approvals, which is where Kimi Code really stands out.

  • When it stops: the loop.

Gotcha: no sandbox here; Claude Code, Codex, Cursor and Antigravity CLI all ship one, which is the layer that catches approvals set too loosely. Without it the gate layer is thinner so the approval settings carry the load instead of being the first line of defence. Good to remember before any unattended run — we have a dedicated lesson in the Kimi Code supplement.

The habit to take away

In summary, after a bad session our first question is no longer "which model was selected". We ask "what occupied the context window" instead, and this is important because it channels the energy into the half you can control. The opposite is channelling it into waiting for a release.

j / k to move between lessons