A source-grounded comparison of eight agentic coding harnesses — the agent loops that turn an LLM into a coding assistant. Where most comparisons stop at feature checklists, this one reads the actual source of each harness and reconstructs how its loop runs: how it calls the model, dispatches tool calls, gates them for permission, and hands control back to you.
It ships with an interactive visualizer (site/) that animates each loop step-by-step and plays the same scenario across all eight harnesses side-by-side — so you can watch how each one handles, say, an edit it needs your approval for.
Sibling project to
spec-compare, which compares spec-driven development toolkits. This repo compares the execution layer underneath them.
| Harness | Repo | Language | Stars | Why it's here |
|---|---|---|---|---|
| Claude Code | claude-code-src (v2.1.88 recovery) |
TypeScript / Ink | — | Anthropic's CLI agent. Async-generator streaming loop with a canUseTool permission gate. |
| OpenCode | anomalyco/opencode |
TypeScript | 167K | "The open source coding agent." Client/server split, provider-agnostic. |
| pi | earendil-works/pi |
TypeScript | 57K | Monorepo toolkit: coding-agent CLI + unified LLM API + TUI/web libraries. |
| code_puppy | mpfaffenberger/code_puppy |
Python | 556 | A Python outlier — a different language and a different tool-call protocol. |
| Claw Code | ultraworkers/claw-code |
Rust | — | Claude-Code-parity Rust port. The most elaborate gate here — sandbox modes + per-tool rules + Pre/PostToolUse hooks. Marketing runs hot; the loop is real. |
| claux | ducks/claux |
Rust | — | Clean Claude-Code reimplementation: a single legible turn loop, 4 permission modes (default/accept-edits/bypass/plan), parallel read-only tools. |
| Hermes Agent | NousResearch/hermes-agent |
Python | — | The structural outlier: a normal per-turn loop plus a self-improving skill/memory meta-loop that runs between turns. Gates only dangerous shell commands. |
| llm-tui | ducks/llm-tui |
Rust | — | The maximal-approval baseline: an event-driven TUI where every tool call waits for a y/n/a/q keypress, home-sandboxed by construction. |
Five projects were evaluated and excluded for having no model→tool→loop of their own. Two sit below or beside a harness —
llm-mux(a provider router/multiplexer) andopenclaw(a gateway that delegates coding to external agents). Three sit above one, driving Claude Code and Codex as their execution substrate —genie,Trellis, andloom. See methodology → Considered but not onboarded.
Each harness's loop is reconstructed into a structured loop spec (site/src/data/loops/<harness>.json) — nodes, edges, and scenarios, every node tied back to a real file:line in the harness source. That one artifact drives both the prose docs and the visualizer, so they can't drift.
The node vocabulary is fixed so all eight are comparable:
| Kind | Meaning |
|---|---|
input |
A user message enters the loop |
llm |
A call to the model |
tool |
A tool call is dispatched |
approval |
A permission / approval gate |
execute |
The tool actually runs |
decision |
A branch (e.g. "more tool calls, or done?") |
terminal |
The turn ends |
Every harness defines the same scenarios — edit-file, denied-tool, multi-tool, plain-answer — which is what makes the side-by-side comparison meaningful.
- Comparison Matrices — side-by-side feature, capability, and architecture tables
- The Loops — agent loops compared, with links into the visualizer
- Tool Handling — dispatch, registries, and permission/approval models
- User Interaction — input, streaming, interrupts, slash commands, sessions
- Language & Runtime — TypeScript, Python, and Rust harnesses across the set
- Methodology — exact sources, versions, and what was read
- What Goes Across the Wire — the
/v1/messagesrequest: API client, tool-call protocol, prompt caching (cache_controlplacement), system-prompt assembly, CLAUDE.md loading - Events & Hooks — all 27 lifecycle events, the settings.json config schema, the exit-code/JSON control-flow contract, and where each fires on the loop
The site/ app animates each loop and compares scenarios across harnesses. Navigation: a sidenav lists "Compare all" or a harness; within a harness, tabs switch between:
- Compare all — every harness runs the same scenario, stepped in lockstep
- Loop — one harness's loop with transport controls and a node inspector
- Sequence — the same scenarios projected as an animated sequence diagram (User · Agent · Model · Tool lifelines)
- Hooks & events — Claude Code's lifecycle hooks overlaid on its loop (click a node to see what fires) — Claude Code only
- Across the wire — Claude Code's request/response, as a curl walkthrough (hand-run the round-trips) or a layered request-assembly view, with cache breakpoints — Claude Code only
The Loop, Sequence, and Hooks diagrams sit in a pan/zoom frame: drag to pan, +/− or ctrl-scroll to zoom, Fit to reframe, and arrow keys once the frame has focus. Each also expands to a full-screen viewer. Compare all deliberately keeps its scale-to-fit columns so the set stays glanceable.
cd site
npm install
npm run devEight harnesses, analyzed deeply — not a survey of the wider field. A broader landscape (aider, Codex CLI, Gemini CLI, Goose, Crush, …) is explicitly out of scope. Projects without a coding loop of their own (routers, gateways, and orchestration layers that drive another harness) are documented as exclusions rather than profiled — see methodology.
MIT. Harness sources are analyzed in place and never vendored into this repo (see methodology).
Last Updated: 2026-05-31