# Harness vs framework: the open-source harness is the one you write

> A framework gives you the loop, the tools and the state an agent keeps. A harness decides what that agent reads, what it may call, and where its work is allowed to land. Kortix is the open-source AI Operating System, and in it the harness is a set of files a team reviews.

URL: https://harnessengineeringguide.com/harness-vs-framework

## Two things now answer to the word harness

LangChain draws the line most clearly, because it sells all three layers. "Agent frameworks provide abstractions that make it easier to get started when building with LLMs." "Agent runtimes provide the tooling for running agents in production." "Agent harnesses are opinionated, batteries-included frameworks with built-in tools and capabilities for building sophisticated, long-running agents." ([LangChain](https://docs.langchain.com/oss/python/concepts/products))

LangChain's third line shows the word moving. A harness used to name the environment around a model, and it now also names a product a vendor installs for you. Microsoft's Agent Framework ships one as a class inside the framework: "Agent Framework provides an opinionated, batteries-included Harness for research, coding, data analysis, and other long-running work." ([Microsoft Learn](https://learn.microsoft.com/en-us/agent-framework/concepts/harness)) Mastra's first command creates "a general-purpose agent harness" and fills it with a workspace, shell tools, memory and recurring schedules ([Mastra](https://mastra.ai/docs)). Both vendors are selling batteries.

What is the agent harness framework, then? There is no single product by that name. The phrase means a batteries-included framework whose built-in loop acts as the harness, and LangChain files its Deep Agents SDK in that class beside the Claude Agent SDK and Manus.

The other sense of the word comes from practice, and it covers the part a vendor cannot ship. Martin Fowler names the part a team builds around a vendor's agent the outer harness, and keeps it separate from whatever the coding agent ships built in. Inside that outer harness he splits the controls by direction: guides anticipate an agent's behavior and steer it before it acts, and sensors observe what it produced and help it correct ([Fowler, 2 April 2026](https://martinfowler.com/articles/harness-engineering.html)). A team that writes both for its own repository ends up owning the outer harness, and that ownership is what separates the two meanings of the word.

## Three layers, three jobs

A framework answers a build question: which abstractions do I write this agent with? A runtime answers an operations question: what keeps a long-running agent alive across failures? A harness answers a governance question: what does this agent read, what may it call, and what stops a wrong result from landing?

The build and operations questions have commercial answers, and paying for them is usually right. The governance question has an answer made of your own material: your tests, your permission boundary, and the place a change is allowed to land. So the harness that decides whether a failure repeats is rarely the one that arrived with the framework. It is the one your team writes in its own repository, where a reviewer can watch it change.

What is the difference between an agent harness and an agent? The agent is the unit that does the work: a model with instructions, tools and a task. The harness is everything around it, from the permissions on its tools and what it can reach to the checks on what it produces and where its work is allowed to land.

## What each project decides

Each first cell uses the project's own words; the other two say what it settles and what stays with your team. The last two rows record runs rather than permit them.

| | What it is, in its own words | What it decides | What it leaves to you |
| --- | --- | --- | --- |
| Kortix | The open-source AI Operating System | Which files an agent reads, what it may call, where work lands | The rules themselves, and who reviews each change |
| LangGraph | a low-level orchestration framework and runtime | Durable execution, persistence, streaming and human-in-the-loop for stateful graphs | Prompts and architecture; it does not abstract either |
| CrewAI | the leading open-source framework for orchestrating autonomous AI agents | How a crew of agents collaborates, and how flows order steps | The tools and the review a finished task must pass |
| Mastra | a TypeScript framework for building AI agents and applications | The agent loop, workflows, memory and a local dev studio | Where it runs, and the checks that guard output |
| OpenAI Agents SDK | agentic AI apps in a lightweight, easy-to-use package | Handoffs, guardrails and tracing inside a small primitives set | Production operations, and every rule your team enforces |
| AutoGen | A framework for building AI agents and applications | Event-driven message passing between agents in one system | The conventions each agent follows, and the gate before merge |
| LangSmith | the record of what your agents did in production | Which runs get traced, scored and compared over time | What an agent may do; tracing records, it does not permit |
| Langfuse | an open-source AI engineering platform | Which traces, prompt versions and scores a team reviews | Permissions and gates; it observes, it does not block |

## The line the framework cannot cross

A framework's control flow lives in your application code. LangGraph says it outright: "LangGraph does not abstract prompts or architecture" ([LangGraph](https://docs.langchain.com/oss/python/langgraph/overview)). You define the nodes, you call the graph, and the loop runs inside the service you deployed. That is the right shape for the job, and it is why one graph can serve a support agent and a billing agent without knowing anything about either.

The harness sits outside that code. It is the instructions an agent starts with, the skills it can load, the tools it is granted, the permission on each grant, and the check that decides whether its output counts. All of those describe your repository, and none of them fits inside a graph definition.

The failure this produces is quiet, because the framework keeps working. An agent adds a React component that imports the database client directly, and review sends it back to the server module that owns those queries. The framework routed the call, the tools ran, the tests passed. Two weeks later a different session makes the same import in another view, and a third one opens a change request with it.

Nothing in the framework failed. A rule such as "UI code never imports the database client" describes your repository, and it can live in only three places: a file the agent reads, a check that fails when the import appears, or a permission that stops the call. Fowler reaches the same conclusion from the other end of the loop: "Whenever an issue happens multiple times, the feedforward and feedback controls should be improved to make the issue less probable to occur in the future, or even prevent it." The repair belongs in the guides and sensors that outlive the prompt of the day.

## The right time to buy a framework

Buy the framework when the loop is the expensive part. Durable execution, streaming, retries and state across sessions take months to build, and no team should write them twice. The second column of the table says what each project settles, and the third says what it leaves to you. That third column is the one that matters. If the answer reads like "the rules my team enforces", the framework is doing its job and the missing layer is somewhere else. Three signals say the missing layer is the harness:

- The same review comment lands on two change requests from different sessions.
- A rule exists in a prompt, and nobody can point to the file every agent reads where it is stated.
- An agent reaches a tool it should never have had, and the fix was a message rather than a grant.

## Write three files first

Start with the failure that just happened, and write three small things rather than a framework of your own. A guide states the rule in the file every agent reads before it starts work. One sentence a reviewer can check against a diff is enough, and a short file gets read.

A sensor fails when the rule breaks, and its message carries the correction. A linter error that says which module to import from ends the retry in one attempt, while a stack trace starts a conversation.

A permission moves the boundary out of prose. A prompt that asks an agent to stay away from production is a request; a grant that omits the tool is a refusal the runtime enforces.

## The harness is a project in a git repo

In Kortix, the harness is the project itself. "Your agents, the skills they share, your company memory and every connector live in one git repo you own." ([Kortix on GitHub](https://github.com/kortix-ai/suna)) A change to what an agent may call is an edit to that project, so it reaches the next session as a diff a reviewer has already read.

One isolated sandbox per session. Each session has its own isolated machine and branch. A rule written after a failed task therefore arrives as a branch and a diff, and the next session inherits the version that survived review.

Session work reaches `main` through a change request. Merge is default-deny for agents. The gate that refuses a bad change is the same gate that refuses a bad rule, so a permission change is argued over in review instead of discovered in an incident.

## What an agent may call is declared

`kortix.yaml`

```
# Each block is one agent. Behavior: description, mode (primary | subagent |
# all), model, prompt or prompt_file, and permission (per tool: allow | ask |
# deny; omitted = allow, so a tool never waits for an answer the agent did not
# ask for). Grants are deny-by-default: an omitted skills, subagents,
# commands, extensions, connectors, secrets or kortix_permissions grant is
# none. Write `all`, `none`, or a list of names.
```

Source: https://github.com/kortix-ai/suna/blob/dev/packages/starter/templates/base/kortix.yaml

Each tool’s permission is declared in the block as allow, ask or deny, and the grants for skills, connectors, secrets and `kortix_permissions` are stricter: omit one and it resolves to none, so the call is refused. The edit reaches the next session through the change request a person reviews.

## The two layers behind the words

### What is the difference between a harness and a framework?

A framework supplies the loop, the tools and the state an agent is built from. A harness is the environment around a running agent: what it reads, what it may call, and what happens when it errs. The harness that prevents a repeat is one a team writes and versions.

### Is the Microsoft agent framework a harness?

Yes, as a product inside it. "Agent Framework provides an opinionated, batteries-included Harness for research, coding, data analysis, and other long-running work." Microsoft ships that harness as a class in the framework, and its defaults are still Microsoft's.

## Keep the harness in the repo your team reviews

Every rule you add after a failure arrives as a diff a reviewer reads before the next session starts. The gate that refuses a bad change refuses a bad rule the same way.

[Try Kortix](https://kortix.com) · [Read the source](https://github.com/kortix-ai/suna)
