A single 960KB binary
Install with brew, npm, pip, or `zig build`. The CLI is the same Zig-compiled native binary in every package — no Node runtime, no Python interpreter, no Docker required.
Zig 0.16 · MIT · github.com/neul-labs/tokenworm
A tiny, fast, zero-dependency AI coding agent — CLI, C-ABI library, and idiomatic SDKs for Python, TypeScript, and Go. One 960KB Zig binary, 8ms cold start, the same agent core in every package.
What the README claims, verbatim
960KB
ReleaseSmall binary
8ms
cold start
2.4MB
idle memory
0
runtime dependencies
6
built-in tools
5
LLM providers
18
lifecycle hooks
Zig 0.16
compiler
What is tokenworm?
tokenworm is an MIT-licensed AI coding agent written in Zig 0.16. It ships as a ~960KB native binary with zero runtime dependencies, and the same agent core is exposed as a CLI, a C ABI library (libtokenworm.so / .dylib), and idiomatic SDKs for Python, TypeScript, and Go. The product surface is small on purpose: six built-in tools, five LLM providers, OS-native sandboxing, and portable .tworm sessions.
At a glance
The problem, and the bet
One agent core, many surfaces
The C ABI in src/lib/ffi.zig is the load-bearing decision. Every SDK is a thin language binding over the same shared library; the agent loop, the providers, the tools, and the sandbox all live in the native code.
Install with brew, npm, pip, or `zig build`. The CLI is the same Zig-compiled native binary in every package — no Node runtime, no Python interpreter, no Docker required.
src/lib/ffi.zig exposes `tokenworm_init`, `tokenworm_run`, `tokenworm_cancel`, and the session functions as a stable C boundary. Any language with FFI can drive the agent.
`Agent(provider="opencode-zen")` and `async for chunk in agent.run(...)`. Wraps libtokenworm; the agent loop, providers, and tools all live in the native binary.
`new Agent({ provider })` with the same `agent.run()` shape. Sessions exported from one SDK resume in another — the .tworm format is the portable contract.
`tokenworm.NewAgent(Options{...})` returns outputs synchronously. The Go binding is intentionally thin; the heavy lifting stays in the Zig core.
The README documents .tworm sessions as 5x smaller and 20x faster to parse than JSONL. O(1) offset table for random message access. Export from CLI, resume in Python.
Install
brew, npm, pip, and `go get` all resolve to the same Zig-compiled native binary. Or build from source with Zig 0.16 — `zig build -Doptimize=ReleaseSmall` produces the 960KB executable.
# macOS / Linux brew install tokenworm # npm npm install -g tokenworm # pip pip install tokenworm # Go SDK go get github.com/tokenworm/tokenworm-go # Build from source (requires Zig 0.16) zig build -Doptimize=ReleaseSmall
Quickstart
Set an API key for any of the five providers and ask. The agent loop, the tool dispatch, and the sandbox are already wired up.
# Pick a provider export OPENCODE_ZEN_API_KEY="your-key" # One-shot tokenworm "what does src/core/agent.zig do?" # Switch provider at runtime tokenworm --provider anthropic "refactor the login flow" # Portable session tokenworm --export-session session.tworm "analyze auth" # Or run the REPL tokenworm -i
What the agent can do
All tools are workspace-scoped — they cannot access files outside the project directory. The `bash` tool runs commands in an OS-level sandbox: bubblewrap on Linux (`/usr`, `/lib`, `/etc` read-only; workspace read-write), sandbox-exec on macOS (Seatbelt profile).
read
Read file contents with offset/limit.
write
Create or overwrite files.
edit
Surgical text replacement (unique match required).
bash
Sandboxed shell commands (bwrap on Linux, sandbox-exec on macOS).
grep
Substring search across files with extension filter.
glob
Wildcard pattern file search.
Restrict the agent to a subset: Agent(allowed_tools=["read","grep","glob"]) for a read-only agent. The agent's system prompt only mentions the allowed tools.
Auto-trims old messages at the 80% context-window threshold (default), preserves recent messages and tool-call chains, and inserts a compaction marker so the model knows context was trimmed.
Capture every agent event for debugging and evaluation with --trace-file trace.json on the CLI or agent.enable_trace() in the SDK.
Five LLM providers
No code change required. tokenworm --provider ollama on the CLI; agent.switch_provider("anthropic") in the SDK. All providers share the same agent loop, tool dispatch, and session format.
| Provider | Setup | Use case |
|---|---|---|
| OpenCode Zen | OPENCODE_ZEN_API_KEY | Default. Free models, curated for coding agents. |
| Anthropic Claude | ANTHROPIC_API_KEY | Best coding performance. |
| OpenAI | OPENAI_API_KEY | Broad model selection. |
| Ollama | install ollama | Local, private, no API key. |
| MiniMax | MINIMAX_API_KEY | OpenAI-compatible alternative. |
Architecture
Key patterns from the README: vtable-based runtime polymorphism, a canonical agent while-loop, thread-local context globals, and a C ABI for zero-copy cross-language interop.
┌────────────────────────────────────────────────┐ │ CLI (src/cli/) │ Python SDK │ TS SDK │ Go SDK ├────────────────────────────────────────────────┤ │ C ABI (src/lib/ffi.zig) │ tokenworm_init / run / cancel / session / free ├────────────────────────────────────────────────┤ │ AgentRunner (src/lib/agent_runner.zig) │ Provider → Tools → Conversation → Stats ├────────────────────────────────────────────────┤ │ Core: agent.zig conversation.zig session.zig │ stats.zig trace.zig subagent.zig ├────────────────────────────────────────────────┤ │ Providers: anthropic / openai / minimax / ... ├────────────────────────────────────────────────┤ │ Tools: read / write / edit / bash / grep / glob ├────────────────────────────────────────────────┤ │ Sandbox: bwrap / darwin / allowlist / restricted └────────────────────────────────────────────────┘
Honest comparisons
Two grounded comparisons, sourced from the README's own vs-table. Each one uses only the rows the README documents.
Anthropic-only provider, Node.js or Python runtime, JSON sessions, no built-in sandbox. tokenworm runs as a native binary, multi-provider, with .tworm binary sessions and OS-native sandboxing.
OpenAI-only, Node.js or Python runtime, state-object sessions, container-based sandboxing. tokenworm is native, multi-provider, with portable binary sessions and OS-native (bwrap / seatbelt) isolation.
FAQ
No. The CLI binary is self-contained — it is a single 960KB Zig-compiled executable with no runtime dependencies. The Python, TypeScript, and Go SDKs require their respective runtimes, but the agent core itself is the native binary in every case.
Any provider with an OpenAI-compatible API. Built-in support for Anthropic, OpenAI, Ollama, MiniMax, and OpenCode Zen. OpenCode Zen includes free models such as deepseek-v4-flash-free and big-pickle.
Yes, by default. All bash commands run in an OS-level sandbox — bubblewrap on Linux, sandbox-exec on macOS. The agent cannot access files outside the workspace, and network access is configurable. `--no-sandbox` disables it entirely if you need to.
Yes. The 8ms cold start and 960KB binary size make it well suited to CI runners — no `npm install` or `pip install` of a hundred megabytes of dependencies, no Docker pull. The .tworm session format is designed to be exported from a CI step and resumed elsewhere.
Sessions use a custom binary format (.tworm) that includes conversation history, provider metadata, timestamps, token counts, and workspace file snapshots. Per the README, the format is 5x smaller and 20x faster to parse than JSONL and supports random message access through an O(1) offset table. Sessions exported from one SDK resume in another.
tokenworm ships as a native binary with no runtime dependency, while both alternatives require Node.js or Python. The README reports an 8ms cold start vs ~480-520ms for the alternatives, 2.4MB idle memory vs ~38-45MB, OS-native sandboxing vs none / container-based, and multi-provider support vs one provider each. See /compare/ for the full per-row breakdown.
Yes — MIT-licensed. Source lives at github.com/neul-labs/tokenworm.
Explore the docs
Read deeper into any part of tokenworm — the full feature set, the C ABI architecture, the five providers, worked use cases, the glossary, and the long-form blog.
The full feature set: native binary & performance, six tools, five providers, C ABI + SDKs, hooks/skills/MCP, sandboxing, and .tworm sessions.
The C ABI architecture end to end: surface → ffi.zig → AgentRunner loop → provider → workspace-scoped tools → OS-native sandbox → .tworm session.
Install, set a provider key, and run your first task from the CLI or the Python SDK — one-shot, REPL, runtime provider switch, portable session export.
The five LLM providers — OpenCode Zen, Anthropic, OpenAI, Ollama, MiniMax — with env vars and how runtime switching works.
Three worked walkthroughs: embed an agent in a native app via the C ABI, a coding agent in CI, and one agent core across Python, TS, and Go.
README-grounded, per-row comparisons with the Claude Agent SDK and the OpenAI Agents SDK — every row sourced from the published vs-table.
Plain-language definitions: native binary, C ABI, FFI, agent loop, MCP, SKILL.md, lifecycle hooks, sandboxing, .tworm session, cold start.
Grounded answers on why Zig, binary size, the providers and tools, sandbox safety, MCP and skills, session portability, and the MIT license.
Long-form notes on native-binary AI agents: the 960KB deployment story, the C ABI as the universal SDK boundary, and the systems-language shift.
Design rationale: why a systems language, what the C ABI buys, the three architectural commitments, and what is in and out of scope.
MIT-licensed, 960KB native binary, C ABI for any-language interop, multi-provider, OS-native sandbox. The systems-language bet, made concretely.