Skip to content
Go back

What Is an AI Harness?

By SumGuy 20 min read
What Is an AI Harness?
Contents

Your Chat Box Is Already a Harness. It Just Has One Tool.

Credit where it’s due: this article exists because a reader named Pedja asked for it. The question, left in the comments on an unrelated post, was what an “AI harness” actually is and where it fits, having noticed that everyone writes about building them and nobody stops to explain what they’re for. Correct on both counts, and thanks for the nudge. Everyone is too busy shipping their own to define the thing.

A language model turns text into text. That’s it. It cannot open a file, run a command, remember what you asked it yesterday, or check whether the code it just wrote actually compiles. Every single one of those things, in every AI tool you’ve ever used, was done by a program wrapped around the model. That program decides what the model gets to see, runs whatever the model asks for, and decides what happens next. DeepSeek’s own documentation for its open-sourced harness states this as flatly as it can be stated: Agent = Model + Harness. The model is the reasoning. The harness is everything that turns reasoning into action.

You’ve already used one. If your LLM experience is mostly a DeepSeek chat window, you have been running a harness this whole time. It has exactly one tool, and that tool is you. You paste in a question, the model answers, you copy its suggested command into a terminal, you run it, you copy the error back in. That’s a full loop: prompt in, model reasons, action taken, result fed back. The only difference between that and Claude Code editing a repo unattended is who executes step three. A real agent harness just closes that loop without a human standing in the middle passing messages back and forth.

The harness is the part of the system doing everything a model can’t do, and almost every AI power user has spent months tuning which model to use and zero minutes thinking about the program wrapped around it. That second choice matters at least as much.

The Loop, Drawn Out

Strip away the branding and every agent harness runs the same five-step loop.

  1. The harness builds a prompt: system instructions, the running conversation, whatever file contents or search results it decided were relevant, and a list of tools the model is allowed to request.
  2. The harness sends that prompt to the model.
  3. The model returns either plain text, or a structured request to call one of the tools it was offered, naming the tool and supplying arguments.
  4. The harness reads that request, checks it’s a real tool with valid arguments, and actually runs it: executes the shell command, edits the file, hits the API.
  5. The harness takes the result and appends it back into the conversation, then goes back to step one, until something tells it to stop.

Here’s that loop with the framework sanded off:

agent_loop.py
def run_agent(task, model, tools, max_steps=20):
messages = [{"role": "user", "content": task}]
for step in range(max_steps):
response = model.complete(messages, tool_schemas=tools.schemas())
if response.is_text:
return response.text # model thinks it's done
call = response.tool_call
tool = tools.get(call.name)
if tool is None:
result = f"error: no such tool '{call.name}'"
else:
result = tool.run(**call.arguments)
messages.append({"role": "assistant", "tool_call": call})
messages.append({"role": "tool", "name": call.name, "content": result})
return "hit max_steps without finishing"

Twenty lines, and it’s most of what a coding agent is. Everything else in a real harness (permission checks, retries, cost tracking, a nicer terminal UI) sits around this loop, not inside it.

Worth sitting with if you already run one of these tools: the model never runs anything. A tool schema is a name, a description the model reads to decide when to reach for it, and a parameters spec (usually JSON Schema) saying what the arguments look like. The harness hands the model a list of these:

tool_schema.json
{
"name": "run_shell",
"description": "Run a shell command in the project directory and return its output.",
"parameters": {
"type": "object",
"properties": {
"command": { "type": "string", "description": "The command to run" }
},
"required": ["command"]
}
}

And all the model ever sends back is a request to use one:

model_response.json
{ "name": "run_shell", "arguments": { "command": "pytest -x" } }

That is text. The model can execute it about as much as a letter can mail itself. Something else has to read that JSON, decide whether to allow it, and spawn the process. If the model hallucinates a tool that doesn’t exist, or fills an argument the schema forbids, the harness is the only thing standing between that garbage and your filesystem. A well-built harness rejects it and feeds the error back as a normal tool result, giving the model a chance to correct itself. A badly built one crashes, or worse, runs it anyway.

What the Harness Actually Owns

This answers the question directly: what is a harness for? The full list of jobs the model contributes none of.

Context assembly. Before the model ever sees a token, something decided what goes in the window: which files, how much of your prior conversation, which search results. Claude Code decides this by walking your repo and reading files on demand; a naive harness might just dump every file in the directory and blow the budget in one shot. Same model, wildly different quality, purely because of what got fed in.

