OpenHarness: The Python Harness That Turns Any LLM Into an Agent
A deep dive into the control plane behind tool use, memory, permissions, and multi-agent coordination.
- OpenHarness treats the harness, not the model, as the product boundary, so permissions, tools, memory, and continuation logic become first-class design decisions.
- Its engine turns provider-specific output into a local conversation loop, which makes tool use and retries feel like state transitions instead of ad hoc hacks.
- MCP, markdown skills, and a terminal-native UI give it extensibility without turning it into a heavyweight framework.
- Compared with Claude Code and agent SDKs, it occupies the narrow middle ground where transparency and control matter more than polish.
OpenHarness is interesting because it refuses the usual agent story. The model is not the product here. The harness is. That means permissions, tool calls, memory, continuation logic, and swarm coordination are first-class, not bolt-ons.
OpenHarness (oh) is an ultra-lightweight alternative to Claude Code with pure Python implementation
That design choice makes sense for a repo coming out of HKUDS, the University of Hong Kong Data Science group. The code reads like an attempt to compress a messy agent stack into something inspectable, portable, and easy to swap underneath a different model provider.
港大刚刚最新开源了一款比Claude Code轻44倍、兼容Claude Code skills和plugins生态的智能体框架:OpenHarness核心代码1万多行,砍掉了遥测、OAuth、重型React UI,只保留了核心Harness架构模型负责思考,Harness给模型提供手、眼、记忆和安全边界。
What OpenHarness actually ships
The repository is split by responsibility, not by hype. engine owns the loop, coordinator defines agent behavior, mcp standardizes external tools, swarm keeps long-lived teams, and frontend/terminal gives the whole thing a console face.
src/openharness/
api/
engine/
coordinator/
mcp/
swarm/
frontend/terminal/
ohmo/
.claude/skills/
That layout is the point. OpenHarness keeps the state machine visible, so you can see where a message becomes a tool call, where a tool call becomes a result, and where a result becomes another turn. The engine does not hide the harness behind a single opaque prompt.
Inside the agent loop
The engine is where the harness earns its name. QueryEngine tracks conversation history and cost, while ConversationMessage and its content blocks normalize provider-specific payloads into one local language. has_pending_continuation then decides whether the last tool result should flow back into the model for another pass.
That is why this does not feel like a dumb wrapper. It is a governed loop that keeps enough structure to be inspectable and enough freedom to keep going when the work is not done.
How it keeps agents on a leash
OpenHarness puts approval before action. Tool breadth matters less than the place where the system stops and asks a human, because that is where autonomy becomes usable instead of reckless. Memory persistence and continuation control are part of the same bargain: the harness remembers enough to continue, but not so much that it forgets who is in charge.
Why the terminal is part of the product
The React plus Ink terminal is not decoration. It gives the agent loop a visible surface, which matters when the system is making decisions over several turns and the user needs to know what just happened. In a terminal, status, prompts, approvals, and task handoffs share the same space, so the control plane stays close to the operator.
MCP, skills, and the long tail of tool use
OpenHarness's tool story is deliberately hybrid. MCP gives it a standardized way to reach out to external systems, while markdown skills make extension feel lightweight instead of plugin-heavy. The result is not just more tools, but a cleaner way to organize capability.
OpenHarness vs Claude Code and agent SDKs
This is where the trade-off becomes obvious. Claude Code is the finished product experience, agent SDKs are building blocks, and OpenHarness is the harness layer you can inspect, trim, and extend without rebuilding the whole control plane.
| Axis | OpenHarness | Claude Code | Agent SDKs |
|---|---|---|---|
| Primary unit | Harness first. The model is swappable. | Product first. The model family is embedded. | Library first. You assemble the experience. |
| Extensibility | MCP, skills, swarm, and permissions. | Constrained by the product architecture. | Anything you can build on top. |
| Governance | Explicit permission checks and continuation control. | Managed inside the app experience. | Mostly your responsibility. |
| UI posture | Terminal-native with a React plus Ink surface. | Polished first-party CLI experience. | No UI opinion unless you add one. |
| Best fit | Teams that want a transparent control plane. | Users who want a finished agent tool. | Developers who want primitives, not opinions. |
The trade-off is clear. You give up some product polish, but you get less coupling, more visibility, and a control layer that can survive model churn. That is a good deal if your real problem is not chatting with a model, but running one inside a governed workflow.
What this design says about agents
The larger lesson is simple. As models get easier to swap and cheaper to improve, the harness becomes the durable layer. OpenHarness is interesting because it makes that layer explicit, legible, and small enough to study.





