The harness paradigm is the foundational insight of production AI engineering: the model provides intelligence, but the harness provides control. A raw language model is a text generator — powerful but undirected, capable but unsafe. The harness is the infrastructure layer that wraps the model and transforms it into a controllable, auditable, production-ready agent. It constrains the action space through typed tools, manages conversation state across turns, enforces safety through a permission system, handles failures gracefully, and tracks resource consumption. Without a harness, deploying an LLM into production is like wiring a jet engine directly to a steering wheel — the power is there, but the control system is missing.
Claude Code implements the harness as a TypeScript class called QueryEngine
. This class is the single owner of all mutable state in a conversation session, and every agent interaction flows through it.
// src/QueryEngine.ts
// The QueryEngine is the harness core — it owns all mutable state for a session.
export class QueryEngine {
private config: QueryEngineConfig
private mutableMessages: Message[] // Full conversation history, append-only
private abortController: AbortController // User can cancel mid-execution at any time
private permissionDenials: SDKPermissionDenial[] // Audit trail of every blocked action
private totalUsage: NonNullableUsage // Cumulative token + cost tracking
Each field maps to a core harness responsibility. mutableMessages
is the agent's memory — every user message, assistant response, and tool result is appended here. abortController
is the emergency stop — the user can always regain control. permissionDenials
is the audit trail — every blocked action is recorded for review. totalUsage
is the budget tracker — the harness knows exactly what the session has cost.
The QueryEngine exposes its functionality through a single async generator method:
// src/QueryEngine.ts
// submitMessage is an async generator — it yields results incrementally.
// This enables real-time streaming: the user sees text as it's generated,
// and tool executions are reported as they complete, not after the full turn.
async *submitMessage(
prompt: string | ContentBlockParam[],
options?: { uuid?: string; isMeta?: boolean },
): AsyncGenerator<SDKMessage, void, unknown>
The async generator pattern is a deliberate design choice. Instead of blocking until the entire conversation turn is complete, submitMessage
yields events as they happen — a token arrives, a tool starts, a tool finishes. This makes the system feel responsive and allows the UI layer to update in real time. It also means the harness can be interrupted mid-stream without losing the work already done.
Every action the model can take is expressed as a Tool
. The interface is comprehensive by design — it forces every tool to declare not just what it does, but how it behaves:
// src/Tool.ts
// The Tool interface is the contract between the harness and every action.
// Tools must declare their identity, execution logic, input schema,
// concurrency safety, read/write/destructive behavior, and permission rules.
export type Tool<Input extends AnyObject = AnyObject, Output = unknown> = {
readonly name: string // How the model addresses this tool
call(args, context, canUseTool, ...): Promise<ToolResult<Output>> // Execution
readonly inputSchema: Input // Zod schema — validated before call()
isConcurrencySafe(input): boolean // Can this run in parallel?
isReadOnly(input): boolean // Safe to auto-approve?
isDestructive?(input): boolean // Requires explicit user consent?
checkPermissions(input, context): Promise<PermissionResult> // Tool-specific safety
maxResultSizeChars: number // Prevents context window explosions
}
The inputSchema
is a Zod schema — it provides both compile-time type safety and runtime validation. When the model produces a tool_use
block, the harness validates the input against this schema before ever calling the tool. Malformed input never reaches tool code. The behavioral declarations (isReadOnly
, isDestructive
, isConcurrencySafe
) let the harness make intelligent decisions about permissions and execution order without needing to understand what each tool actually does.
Hermes implements the harness as a Python class called AIAgent
in run_agent.py
. The design philosophy is similar — one class owns the session state — but the execution model is synchronous and the tool system uses a registry pattern rather than a typed interface.
# run_agent.py
# AIAgent is the harness core in Hermes — it owns model, budget, callbacks, and platform context.
class AIAgent:
def __init__(
self,
model: str = "anthropic/claude-opus-4.6",
max_iterations: int = 90, # Hard cap on LLM turns
enabled_toolsets: List[str] = None,
disabled_toolsets: List[str] = None,
platform: str = None, # "cli", "telegram", "discord", etc.
iteration_budget: "IterationBudget" = None, # Shared across parent + subagents
tool_progress_callback: callable = None, # Real-time tool status updates
clarify_callback: callable = None, # Human-in-the-loop questions
session_id: str = None,
# ... plus provider, routing, memory, and checkpoint params
):
self.model = model
self.max_iterations = max_iterations
# IterationBudget is thread-safe and shared with subagents.
# Parent creates it; children inherit it. This caps total work
# across the entire agent tree, not just the root agent.
self.iteration_budget = iteration_budget or IterationBudget(max_iterations)
self.platform = platform
# run_agent.py
# IterationBudget is a thread-safe counter that caps runaway agent loops.
# It's shared across parent and all subagents — total iterations are bounded
# at the tree level, not per-agent. consume() returns False when the budget
# is exhausted, which breaks the agent loop cleanly.
class IterationBudget:
def __init__(self, max_total: int):
self.max_total = max_total
self._used = 0
self._lock = threading.Lock() # Thread-safe for parallel subagents
def consume(self) -> bool:
"""Try to consume one iteration. Returns True if allowed."""
with self._lock:
if self._used >= self.max_total:
return False
self._used += 1
return True
def refund(self) -> None:
"""Give back one iteration (e.g. for programmatic tool calls)."""
with self._lock:
if self._used > 0:
self._used -= 1
# run_agent.py (simplified from AGENTS.md)
# run_conversation() is the harness loop — entirely synchronous.
# It calls the LLM, executes tools, and repeats until the model stops
# requesting tools or the iteration budget is exhausted.
def run_conversation(self, user_message: str, ...) -> dict:
while api_call_count < self.max_iterations and self.iteration_budget.remaining > 0:
response = client.chat.completions.create(
model=model, messages=messages, tools=tool_schemas
)
if response.tool_calls:
# Execute each tool call and append results to message history
for tool_call in response.tool_calls:
result = handle_function_call(tool_call.name, tool_call.args, task_id)
messages.append(tool_result_message(result))
api_call_count += 1
else:
# No more tool calls — model is done
return {"final_response": response.content, "messages": messages}
Where Claude Code uses a typed Tool
interface, Hermes uses a central registry. Tools register themselves at import time:
# tools/registry.py (pattern from AGENTS.md)
# Tools self-register at import time. The registry collects schemas for the
# LLM's tool list and routes function_call events to the right handler.
# No interface to implement — just call registry.register() with a schema,
# a handler lambda, and an optional availability check function.
registry.register(
name="port_scan",
toolset="security",
schema={
"name": "port_scan",
"description": "Scan open ports on a target host",
"parameters": {"type": "object", "properties": {"host": {"type": "string"}}}
},
handler=lambda args, **kw: port_scan(host=args["host"], task_id=kw.get("task_id")),
check_fn=lambda: bool(os.getenv("NMAP_AVAILABLE")), # Availability guard
)
The registry pattern trades compile-time safety for runtime flexibility. Tools can be added, removed, or conditionally enabled without changing any interface — just import the file and the tool appears. The check_fn
provides the availability guard that Claude Code's checkPermissions
handles at the interface level.