Tool definitions and permission scope. The harness decides the model’s entire universe of possible actions. A harness that only exposes read_file and search_web cannot delete your database no matter how it’s prompted, because the capability doesn’t exist. A harness that exposes an unrestricted shell can. This is a design decision made once, in code, not a prompt you can talk the model out of.

Executing the call and formatting the result. Running git diff and handing the model 4,000 lines of raw output is a choice. Truncating it, summarizing it, or pre-filtering to the relevant hunk is a different choice, made by the harness, before the model ever reasons about it.

Stop conditions and loop limits. Something has to decide when the agent is “done,” and something has to cap how many loop iterations it gets before the harness gives up and hands control back to you. Without a cap, a confused model in a bad loop will happily burn your token budget until the API key runs dry.

Retries and error recovery. A tool call that fails on a transient network blip shouldn’t kill the whole run. The harness decides what counts as retryable, how many attempts to make, and what backoff to use, outside the model’s awareness entirely.

Cost and token budget. Every tool result that goes back into the conversation grows the next prompt. A harness that never prunes old context will eventually be sending a five-figure token prompt to answer a one-line follow-up. Tracking spend and trimming context is harness plumbing; the model has no part in it.

Session state and resumability. Can you close your laptop mid-task and pick the exact same run back up tomorrow? That depends entirely on whether the harness persisted the conversation, the tool results, and where it left off. The model has no memory of any of it; it re-reads whatever the harness hands it next time.

Model routing. Some harnesses route a “which file should I open next” decision to a cheap small model and save the expensive one for the actual code generation. That routing logic lives in the harness. The model doesn’t know it’s being routed at all.

Every one of those is a design decision, made in code, before the model gets involved. Change the harness and you change the outcome, even if the model underneath never changes.

Why DeepSeek Chat Feels Different

If your DeepSeek experience is the chat window, none of the above has been happening, and that’s not a knock on the model. A chat UI is a harness with exactly one tool (you) and one permission scope (whatever you’re willing to paste back in). No file access, because it never opens a file. No persistence beyond the current conversation. No shell, no retries, no loop limit past the length of your patience.

That reads like a downgrade until you notice what it buys you. Nothing runs on your machine unless you run it yourself, so you’re the review gate for every command before it touches your system. Hand that same model a harness with a shell tool and no supervision, and you’ve traded that gate for speed. Both are legitimate, and which one you want depends on the task, not on which model is answering.

The Landscape, Grouped by Job

Group these by the job they’re doing, because that’s what decides whether one fits you. Names first, opinions after.

Terminal coding agents run in your shell against your working repo. This is the busiest category by far.

HarnessOpen sourceGood for
Claude CodeNoRepo-scale work, strong context handling
Codex CLIYesThe tightest sandboxing here, enforced by the OS
GitHub Copilot CLINoAnyone already paying for Copilot
Gemini CLIYesGoogle’s models, with a real free daily allowance
AiderYesGit-native editing, a commit per change
ClineYesApproval-gated edits with a visible diff
OpenCodeYesStaying provider-agnostic
Kilo CodeYes500+ models with no inference markup
GooseYesLocal-first work against Ollama

Codex CLI is OpenAI’s, written in Rust and Apache-2.0 licensed, and its sandboxing is the real differentiator: Apple Seatbelt on macOS, Landlock and seccomp on Linux, so the isolation is enforced by the kernel rather than by the agent promising to behave. GitHub Copilot CLI comes with every Copilot plan and carries a Plan mode that works out an implementation plan with you before any code gets written, plus an autopilot mode that runs multi-step work without stopping for approval at each step. Gemini CLI is Apache-2.0 and still the most generous free tier in this table, at 60 requests a minute and 1,000 a day on a personal Google account, as of August 2026. Goose started at Block and now lives under the Agentic AI Foundation at the Linux Foundation. It’s Apache-2.0, ships as both a desktop app and a CLI, works with 15+ providers including Ollama, and keeps everything on your machine when you point it at a local one, which makes it the obvious first stop for the local-model crowd.

Editor agents live inside your IDE instead, with inline diffs and a chat panel beside the code rather than a terminal pane to babysit.

HarnessOpen sourceGood for
CursorNoAn editor built around the agent from the start
GitHub Copilot agent modeNoAdding agent behaviour to an editor you already use
ContinueYesPointing an IDE agent at a local or self-hosted model
ClineYesWatching every edit before it lands
Kilo CodeYesSpanning VS Code, JetBrains, CLI and cloud at once

