Every team shipping an agent-powered feature in 2026 rebuilds the same thing: a loop that runs a coding agent in a sandbox, streams progress to a UI, keeps a session alive for follow-ups, and hands back files. Then a better harness ships, roughly every eleven days by one count, and the loop is rebuilt again.
HarnessRouter exists to end that cycle. It is the unified interface for agent harnesses: one API and one control plane through which a product can run Codex, Claude Code, Hermes, Pi, DeepSeek Harness, OpenCode, Qwen Code, Cline, Gemini CLI and Oh My Pi, switch between them per task, and get back streams, sessions, files and artifacts in a single contract. It ships as a managed Cloud and as an Apache 2.0 Community Edition, both implementing the open Unified Harness Protocol (UHP).
This is a technical teardown of that stack: the thesis, the object model, the API surface, the streaming contract, the protocol, the self-hosted architecture, the economics, and the roadmap the design implies. It is written from the public docs, the UHP specification and the open-source repository, with the parts that are not documented called out as such. For how Epsilla runs its own operations on top of it, see the companion post: How Epsilla Runs as an AI-Native Company on HarnessRouter.
Key takeaways
- The unit of exchange is a task, not a model turn. HarnessRouter's API accepts one authorized end-user task and returns a complete execution: progress events, text, files and artifacts.
- Harness and model are both request parameters. A configured agent pins a base harness, instructions, tools, skills and a model policy; the product calls it by ID and never hardcodes a vendor.
- The wire format is deliberately familiar. Requests and streams follow the OpenAI Responses shape, so existing parsers work, but every event carries a gapless sequence number and one authoritative terminal state.
- The Unified Harness Protocol turns the harness layer into infrastructure. Ten chapters, three cumulative conformance classes, a 64-check suite, and an error envelope that treats failure as a first-class result.
- The economics are the argument. In HarnessRouter's published Care Prep benchmark, cost per successful task varied about 475x across eight harness and model combinations. Routing is where the savings live.
1. The thesis: models generate tokens, harnesses complete work
HarnessRouter's stack framework splits an AI product into four layers: the model layer (hosted or open-weight, adopted rather than built), the context layer (retrieval and knowledge; Epsilla's own knowledge services sit here), the harness layer (the execution loop, tools, permissions, sandboxing and recovery), and a unified interface layer that connects many harnesses to one product. The recurring line across its blog is that a model is an engine and engines get swapped; the harness is the drivetrain that turns reasoning into finished work.
That framing explains a design decision that is easy to miss. HarnessRouter does not try to be a better harness. It treats Codex, Claude Code and Hermes as interchangeable backends, wraps each in the same lifecycle, and competes on the layer above them: routing, isolation, sessions, streaming, files, metering and tracing. This is why the architecture below looks less like an agent framework and more like a database driver plus a job system.
2. The object model
Five objects carry the whole product. Understanding them is most of understanding the API.
| Object | ID prefix | What it is |
|---|---|---|
| Workspace | key-scoped | The boundary for one product integration: API keys, configured agents, sessions and returned files. Keys are minted per Workspace. |
| Configured agent (harness) | chrn_ | A base harness plus purpose, instructions, tools and skills, and a model policy. The product invokes it by ID. |
| Response | resp_ | One turn. Its ID is the handle for continuation. |
| Session | hsess | Continuity across turns: the working directory, context and configured harness persist. Created implicitly by the first task. |
| File and container | file_, cntr_ | Inputs uploaded by the product and artifacts produced in the sandbox, always fetched server-side. |
Two rules from the core concepts matter more than the rest. First, the product keeps the user experience, auth, tenancy, data and permissions; HarnessRouter is only the runtime that receives one authorized task. Second, build-time work (a coding agent integrating HarnessRouter into your app) and runtime work (your end user's task) must never collapse into one request. The quick start even encodes this: you paste an AGENTS.md into Codex or Claude Code, describe the feature, and the coding agent wires the runtime call with the Workspace key entered through a secure modal rather than pasted into chat.
The configured agent is the load-bearing object. A JSON body is enough to create one:
{
"name": "Contract Review Agent",
"base": "claude-code",
"default_model": "claude-sonnet-4.6",
"system_prompt": "Review the uploaded agreement and return a risk checklist as JSON.",
"mcp_servers": [],
"skills": []
}
The guidance on when to create a second agent is a good operating rule for any team: split when purpose, data access, tools, permissions, model policy or artifact contract differ, not by button count.
3. The API surface
All routes live under https://api.harnessrouter.ai/v1 and authenticate with a server-side Bearer key. The browser never calls HarnessRouter directly; the documented pattern is a server-side proxy that maps a product feature key to a harness ID.
Running a task is one call:
curl -N https://api.harnessrouter.ai/chrn_abc123/v1/responses \
-H "Authorization: Bearer $HR_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{"input": "Review this uploaded agreement and return a checklist.", "stream": true}'
Continuing the same session reuses the working directory and context by referencing the previous response:
{
"input": "Continue where you left off and finish the remaining work.",
"previous_response_id": "resp_...",
"metadata": { "session_id": "hsess..." },
"stream": true
}
The rest of the surface is small and regular:
GET /v1/modelsandGET /v1/harnesses/{id}/modelsreturn the model catalog, keyed by backend, with anavailableflag the server must compute rather than assert.GET,POST,PUTandDELETEon/v1/harnessesmanage configured agents.POST /v1/filesuploads inputs as multipart, referenced in a task as aninput_fileitem alongsideinput_text.GET /v1/sessions/{id},/turns,/filesand/files/archivepoll status, recover answer text after a dropped stream, list artifacts and download a zip with folder hierarchy preserved.GET /v1/containers/{session}/files/{file}/content, with/pdfappended for a server-converted preview of Office documents.POST /v1/sessions/{id}/cancelstops the agent. Closing the SSE connection does not; the docs are explicit that cancellation is a call, not a disconnect.
Idempotency is not optional. Every initial runtime request carries a fresh UUID; the same key is reused only for transport retries of that exact request, and if a stream drops after the first event, the product recovers from the session instead of sending a new task. Keys are retained for at least 24 hours, and a repeated key waits for and returns the first result.

4. The streaming contract
Streaming is where most agent integrations break, so this is the part of the stack worth reading twice.
HarnessRouter streams Server-Sent Events in an OpenAI Responses-style format with data: frames only. There are no event: lines; the event name is the type field inside each JSON payload, and parsers dispatch on it while ignoring unknown types. The first frame is always response.created, which carries the two IDs a product must persist immediately:
data: {"type":"response.created","sequence_number":0,
"response":{"id":"resp_...","status":"in_progress",
"metadata":{"session_id":"hsess..."}}}
Every event has a sequence_number that starts at zero and increases by exactly one, and exactly one terminal event ends the stream: response.completed, response.incomplete (a budget such as max_step or timeout_seconds was hit; partial output is retained and the session is continuable) or response.failed. Cancellation terminates with response.failed whose status is cancelled, and the specification is pointed about it: the status field, not the event name, is authoritative.
Between the first and last frame, the vocabulary is the Responses vocabulary: response.output_item.added and .done bracket each item; response.output_text.delta carries text; response.function_call_arguments.delta carries tool calls; reasoning summaries are optional and never required; artifact citations arrive as container_file_citation annotations. Servers must not buffer to completion, must send keep-alive comments at least every 30 seconds, and may support resume from Last-Event-ID. The client guidance is the sensible one: treat the stream as an optimisation and the stored response as the source of truth.
For product UIs the streaming UI pattern adds one more rule: stream useful progress, not raw agent internals. Tool and item events become sanitized status lines; the diff or document is what the user sees.
5. The Unified Harness Protocol
What makes HarnessRouter more than a hosted wrapper is that the contract above is published as an open standard. UHP version 2026-08-11 is a draft standard, Apache 2.0 licensed, expressed in OpenAPI 3.1 and JSON Schema 2020-12, and governed in the open-source repository. Its unit of exchange is a task, a complete agent execution, rather than a model turn.
The specification has ten chapters: Architecture, Lifecycle, Harnesses, Tasks, Streaming, Sessions, Files, Errors, Security and Schema. Three design principles from the Architecture chapter explain most of the details:
- The client should not be able to tell which harness ran the work, except by asking.
- Events describe what happened, never how to display it.
- Every failure is reportable in the same envelope as success.
Conformance classes are cumulative. Core covers discovery, harness listing, task execution (streaming and non-streaming), session continuation, cancellation and the error model. Extended adds file input, artifacts and session listing. Full adds harness create, update and delete, plus read-only session sharing. A server must not advertise a capability it does not implement, and a GET /v1/uhp discovery call returns the class and a capability map.
Errors are a closed set. Every error uses one envelope, {"error": {"type", "code", "message", "param", "detail"}}, with types such as invalid_request_error, authentication_error, rate_limit_error, harness_error and server_error, and named codes including session_busy, harness_mismatch, session_expired, model_unavailable, quota_exhausted and harness_unavailable. Retry guidance is part of the spec: back off on 5xx, honour Retry-After on rate limits, wait for a terminal state on session_busy, and never retry quota_exhausted or an auth error.
Model substitution is explicit. A server may either fail with model_unavailable or substitute a model and set metadata.model_fallback to true with the requested model and a reason. Usage counts are real or null, never a fabricated zero.
Conformance is measured, not claimed. The suite has 64 checks (40 Core, 8 Extended, 15 Full) and is run from the command line against any base URL. It fails buffered streams, checks gapless sequence numbers, verifies that cancel reaches a terminal state, tests path traversal and nosniff on downloads, and treats a skip as never a pass. The Community Edition reported 64 of 64 on 2026-09-04, and the implementations registry already lists an independent client. That last fact is the one to watch: a protocol becomes real when a second party implements it.
For context on how UHP relates to MCP, A2A, AG-UI and MHS, HarnessRouter's own framing is that different protocols standardize different boundaries: UHP configures and runs harnesses, MCP wires tools at runtime, A2A delegates between agents, AG-UI renders, MHS reaches hardware. We covered the earlier stage of this landscape in The Agent Harness Wars: OpenAI's Sandbox Decoupling vs. Anthropic's Model Context Protocol.
6. Community Edition: what runs where
The Community Edition is the reference implementation, and reading it clarifies what the Cloud abstracts away.
It ships as a single Docker container with three processes and one volume:
- Console on port 3000, the only published port, serving the UI and proxying the API on the same origin.
- Gateway on a loopback port, implementing the Responses-style API and the harness lifecycle.
- Runner on a second loopback port, executing harness CLIs inside session workspaces.
- A
/datavolume holding a local SQLite database, files, secrets and workspaces.
Harness CLIs are installed into the volume on first start rather than bundled, and a failed install is non-fatal. Isolation in the Community Edition is per-session operating-system users: each agent process runs as a dedicated user that owns only its workspace directory, so no privileged flags or custom seccomp profiles are required. Idle workspaces expire after a configurable TTL and can be rehydrated from a checkpoint. This is honest about what a single host can promise; the Cloud, by contrast, advertises one serverless isolated sandbox per task and managed concurrency, and does not document its sandbox internals publicly.
Credential handling is the other instructive piece. Provider keys are stored as named connections in environment variables, and each backend has a policy that is an ordered chain of connection names. Connectors exist for Anthropic, OpenAI, OpenRouter, Azure Foundry, Google, Bedrock, Vercel, a custom OpenAI-compatible endpoint, and TokenRouter, which is compatible with all ten harnesses. That chain is the seed of a credential broker: fall through to the next connection on an auth or provider failure, keep the runner ignorant of where the key came from.
The whole thing is one command:
docker run -d --name harnessrouter -p 127.0.0.1:3000:3000 \
-v harnessrouter:/data harnessrouter/harnessrouter
Then curl http://localhost:3000/api/harness/v1/models confirms it is up. A team can develop against the Community Edition, save a harness configuration, and upload that configuration (not keys, sessions or files) to the Cloud. That is deployment portability in practice, and it is the property HarnessRouter's portability post calls the socket rather than the dock.
7. The harness roster
As of this writing the catalog lists 41 harnesses, ten of them available to run and 31 reviewed with capability profiles only.
| Harness | Maker | Notes from the catalog |
|---|---|---|
| Codex | OpenAI | AGENTS.md, skills, sandbox and approval policies, subagents |
| Claude Code | Anthropic | Real working tree, sub-agents, document skills, MCP, tiered permissions, checkpointing |
| Hermes Agent | Nous Research | Persistent memory, skills library, browser and computer use, deliverable mode for DOCX, XLSX, PPTX |
| Pi | earendil-works | Minimal, steerable, session trees with resume, fork and clone |
| DeepSeek Harness | DeepSeek | Version-pinned developer preview, MCP overlay, subagents |
| OpenCode | anomalyco | Bash, edit, patch and web tools; 75+ providers; allow, ask, deny rules |
| Qwen Code | Alibaba | QWEN.md, five permission modes, rollback |
| Cline | Cline Bot | Headless, shadow git checkpoints, parallel research subagents |
| Gemini CLI | Gemini models only; GEMINI.md; sandboxing | |
| Oh My Pi | can1357 | Pi lineage; LSP, Python, browser, subagents in isolated worktrees |
The roster went from three at the August 14 open-source launch to eight by the end of August to ten in September, which is the cadence the unified-interface bet depends on. Every available harness also gets the same artifact tooling in the sandbox: Pandoc for documents, SheetJS for spreadsheets, PptxGenJS for presentations, Sharp for images and Remotion for video.
8. Routing economics: the number that justifies the layer
HarnessRouter's Care Prep benchmark ran one controlled task across eight harness and model configurations, five runs each, with the dataset, skill, schema and output contract fixed.
| Configuration | p95 latency | Cost (credits) |
|---|---|---|
| Hermes + gpt-5.2 | 2m 33s | 0.47 |
| Codex + gpt-5.2 | 4m 36s | 0.72 |
| Hermes + claude-sonnet-4.6 | 2m 49s | 39.6 |
| Hermes + gpt-5.5 | 1m 25s | 40.7 |
| Codex + gpt-5.5 | 2m 46s | 59.7 |
| Claude Code + claude-sonnet-4.6 | 1m 31s | 83.5 |
| Hermes + claude-opus-4.8 | 2m 42s | 150 |
| Claude Code + claude-opus-4.8 | 3m 18s | 223 |
Three findings follow. The cost spread is about 475x. Holding the model fixed and switching only the harness moved cost 1.5x to 2.1x and latency up to 1.95x. And for six of the eight configurations, another setup was both cheaper and faster; only two sat on the efficiency frontier. The benchmark publishes quality as a strict grounding pass (schema compliance, exact supplied facts, valid evidence references, a required human-review flag) rather than folding it into one score.
This is why HarnessRouter's pricing bills agent work per active minute, metered by the second, with waiting on a model, on a queue or on the user free. The Cloud plans run from a free tier (30 work minutes, no card) through Developer at $20, Production at $200 and Scale at $1,000 per month, each including its price as usage, with model usage at catalog price or on your own keys. The pricing page works an example: a typical three-minute text task on a mid-size model costs about seven cents.
Harness Arena is the product built on this insight: run one task across configurations, gate on success, compare cost and latency, then route traffic. The public rankings, by contrast, measure popularity by routed tokens, and the page is careful to say that usage rank does not measure capability.
9. Where the stack is heading
None of this is a public roadmap, but the design and the beta flags point in a consistent direction.
- From runtime to control plane. Tracing is already a per-run timeline of user, agent, tool and result events and a paid add-on in beta. Agent Memory, billed per gigabyte-hour for work histories, trajectories and artifacts, is the storage half of the same move. Together they turn the router into the system of record for agent work, which is the position from which routing decisions get automated.
- From configuration to competition. Harness Arena makes selection a repeatable experiment. The next step the docs imply is closing the loop: promote and demote configurations per task class on evidence rather than by hand.
- From one implementation to a protocol ecosystem. UHP's Full class includes session sharing and harness management, the conformance suite is public, and an independent client already exists. Custom harness upload from Community Edition to Cloud is the packaging story. The endgame is that a harness is a plug-in and a product never learns which one ran.
- From coding agents to every deliverable. The artifact tooling (documents, spreadsheets, decks, images, video) and the open starter kits for slides, sheets, dashboards and videos show the target market is any product feature that ends in a file, not only code.
The bet underneath all four is the one we made at Epsilla when we started treating agent harnesses as reusable infrastructure: the harness layer only becomes infrastructure when there is a shared contract at its boundary. UHP is that contract, and HarnessRouter is the first production implementation of it.
10. Evaluating it for your product
HarnessRouter publishes a nine-item production checklist. Condensed, it is the review we would run on any agent runtime:
- Build-time and runtime requests are written separately.
- The API key lives server-side only; the browser sends a feature key and input, never a harness ID.
- Every run carries an idempotency key; the stream parser dispatches on
data.type. - Response and session IDs are saved from
response.created. - Continue, cancel, preview and download verify ownership first.
- Generated HTML and code are isolated before preview.
- A representative end-user task has been tested through the product UI.
The docs close that checklist with a line worth adopting: passing defined checks, not self-assessment, is what ready means.
Frequently asked questions
What is HarnessRouter? HarnessRouter is a unified interface for agent harnesses. Through one Agent API a product can run Codex, Claude Code, Hermes, Pi, DeepSeek Harness, OpenCode, Qwen Code, Cline, Gemini CLI and Oh My Pi, with serverless sandboxes, sessions, streaming, files and metering handled by the platform. It is available as a managed Cloud and an Apache 2.0 Community Edition.
What is the Unified Harness Protocol? UHP is the open standard HarnessRouter initiated and maintains. Version 2026-08-11 defines a task-centric API in OpenAPI 3.1 and JSON Schema 2020-12, with Core, Extended and Full conformance classes, an OpenAI Responses-compatible streaming vocabulary and a closed error-code set, verified by a 64-check conformance suite.
How is HarnessRouter different from an LLM router? An LLM router selects a model for a single request and returns content. HarnessRouter manages complete multi-step work: it selects a harness and model, runs the task in an isolated sandbox with tools and files, streams progress, keeps a session for follow-ups and returns artifacts.
Can I self-host HarnessRouter? Yes. The Community Edition runs as a single Docker container with a console, gateway and runner, uses a local SQLite database, isolates sessions with per-session operating-system users and supports the same ten harnesses. Configurations can be uploaded to the Cloud later.
How does HarnessRouter charge? Agent work is billed per active minute, metered by the second, with waiting free. Plans start at a free tier and run from $20 to $1,000 per month, each including its price as usage. Model usage is billed at catalog price with no markup, or you bring your own keys.
How does Epsilla use HarnessRouter? Epsilla builds its own agent operations on the platform. The companion post on Epsilla's AI-native operations roadmap covers the details.

