harnessrouter
A Python client and CLI for any server that speaks the Unified Harness Protocol.
A harness is a configured agent: a runtime, a model, instructions and limits. A task is one run of it — a real conversation against a real workspace, streamed back as it happens. This client sends work, follows it, continues the conversation, cancels it, and collects the files it produced.
It is a UHP client, not a client for one product. It works against the open-source HarnessRouter server, the hosted one, or any third implementation that passes the conformance suite. Standard library only — no dependency on an HTTP stack you may not want.
pip install harnessrouter
Run a task
import os
from harnessrouter import HarnessRouter
client = HarnessRouter("http://localhost:3000", os.environ["UHP_API_KEY"])
harness = client.harnesses()[0]
response = client.run("Summarise README.md in three bullets.", harness_id=harness["id"])
response["status"] # 'completed'
response["output"] # ordered items: message, reasoning, function_call, function_call_output
Follow it while it happens
Agent tasks run for minutes. Without a stream a product can only show a spinner and hope.
for event in client.stream("Add tests for the parser.", harness_id=harness["id"]):
if event["type"] == "response.output_text.delta":
print(event["delta"], end="", flush=True)
Or let the client assemble it for you:
task = client.collect("Add tests for the parser.", harness_id=harness["id"])
task.text # the finished text
task.tool_calls # what the agent ran
task.annotations # the files it wrote
task.sequence # (False, [12]) if the stream dropped an event
Continue, cancel, collect
nxt = client.continue_(response["id"], "Now add tests for the function you just wrote.")
# same session, same working directory, same files
client.cancel(nxt["id"]) # a request to stop; the session stays continuable
files = client.session_files(nxt["metadata"]["session_id"])
data = client.download_file(files[0]["container_id"], files[0]["id"])
What it does for you
- Idempotency by default. Every
runcarries anIdempotency-Key, so a retry cannot start a second agent against the same files. - Retries only what is worth retrying.
session_busyand503s back off and try again;quota_exhaustedand every malformed request do not. APOST /v1/responsesthat may already have started is never resent on the client's own initiative. - Errors you can branch on.
UhpErrorcarries the server'stype,code,paramanddetail, plus aretryableproperty — no parsing prose to decide what to do. - Long timeouts. 15 minutes by default, because a 30-second timeout cancels healthy work.
CLI
export UHP_BASE_URL=http://localhost:3000
export UHP_API_KEY=…
harnessrouter discover # what the server is, and what it supports
harnessrouter harnesses # chrn_… Research agent [claude-code]
harnessrouter stream "Summarise README.md" --harness chrn_…
API
| Method | What it does |
|---|---|
discover() |
The server's version, conformance class and capabilities (no token needed) |
harnesses(), harness(id) |
Configured harnesses in your scope |
models(), harness_models(id) |
Model catalogues, with a computed available |
run(input, ...) |
Run a task and wait for the result |
stream(input, ...) |
Run a task and iterate its events |
collect(input, ...) |
Run, stream, and return the accumulated task |
continue_(response_id, input) |
Continue the session that produced that response |
get_response(id), input_items(id), wait(id) |
Read a task back, or poll it to a terminal state |
cancel(id), delete_response(id) |
Stop work; delete history. Deliberately different things |
sessions(), session(id), turns(id), session_files(id) |
Session listing and inspection |
download_file(container_id, file_id) |
Artifacts out |
Specification
https://github.com/HarnessRouter/harnessrouter/tree/main/protocol
Apache-2.0.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file harnessrouter-0.1.0.tar.gz.
File metadata
- Download URL: harnessrouter-0.1.0.tar.gz
- Upload date:
- Size: 12.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c0fee735f3a18ad5c01681dfa771a19a24b3ecc640c724b7aea3e9ff962fa61f
|
|
| MD5 |
930b150ac9a2d0a390d83ffcc4ce5ace
|
|
| BLAKE2b-256 |
b65801be95a986354927397c5e048786a9da9a96b6d64bf8586bdd324ba151b9
|
File details
Details for the file harnessrouter-0.1.0-py3-none-any.whl.
File metadata
- Download URL: harnessrouter-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
uv/0.10.10 {"installer":{"name":"uv","version":"0.10.10","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
057be285b458c74f0619f2f9d6307ea3a7b7dcf84e108f5c4b957a44f37d70cd
|
|
| MD5 |
627eacd8ae146b478c20e86d8126fd5c
|
|
| BLAKE2b-256 |
ec41ef7584dbf00e8711e0845810f8248085c6d797e7faed9802df8753140a77
|