Kilo Code is worth a second look because it refuses to pick a lane. It’s MIT licensed, now owned by Anaconda, and traces its lineage back through the Cline fork chain. The same agent runs in VS Code, the JetBrains line, a CLI, cloud runners and Slack, with bring-your-own keys and local model support. Its pitch is a harness-quality argument rather than a model one: audit the prompt, the context window and the decisions in the source, and no silent model switching behind your back.

Autonomous and research harnesses aim at finishing a whole ticket rather than assisting you through one.

HarnessOpen sourceGood for
OpenHandsYes (MIT)Sandboxed end-to-end work that opens a PR
SWE-agentYes (MIT)Studying how harness design changes model scores

SWE-agent came out of Princeton and matters here more than its user count suggests. It introduced the Agent-Computer Interface, the argument that the way you present a codebase to a model is a design problem in its own right, separate from the model’s ability. That idea is the reason this article exists. OpenHands (formerly OpenDevin) is the applied version: it writes code, runs tests, fixes what broke and opens a pull request inside a Docker sandbox, and it posts competitive SWE-bench Verified numbers with open-weight models behind it.

Build-your-own frameworks hand you the loop, the tool-calling plumbing and the plugin system, then expect you to assemble the agent yourself: LangGraph, CrewAI, AutoGen, and DeepSeek’s own open-sourced DeepSeek Harness, with smolagents and Pydantic AI sitting at the lighter end. This is the right layer for shipping a custom product on top of an agent loop, not just editing code with one.

Self-hosted chat harnesses put an agent loop behind a familiar chat UI you run yourself. Open WebUI, with its tools, functions and pipelines system, is the obvious example, letting you bolt web search, code execution or a RAG pipeline onto a chat interface without adopting a whole coding-agent workflow.

Who Owns Your Harness Next Year?

Every tool in those tables is younger than most of the code you maintain, and the ownership churn shows it. Goose started inside Block and now sits under the Agentic AI Foundation at the Linux Foundation, with the repo and the docs both at new addresses. Kilo Code exists because Cline got forked into Roo Code and forked again, and it belongs to Anaconda today. OpenHands used to be called OpenDevin and has changed GitHub orgs since. None of that is a scandal. It is what a category this young looks like from the inside.

It matters because of which half of the system you can actually replace. Swapping the model inside a harness is a config change you make on a Tuesday. Swapping the harness means relearning a workflow, rewriting your rules files, and rebuilding whatever automation you hung off it. Free tiers are a vendor allowance on the same footing: Gemini CLI’s thousand requests a day is generous right now, and generous right now is not a contract.

So weight the two properties that keep the decision yours. Open source means a rename or an acquisition cannot take away the version you already run. Model portability means the harness survives the day your preferred model gets deprecated or repriced. A harness with both can change hands without changing your week.

DeepSeek Harness deserves a closer look since it just showed up and its design is unusual. It’s MIT licensed, written in Node.js, still labeled a developer preview, and you can try it with no clone and no build:

Terminal window
npx @deepseek-ai/dsh web

It’s built on a plugin kernel called Cordis, and DeepSeek’s own framing is “everything is a plugin,” meant literally: models, tools, skills, sessions, storage, scheduling, the UI, and even the agent loop itself all ship as plugins. That last one is the detail worth remembering next time someone tells you an agent loop has to be hardcoded.

It ships four runtime modes, and the spread between them is a decent map of what a harness can even be:

Reported adoption after the August 2026 release was fast, something like 95,000 GitHub stars within about two days by widely repeated counts, though treat that as a reported figure rather than something confirmed here.

Picking One, Including the Local Model Case

If you’re editing real code in a real repo, start with a terminal or IDE agent, because reinventing that plumbing yourself is a bad use of a weekend. If you’re shipping a product with an agent inside it, reach for a framework instead, because a finished coding agent won’t fit whatever weird domain you’re actually building for.

The local-model case deserves its own paragraph, because this is where people most often blame the model for what’s actually the harness’s fault. A small local model, something you’re running through Ollama or llama.cpp on a home GPU, has a real context window and real reasoning limits. Point a maximal harness at it, one that dumps your whole repo tree, your last fifty tool results, and six paragraphs of system prompt into every turn, and you will watch that model lose the thread by turn four. Not because it’s a bad model. Because it’s drowning in context a bigger model would’ve shrugged off.

