TL;DR: Harness engineering is the runtime control plane around a model: capability allowlists, identity and resource policy, bounded execution, evidence, human decisions, and recovery. MCP can expose capabilities, a workflow library can coordinate state, and a sandbox can reduce blast radius; none of these alone makes autonomous code changes safe.

Introduction

In the Harness Engineering concepts guide, we defined the "Agent = Model + Harness" formula. Now, let's dive into the engineering: How do we build this constraint system from scratch?


A Versioned Harness Design

There is no universal 2026 stack. A production design usually makes these concerns explicit:

  1. Capability interface: MCP or another adapter exposes narrowly scoped tools. The server and runtime still enforce identity, resource, network, rate, and side-effect policy.
  2. Workflow state machine: LangGraph, a queue, or application code can coordinate state, retries, cancellation, and persistence. It does not expose or guarantee a model's private chain of thought.
  3. Execution boundary: Containers, VMs, or WASM may reduce a process's blast radius, but require image/runtime hardening, filesystem and network policy, secrets isolation, quotas, and host-level monitoring.

Practical Steps: Building a "Self-Healing Coding Agent"

We'll build an Agent capable of automatically fixing linting errors.

Step 1: Defining Nodes and States (LangGraph)

First, we define the Agent's workflow logic at the Harness layer:

python
# Illustrative pseudocode; versions, state schema, sandbox API, and
# authorization policy are intentionally omitted.
from langgraph.graph import StateGraph, END

def generate_code(state):
    return {"proposal": model.generate(state["task"], state["allowed_context"])}

def run_linter(state):
    result = sandbox.run(
        ["npm", "run", "lint"],
        cwd=state["workspace"],
        network="deny",
        timeout=state["budgets"].command_seconds,
    )
    return {"lint": result.to_bounded_record()}

def fix_errors(state):
    return {"proposal": model.revise(
        state["proposal"], state["lint"], state["allowed_context"]
    )}

# Build the graph: generate -> lint -> (if error) fix -> lint
workflow = StateGraph(AgentState)
workflow.add_node("generate", generate_code)
workflow.add_node("lint", run_linter)
workflow.add_node("fix", fix_errors)

workflow.add_conditional_edges(
    "lint",
    lambda s: "fix" if s["lint"].has_actionable_errors else END,
)

The runtime must validate the proposed patch, keep it inside an authorized workspace, cap output and retry budgets, run tests in an isolated identity, and require a separate policy decision before any commit or external write.

Step 2: Configuring the MCP Toolset

An MCP configuration declares a transport and a server; it does not itself prove that a caller may read or write a path. Use a runtime-issued identity and an allowlist of resources and operations:

json
{
  "mcpServers": {
    "filesystem": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-filesystem", "/workspace"]
    }
  }
}

Step 3: Designing Human-in-the-Loop (HITL)

Approval should be a durable, authenticated decision bound to a specific diff, repository, branch, actor, expiry, and policy. A terminal prompt alone is not an authorization control:

python
def human_approval(state):
    decision = approval_service.request(
        actor=state["principal"],
        effect="repository_write",
        diff_digest=state["diff_digest"],
        target=state["target_branch"],
    )
    return {"approved": decision.is_valid_for(state)}

Three Secrets to Harness Optimization

1. Model Tiering Strategy

Don't use the most expensive model for everything. Compare model revisions on representative quality, safety, latency, privacy, and cost slices. Deterministic parsers, compilers, and linters are preferable to a model for deterministic checks.

2. Context Pruning

In the "Generate-Error-Fix" loop, context accumulates quickly. Summarize or prune redundant logs, but retain source revisions, policy decisions, failures, and provenance required for debugging, audit, and reproducibility.

3. Environment Snapshots

Before modifications, create an isolated workspace and record a source revision and patch digest. A Git branch or snapshot helps recover repository state, but cannot roll back emails, deployments, database writes, or other external effects; those need idempotency and compensating procedures.


Typical Architecture Diagram

graph TD User["User Requirement"] --> Harness["Harness Controller"] Harness --> LLM["LLM Inference (Brain)"] LLM --> Tools["MCP Toolset (Hands)"] Tools --> Sandbox["Docker Sandbox (Safety)"] Sandbox --> Feedback["Result Feedback (Logs/Errors)"] Feedback --> Harness Harness -- "Valid Result" --> User

Summary

Harness engineering means treating model output as an untrusted proposal and enforcing policy in the runtime. Workflow control, capability adapters, execution isolation, evidence, human decisions, and recovery should be tested as separate controls rather than assumed from a framework name.

Next, you can explore how to combine multiple constrained Agents into a Multi-Agent System.


Related Reading:

Primary Sources