All postsHelmo Solutions
Notes
July 6, 20268 min read

The ten primitives of AI agent harness engineering

A walkthrough of the layers around the model, from instructions to verification, that turn a chatty LLM into something like Claude Code or Codex.

When an agent like Claude Code or Codex does something impressive, it's tempting to credit the model. The model matters, of course, that's why the benchmark wars exist. But once you start building real agent workflows, the model is only one part of the machine. Everything else, what the model sees, what it can act on, what it remembers, what work gets delegated, how it verifies, how it recovers, lives in the harness. This article walks through the ten primitives that make up that harness, following the framing from The Carbon Layer's Harness Engineering Masterclass. None of these are formally standardised yet, but together they explain why "the model just did that" is almost never the right answer.

Instructions

The first primitive is the one you already write by hand: instructions. You tell the model who it is, what work it's doing, the tone, the constraints, the coding style, the rules of the review, the things it should never do. agents.md, Claude.md, system prompts, custom instructions, cursor rules, same family. Their power is that they move repeated guidance out of the chat window and into the environment, so you don't paste the same rules into every session. But instructions are passive. They can say "follow the project convention" but they cannot discover the convention. They can say "be careful with migrations" but they cannot inspect a migration. They shape behaviour; they don't hand the model the world.

Context delivery

The next primitive is context delivery, the mechanism that hands the model the material it needs to actually work. The @-mention that pulls a file into the prompt, the failing test attached to a bug report, the stack trace, the doc, the log. This is where the difference between a bare model and an agent inside a harness becomes obvious. Ask a bare model to fix a bug with no files and you get a generic fix; give it the source file plus the failing test and you get something that might actually land. But dumping content in is not the same as delivering context, which leads directly to the next layer.

Context management

Context management is the harness deciding, at every turn, what the model should be looking at right now. Repositories are too large, chat transcripts get too long, production incident logs are enormous. Pour all of it into the window and you don't get a smarter agent, you get a noisier prompt, and often a worse answer, because wrong context is more damaging than missing context. This is where RAG, reranking, summarisation, prompt caches, session summaries, and compaction all live. The names change; the job doesn't: protect the model's attention. The question stops being "can we provide context?" and becomes "who decides what context matters right now?", and most of that decision belongs to the harness, not the human.

Tool interface

Context management makes the agent smarter inside the conversation, but the agent is still mostly a talker. It can name the file, propose the command, describe the next step. At some point something has to actually happen, and that's the tool interface. Tools give the model a structured way to act, a name, a description, an input schema, sometimes an output schema, and the model chooses which one to call with which arguments. Function calling, tool use, MCP, bash, grep, find, all the same primitive at different altitudes. MCP in particular is interesting because it abstracts how tools are exposed, so any service provider can plug their capabilities into any model. The tool interface is what turns a describer into an actor.

Execution environment

Once the model can call tools, a new question appears: where does the call actually run? On your laptop? In a container? In a cloud sandbox with network access? With which secrets, and against which files? Tools fail, return messy text, sometimes return prompt injection embedded in a web page, and the harness has to decide how much of that to trust. The execution environment is the layer that answers those operational questions: file system scope, network policy, credentials, sandboxes, dev containers, work trees, browser profiles. Companies like Daytona, E2B, and Docker's dev sandbox exist because this primitive is doing real work. It's also where trust becomes practical: instead of instructing the model "please don't touch secrets", the harness makes secrets unreachable.

Durable state

An isolated sandbox is enough for one clean task, but real work pauses, resumes, forks, fails, and retries. If the only record of what happened lives in the model's context window, a crash loses everything. Durable state is the workbench that survives the current turn: plan files, checkpoints, task state, session summaries, diffs, logs, memory stores. For a coding agent it might be a branch, a test log, a plan document; for a research agent it might be a source map or an extracted quote table. The storage format doesn't matter. What matters is that progress becomes inspectable outside the model's attention, so the next step starts from where the last one left off rather than from scratch.

Orchestration

Durable state preserves work but doesn't move it forward. A plan file describes what should happen but doesn't decide when to retry, when to ask for approval, or when to hand off to a human. That coordination is orchestration: lifecycle hooks, heartbeats, retries, approval gates, human hand-offs, tool wrappers, step ordering, task routing. Claude Code's hooks are a good example: agent frameworks expose lifecycle events precisely because real systems need places to intercept behaviour. The model isn't running a workflow by willpower; the harness is carrying the workflow, and orchestration is what makes the whole thing look less like a chat and more like a runtime.

Sub-agents

One agent doing everything serially runs into two problems: it's slow, and its attention gets crowded by unrelated work. When work naturally branches, one thread to explore the codebase, another to review the diff, another to verify sources, another to draft the plan, the harness needs to branch too. That's the sub-agent primitive. OpenAI's Agent SDK captures two useful patterns: agents as tools, where a manager calls specialists and integrates their output, and hand-offs, where the active conversation moves to a specialist. A sub-agent isn't just more model; it's a model with a narrower job, narrower context, and often narrower tools. The whole point is reducing the surface area each worker has to reason about.

Skills and procedures

Delegation creates its own problem: if every sub-agent invents its own process, you get parallel inconsistency, everyone comes back with a different interpretation of the job. Agents need reusable procedures that can be loaded at the right moment. That's the skills layer: named, structured playbooks encoding when to use them, what inputs they take, what steps they follow, and which tools they prefer. Slash commands, runbooks, recipes, workflows, same primitive. A well-written skill for reviewing a PR, prepping an episode, or running browser checks moves repeated expertise out of "remember to do this" instruction and into a named capability the harness can invoke on demand. It's part of why the moment skills became a first-class concept felt pivotal.

Verification and observability

Skills make work repeatable but don't prove it succeeded. A skill can say "run the tests", it doesn't confirm they passed. A skill can say "check the browser", it doesn't confirm the screenshot was clean. Verification is the harness asking for receipts: tests, builds, type checks, lints, screenshots, evals. The mindset shift is that you don't trust the final sentence because it sounds confident; you ask what external checks back it up. Observability is the other half, the recorder for the run. Traces, tool-call timelines, prompt versions, tool versions, approval events, cost, latency, the full chain from intent to output. Bugs are rarely in the final message; they're three tool calls earlier when the agent searched for the wrong symbol or trusted the wrong page. Verification tells you whether the run passed. Observability tells you why it didn't, and turns a failure from "the agent messed up" into a debuggable system you can actually improve.

Conclusion

Put these ten primitives side by side and the architecture diagrams for Claude Code, Codex, and the Gemini CLI stop looking arbitrary. Each layer is there because something upstream leaves a gap: instructions can't discover files, context delivery can't decide relevance, tools can't decide where to run, environments can't remember, state can't coordinate, orchestration can't branch, sub-agents can't share procedures, procedures can't prove success, and verification can't explain failure. The practical test the video ends on is worth stealing: when an agent fails, stop asking "was the model good enough?" and ask which harness layer ran out of road. Was the instruction missing? Was the context wrong? Did the tool schema mislead? Did the command run in the wrong environment? Was there no verification, no trace, no memory of last time's fix? That's the shift, from clever agents to dependable systems. The model still matters. But reliability gets built in the system around it.


Notes taken from "Harness Engineering Masterclass: Technical Deep Dive on how to build Agentic Systems" by The Carbon Layer.