This is exactly why DeepSeek Harness ships a Minimal mode with only two tools, and it’s worth calling out because it’s counterintuitive: a smaller harness on the same model often outperforms a bigger one. An earlier post on this site covering DeepSeek’s V4 Flash pricing already ran into this sideways: DeepSeek benchmarked that model using the exact same minimal mode, months before the harness was even public. Same model, a stripped-down harness, different score. If a vendor needs a bare-bones mode to get an honest read on its own model, that’s your signal too. Running something small locally, reach for the fewest tools and the tightest context budget you can get away with, not the one with the most checkboxes.

For an actual starting point rather than a principle: Goose is built for this, talks to Ollama and Docker Model Runner directly, and keeps everything on your machine. Continue does the same job inside an editor. Both let you cap the tools on offer, which is the setting that matters most when the model on the other end has 12B parameters and a modest context window.

How to Tell a Good Harness from a Bad One

This is the checklist that pays off once the rest of this article has sunk in.

Context discipline. Does it cap what goes into the window, or does it just keep appending until something breaks? Ask what happens on turn fifty of a long session; a harness with no answer to that question will eventually choke.

Permission scoping. Can you take the shell away and leave it with read-only tools? Kilo Code advertises this directly: no silent model switching, and an auditable prompt, context window, and decision trail in its MIT-licensed source. That’s the right bar. If you can’t see or restrict what a harness is allowed to do, you don’t control it.

Model portability. Can you point it at a local model, a different provider, or does it hardcode one vendor’s API? A harness married to a single model can’t be the thing you tune independently of the model, which defeats half the point of understanding this split in the first place.

Observability. Can you see the literal prompt that went to the model and the literal tool calls it made, or only a cleaned-up summary? DeepSeek Harness keeps an append-only session log of every system prompt, every reasoning step, every tool call and result, viewable through a Trajectory pane, and lets you resume, fork, search, or replay a session off that same event log. That’s the standard other harnesses should be measured against, and most chat UIs give you nothing close to it.

Resumability. Close the laptop mid-task. Does it pick back up where it left off, or start cold?

Cost visibility. Does it show token spend per step, or only a surprise total at the end?

A harness honest about all six is one you can reason about. One that hides any of them is one you’re trusting blind.

The Half Nobody Tunes

People will spend a full weekend comparing benchmark scores between two frontier models and never once ask what’s feeding those models their context, or what’s allowed to run once they answer. That’s backwards, or at least it’s leaving half the available improvement on the table. The model is largely fixed once you pick it; a vendor ships what they ship, and your prompt engineering only moves the needle so far. The harness is the half you can actually rebuild, restrict, swap out, or write yourself, and it changes what an agent can do at least as much as which model sits inside it. Pick your model. Then go pick your harness like you mean it.

Common Questions

Is an AI harness the same thing as an agent framework?

Mostly yes, with a framing difference. “Harness” emphasizes the runtime loop wrapped around one model instance: the tools, the context assembly, the stop conditions. “Agent framework” (LangGraph, CrewAI) usually adds multi-agent orchestration on top, coordinating several model calls or roles. Every agent framework contains a harness; not every harness bothers with multi-agent coordination.

Do I need an AI harness to use a local LLM?

Only if you want it to do more than answer in a chat window. A local model through Ollama or llama.cpp with no harness works exactly like DeepSeek chat: you read, you act, you paste results back. Add a minimal harness (two or three tools, tight context) to get automatic file edits or command execution without the copy-paste loop.

Does a harness make a small model smarter?

No, but it can make a small model perform closer to its real ceiling. A cramped, over-stuffed harness wastes a small model’s limited context on noise, causing it to lose the thread. A minimal harness with a tight token budget lets that same model actually use the reasoning it has, which is why DeepSeek’s own Minimal mode exists for benchmarking.

Is MCP a harness?

No. MCP (Model Context Protocol) is a standard for exposing tools and data sources to a model in a consistent format. A harness still has to run the loop, decide what MCP servers to connect, and enforce permissions around them. MCP is a wire format for tools; the harness is the program deciding when to call them.

Can I write my own AI harness?

Yes, and the loop itself is small: assemble a prompt, call the model, parse a tool request, execute it, append the result, repeat. A working version is under 50 lines in most languages. The loop is the easy half. What turns a toy script into something safe to leave unattended is the surrounding discipline: permission scoping, context limits, retries.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
MariaDB vs MySQL in 2026
Next Post
SQLite for Self-Hosted Apps

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts