Zot vs Pi vs OpenCode: A Hard Look at AI Coding Agent Harnesses
~9 min readZot vs Pi vs OpenCode: A Hard Look at AI Coding Agent Harnesses
AI coding agents have become the de facto programming interface for 2026. But the harness — the CLI tool that drives them — matters more than most developers realise. A slow harness adds latency to every prompt. A fat runtime hogs memory on your laptop. A complex install chain breaks in CI.
After using zot, pi, and opencode daily across dozens of projects, I ran a systematic benchmark on the same machine (Linux x86-64, 64 GB RAM). The results are striking — and not in the way you'd expect.
The Three Contenders
| zot | pi | opencode | |
|---|---|---|---|
| Version | 0.3.13 | 0.82.1 | 0.0.0-docs/limitations |
| Language | Go 1.25 | TypeScript / Node.js | TypeScript / Bun |
| Binary type | Static ELF (stripped) | Node.js script shim | Native ELF (Bun-compiled) |
| Protocol | Custom (JSON-over-stdio) | Custom (JSON-over-stdio) | ACP (Agent Client Protocol) |
| Repository | github.com/patriceckhart/zot | github.com/earendil-works/pi | github.com/opencode-ai/opencode |
All three follow the same basic architecture: a CLI binary spawns an LLM subprocess, instruments your shell, reads and writes files, and manages conversation context. The differences are in how they do it.
Benchmark Results
1. Startup Time
Startup latency is the cost you pay on every single invocation — even before the LLM does any work. For interactive TUI sessions it's a one-time cost, but for print-mode (zot -p, pi -p, opencode run) or CI pipelines, it compounds fast.
| Harness | Command | Avg Startup (10 runs) |
|---|---|---|
| zot | zot --help | 13 ms |
| pi | pi --version | 682 ms |
| opencode | opencode --help | 2,144 ms |
zot starts 52× faster than pi and 165× faster than opencode. This isn't surprising — Go produces a single static binary with no interpreter bootstrapping. pi loads the entire Node.js runtime plus hundreds of npm modules before it can even parse CLI flags. opencode bundles a Bun/JavaScriptCore runtime that includes JIT compilation overhead.
2. Binary Size
| Harness | Binary Size | Type |
|---|---|---|
| zot | 17 MB | Static ELF, stripped |
| pi | 63 B | Shell script → Node.js entrypoint |
| opencode | 162 MB | Native ELF (Bun-bundled TS) |
pi's 63-byte shim is deceptive — it's just a #!/usr/bin/env node redirect to cli.js. The actual runtime cost is the Node.js installation (~130 MB) plus node_modules (~125 MB) in ~/.pi/agent/.
zot's 17 MB includes everything: the TUI, the wire protocol, model resolution, extension loading, and the full conversation engine. One file, zero dependencies.
3. Memory Usage (RSS)
Peak resident set size during a simple print-mode task:
| Harness | Peak RSS |
|---|---|
| zot | ~21 MB |
| pi | ~51 MB |
| opencode | ~128 MB |
pi uses 2.4× more memory than zot. opencode uses 6.1× more. The V8/Bun JavaScript heaps dominate. For a single agent session this is tolerable; if you're running multiple agents in parallel (the ACP orchestrator pattern), it compounds.
4. Model Listing Speed
How fast can each harness enumerate available models? This matters for provider resolution and extension loading.
| Harness | Command | Avg Time (5 runs) |
|---|---|---|
| zot | zot --list-models | 64 ms |
| pi | pi --list-models | 2,020 ms |
opencode doesn't support a non-interactive model listing flag.
zot resolves and formats 1,069 models from 33 providers in 64 ms. pi lists 342 models in over 2 seconds.
5. Provider Ecosystem
| Harness | Providers | Models | Examples |
|---|---|---|---|
| zot | 33 | 1,069 | Anthropic, OpenAI, Google, DeepSeek, Kimi, Ollama, OpenRouter, Groq, Together, xAI, Grok, Mistral, Cohere, Fireworks, SambaNova, Cloudflare, plus 18 more |
| pi | ~30 | 342 | Anthropic, OpenAI, Google, DeepSeek, Ollama, OpenRouter, Groq, Together, xAI, Mistral, plus 20 more |
| opencode | 8 | 561 | OpenAI, Anthropic, Google (LiteLLM), OpenRouter, GitHub Copilot, GitHub Models, plus proprietary opencode and opencode-go providers |
zot has the broadest provider coverage with a catalog that auto-updates from live APIs. opencode lists more models because it includes every OpenRouter model variant, but most come from just 2-3 providers. pi has the smallest catalog but offers the deepest extension API (themes, skills, custom tools, SDK integrations).
6. Runtime Dependencies
| Harness | Runtime Dependency | Dynamic Libs |
|---|---|---|
| zot | None | 0 (statically linked) |
| pi | Node.js 24.18.0 | ~50 (via libnode) |
| opencode | Bun runtime (bundled) | 5 (libc, libm, libdl, libpthread, librt) |
zot is a true single-binary distribution. curl | install and it works everywhere — no Node version, no Bun, no venv, no nothing. This is a decisive advantage for:
- CI/CD pipelines: No
actions/setup-nodestep, nonpm ci, no.npmrcconfiguration - Air-gapped environments: Copy one 17 MB file
- Containers:
COPY zot /usr/local/bin/in ascratchordistrolessbase image
7. Disk Footprint
| Harness | Core Install Size |
|---|---|
| zot | 332 KB (~/.local/state/zot/) |
| pi | 255 MB (~/.pi/agent/) |
| opencode | 2.7 GB* (~/.local/share/opencode/) |
* opencode's full footprint including accumulated conversation DB is 19 GB; the 2.7 GB figure excludes the main database and counts only binary, snapshots, logs, and storage.
zot's entire persistent state fits in a single models-cache.json (332 KB). pi ships with hundreds of npm packages in node_modules. opencode stores conversation snapshots, tool output, and detailed logs that grow unbounded over time.
What the Numbers Don't Show
Extension Ecosystem
pi has the most mature extension model. Its TypeScript-based extension SDK supports:
- Custom providers:
pi.registerProvider()with full model catalog - Skills: SKILL.md + SKILL.md files injected into system context
- Themes: Full TUI theming via CSS-like config
- Custom tools: Expose shell commands as structured tool APIs
- SDK integrations: Programmatic control from other Node/TS projects
zot has a simpler extension model — Go subprocesses that speak newline-delimited JSON over stdio. The wire protocol is documented but less expressive. Extensions can register commands and return prompts, but can't add custom tools or themes.
opencode uses the ACP (Agent Client Protocol) as its primary extension surface. Since ACP is a standardised protocol, any ACP-compatible editor can drive opencode — and any opencode agent can be orchestrated by a central ACP client. This is the right architectural bet for multi-agent workflows.
Conversation Quality
All three harnesses produce comparable results when pointed at the same model. The harness doesn't change what the LLM says — it changes how fast you get there and how much it costs to run.
Print Mode Performance
For a simple "list files in /tmp" task in print mode:
| Harness | Wall-clock time |
|---|---|
| zot | 183 s (using default provider) |
| pi | 8,953 s (hit rate limits during extended session) |
This isn't a fair comparison — both hit different LLM backends and rate limits. The meaningful comparison is the overhead on top of the LLM call, which is negligible for all three.
Architecture Analysis
┌─────────────────────────────────────────────────┐
│ USER │
├──────────┬──────────────┬───────────────────────┤
│ zot │ pi │ opencode │
│ (Go) │ (TypeScript) │ (TypeScript/Bun) │
│ │ │ │
│ ┌──────┐ │ ┌──────────┐ │ ┌───────────────────┐ │
│ │ TUI │ │ │ TUI │ │ │ TUI / Web / ACP │ │
│ │(bubble│ │ │(ink │ │ │ (custom, │ │
│ │ tea) │ │ │ React) │ │ │ very polished) │ │
│ └──────┘ │ └──────────┘ │ └───────────────────┘ │
│ ┌──────┐ │ ┌──────────┐ │ ┌───────────────────┐ │
│ │ext SDK│ │ │extension │ │ │ACP server │ │
│ │(JSON │ │ │SDK (TS) │ │ │(standardised) │ │
│ │stdio) │ │ │(in-proc) │ │ │ │ │
│ └──────┘ │ └──────────┘ │ └───────────────────┘ │
│ ┌──────┐ │ ┌──────────┐ │ ┌───────────────────┐ │
│ │LLM │ │ │LLM client│ │ │LLM client │ │
│ │client │ │ │(in-proc) │ │ │(multi-provider) │ │
│ └──────┘ │ └──────────┘ │ └───────────────────┘ │
├──────────┴──────────────┴───────────────────────┤
│ LLM API (OpenAI, Anthropic, ...) │
└─────────────────────────────────────────────────┘
Why Go Wins on Raw Performance
Go's compilation model produces a single statically-linked binary with:
- No GC pauses on startup (the heap is cold, no JIT warmup)
- No interpreter bootstrapping (no V8, no SpiderMonkey, no JavaScriptCore)
- Efficient I/O (netpoller-based non-blocking I/O, similar to
io_uringon Linux) - Small binary size (tree-shaking + static linking + stripping)
Bun's native compilation (used by opencode) is good but still carries the JavaScriptCore weight — a full WebKit JS engine compiled into the binary. Node.js (used by pi) is the heaviest — V8's JIT compilation alone adds hundreds of milliseconds to every startup.
Why TypeScript Wins on Ecosystem
TypeScript has:
- NPM — the largest package registry on earth
- Hot reload — change code, see results immediately during extension development
- Familiar web patterns — async/await, Promises, EventEmitters
- Pi's in-process extension model — extensions run in the same V8 isolate, sharing memory and event loops with zero serialisation overhead
For plugin development, TypeScript is faster to iterate. For production deployment, Go is faster to execute.
When to Use Which
| Scenario | Best Choice | Why |
|---|---|---|
| CI/CD pipelines | zot | Zero dependencies, single binary, 13 ms startup |
| Docker containers | zot | FROM scratch, COPY zot /bin/ |
| Air-gapped / offline | zot | No runtime downloads, no package manager |
| Plugin development | pi | Rich TypeScript SDK, hot reload, in-process extensions |
| Multi-agent orchestration | opencode | ACP standard, centralised server, web UI |
| Team onboarding | opencode | Best TUI, built-in model management, opencode providers |
| Low-memory machines | zot | 21 MB RSS vs 128 MB |
| Maximum providers | zot | 33 providers, 1,069 models, auto-updating catalog |
| Academic / self-hosted | zot + custom plugins | Easy to write Go extensions for institutional APIs |
The Verdict
zot is the fastest, lightest, and most portable coding agent harness available today. Its Go architecture delivers 50-165× faster startup than its competitors, 2.4-6.1× lower memory, and a single 17 MB binary with zero runtime dependencies.
pi has the best extension ecosystem. If you need custom tools, themes, skills, or SDK integrations, pi's in-process TypeScript extension model is unmatched. The trade-off is heavier runtime (Node.js) and slower startup.
opencode has the best TUI and the best protocol bet. Its ACP support means it works with any ACP-compatible editor and can be orchestrated centrally. But it's the heaviest option — 162 MB binary, 128 MB RSS, 2.7 GB disk footprint.
For most developers, the right answer is: use zot for speed and portability, pi for extensibility, and opencode when ACP orchestration matters. There's no single winner — but the data makes the trade-offs clear.
Methodology
All benchmarks were run on the same Linux x86-64 machine (64 GB RAM) on 2026-07-27.
- Startup time: 10 iterations of
--help/--versioninvocation, measured withdate +%s%N. Minimum recorded. - Binary size:
stat -c%son the resolved binary path. - Memory: Live RSS sampled via
/proc/<pid>/statusduring active print-mode execution. Peak value across 10 samples. - Model listing: 5 iterations of
--list-models, median time. - Provider count: Unique provider prefixes parsed from
--list-modelsoutput. - Disk footprint:
du -shon each tool's data directory, excluding accumulated conversation databases.
Full reproducible benchmark script and raw data available at github.com/tobias-weiss-ai-xr/next-graphwiz-ai.