Agent Harness, Loop, and Graph Engineering: What's the Difference?

Harness, loop, and graph engineering solve distinct problems in agent design. Mixing them up leads to costly mistakes in production systems.

Agent Harness, Loop, and Graph Engineering: What's the Difference?

One of your colleagues asserts that “we require improved loop engineering,” yet the fundamental issue lies within the harness itself. Others may create graphs with 40 nodes before they observe how the agent executes a given task at a single time. Does this sound like something you have encountered before?

This ongoing confusion surrounding agent harness engineering, loop engineering, and graph engineering is becoming quite common. All three work with the same model and involve some type of recurring activity. However, they address distinct problems and mixing them can become costly as soon as an agent works with real APIs or files.

Table of Contents

What Do These Three Terms Actually Mean?

Here’s how I would explain it in under a minute:

  • Harness engineering refers to the process of creating an environment where the model will function.
  • Loop engineering is responsible for the process design concerning the activities and feedback cycle.
  • Graph engineering is aimed at making the configuration of the process explicit in terms of nodes, branches, merges, and controlled loops.

So, the sequence to follow when something breaks down in production is: environment → feedback → flow.

An unprocessed model is incapable of writing onto a file system. It does not have the capability of retaining state from previous sessions, nor can it resume after a failure. All of this is dependent on what is built around it. This is the reason why the stack is evolving into distinct layers, and why the discussion exploded on Twitter in July 2026. Peter Steinberger posed a question that reverberated widely:

Social media post about AI loops and graphs

Agent Harness Engineering: The Foundation Layer

The agent is defined in the simplest way as a model combined with a harness. A harness is everything that exists outside the model — code, configuration, and execution logic.

To test the concept, remove the model from the architecture diagram. What remains is the harness. The harness includes tools, storage, middleware, information retrieval, logging, and retry processes.

Comparison of foundation models and agent harnesses

The same foundational model is given to two teams. Team one receives clean tools, a stable working environment, and observable data. Team two receives poor instructions and an unstable API wrapper.

A typical harness generally contains:

  • Contextual information: guidance, gathered data, dialogue history, approaches to the task
  • Execution mechanisms: APIs, web browsers, command line interfaces, code execution environments, and more
  • Storage and retrieval: files, execution state, sessions, git history
  • Control over execution: time-to-live limits, retries, spending limits, model routing, approval gates

Use harness engineering whenever an agent is unable to complete a task or cannot pick up from where it left off — and when the agent’s information is inconsistent or lost between sessions. Anthropic recognized this with its long-running coding agent: simply compacting the context is not sufficient for keeping the agent on track. The successful implementation requires a full-system solution with an initializer, progress files, or git history so that a new context can pick up exactly where it left off.

Loop Engineering: Designing the Feedback Cycle

Every agent that uses tools already has a loop of sorts built in — make a call, perform an action, submit the result back, and repeat. The term “loop engineering” comes into play when you add additional cycles intentionally and on an ongoing basis.

As Boris Cherny, head of Claude Code at Anthropic, said in a June 2026 interview: “I don’t prompt Claude anymore, I activate loops that prompt Claude. All I do is create loops.” Products like Claude Code and OpenAI are now releasing commands such as /goal and /loop, making this philosophy explicit. Here is a barebones loop verifier:

def run_loop(agent, task, max_attempts=5):
    for attempt in range(max_attempts):
        output = agent.act(task)
        passed, feedback = verify(output, task.spec)
        if passed:
            return output
        task.context.append(feedback)  # specific, not vague
    return escalate_to_human(task, output)


def verify(output, spec):
    # deterministic check beats "does this look right?"
    if spec.type == "code":
        return run_tests(output), "tests failed: see diff"
    return validate_schema(output, spec.schema)

Note what is absent: no “continue refining until it seems right.” The process concludes with proof that tests are passed — verified deterministically, not based on the model’s own certainty. This is where the distinction lies.

Loops can be classified into four important kinds:

  • Turn-based: a cycle acts on every user command
  • Goal-based: a loop continues until achieving a satisfying end
  • Time-based: a cycle performs an action on a schedule
  • Proactive: the system executes an action without user intervention

Four types of agentic loops with triggers and actions

A bug-fixing system is goal-based. A system that outputs daily updates relies on a schedule. Grouping all loop types together leads to incorrect conclusions about how and when to apply them.

Graph Engineering: Making the Control Flow Explicit

Graph engineering asks a different question. It’s not “what is the agent doing?” but rather “what is permitted to continue onward?”

A loop can be characterized as a graph comprising exactly one node that cycles back onto itself. Rather than discarding loops, graph engineering incorporates them — each node of the graph executes its own loop (Discover, Plan, Execute, Verify) at the level of that node. Graph engineering does not replace loop engineering; it incorporates loops into the graph and adds routing on top.

The following is an example of a minimal graph following the LangGraph paradigm, used in a research-brief workflow:

from langgraph.graph import StateGraph, END

graph = StateGraph(BriefState)
graph.add_node("researcher", fan_out_sources)   # runs in parallel
graph.add_node("writer", draft_from_notes)      # sees clean notes only
graph.add_node("reviewer", check_accuracy)      # fresh context, no bias

graph.add_edge("researcher", "writer")
graph.add_conditional_edges(
    "writer", lambda s: "reviewer",
)

graph.add_conditional_edges(
    "reviewer",
    lambda s: END if s.approved else "writer",  # loop back on failure
)

The reviewer node operates under a fresh context. It can view the completed brief and the accuracy measure, but not the intermediate processing that produced it — giving the reviewer unbiased perspective rather than the tunnel vision of the original drafter.

Comparison of sequential loops versus structured graphs

Hands-On Task: Fix Three Bugs Three Different Ways

You have learned about the three layers theoretically. Now it is time to apply them in practice. Execute the following task using all three techniques: first using the harness-only architecture, then with the loop structure, and then with the graph architecture.

Create the Broken Mini-Repo

Create a new directory and add three broken files. Each file contains one bug and one pytest test:

# calc.py
def divide(a, b):
    return a // b  # bug: integer division, not float


# test_calc.py
from calc import divide


def test_divide():
    assert divide(7, 2) == 3.5


# strings_utils.py
def reverse_words(sentence):
    return sentence.split()[::-1]  # bug: returns a list, not a string


# test_strings_utils.py
from strings_utils import reverse_words


def test_reverse_words():
    assert reverse_words("hello world") == "world hello"


# dates_utils.py
from datetime import date


def days_between(d1, d2):
    return (d2 - d1).days + 1  # bug: off by one


# test_dates_utils.py
from datetime import date
from dates_utils import days_between


def test_days_between():
    assert days_between(date(2026, 1, 1), date(2026, 1, 10)) == 9

Install the required dependencies, then confirm all three tests currently fail:

pip install pytest anthropic
pytest -q

Add a small model wrapper that every round will reuse:

# model.py

import os
from anthropic import Anthropic


client = Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])


def call_model(prompt: str) -> str:
    resp = client.messages.create(
        model="claude-sonnet-5",
        max_tokens=1024,
        messages=[
            {"role": "user", "content": prompt}
        ],
    )

    return resp.content[0].text

List of failed unit tests

Round 1: Harness Engineering

In this round, the agent is given access to tools — file reading, file writing, and running tests — but no retry or routing logic is allowed. The operation runs once per file and the process is documented.

# round1_harness_only.py

import subprocess
from model import call_model


FILES = ["calc.py", "strings_utils.py", "dates_utils.py"]

The harness-only approach reveals immediately how much the surrounding infrastructure matters: with clean tool access and clear context, even a single-pass agent can make meaningful progress on well-scoped bugs.

Conclusion

Harness engineering, loop engineering, and graph engineering are not interchangeable terms for the same idea — they are distinct layers that address different failure modes in production agent systems. The harness defines what the agent can access and persist. The loop defines how feedback drives the agent toward a verified outcome. The graph defines which paths are permitted and when control should branch or merge. Understanding where a problem actually lives — in the environment, the feedback cycle, or the control flow — is the first step toward fixing it without overcomplicating the architecture.