About
A single native binary as the agent core.
tokenworm draws one line: the agent loop, the providers, the tools, and the sandbox live in one Zig-compiled native binary. Every language SDK is a thin binding over the same shared library. The CLI is the same binary.
What tokenworm is
tokenworm is an MIT-licensed AI coding agent, distributed as a 960KB ReleaseSmall binary, with a CLI, a C ABI library (libtokenworm.so / .dylib), and idiomatic SDKs for Python, TypeScript, and Go. It is written in Zig 0.16 and has zero runtime dependencies. The CLI cold-starts in 8ms and uses about 2.4MB of memory at idle, per the README's published benchmark numbers.
The product surface is small on purpose:
- CLI —
tokenworm "<prompt>"one-shot,tokenworm -ifor the REPL,--provider,--export-session,--trace-file, and the rest of the flags documented in the CLI reference. - C ABI —
src/lib/ffi.zigexportstokenworm_init,tokenworm_run,tokenworm_cancel, the session functions, and the cleanup primitives. This is the load-bearing boundary. - Language SDKs — Python (async iterator over chunks), TypeScript (
for awaitstream), and Go (synchronous output slice). All three wrap the same shared library. - Six built-in tools —
read,write,edit,bash,grep,glob. Workspace-scoped;bashruns in an OS sandbox. - Five LLM providers — OpenCode Zen (default, free models), Anthropic, OpenAI, Ollama (local), MiniMax. Switchable at runtime.
- .tworm sessions — a portable binary session format. The README documents it as 5x smaller and 20x faster to parse than JSONL, with an O(1) offset table for random message access.
Why a systems language
Most agent SDKs are shipped as Node or Python packages. That is a reasonable default when the agent loop is glue code between an LLM API and a process spawner, because the runtime cost is dominated by the network call to the model. The README's bet is that the runtime cost stops being dominated by the model call as soon as you do any of three things:
- Run a lot of short agent invocations. An 8ms cold start vs a ~500ms cold start matters when an agent is invoked dozens of times per CI job, or once per pre-commit hook, or once per LSP request. Those are real settings now, not hypotheticals.
- Embed the agent inside another binary. A C ABI you can
dlopenis a fundamentally different deployment artifact frompip installornpm install. You can ship tokenworm inside a Go service, a Rust CLI, a desktop app, a kernel module if you really wanted to. - Care about memory or binary size. 2.4MB idle vs ~38-45MB idle is a 15x ratio. 960KB binary vs ~200MB of language runtime is a 200x ratio. Neither matters until you are running a hundred of them or shipping them to constrained environments, at which point both matter a lot.
Zig was chosen because the README's invariants are easier to express in Zig than in C: explicit allocator passing, comptime metaprogramming for the vtable-based runtime polymorphism, no hidden control flow, and no GC pauses. The C ABI is the export layer; the Zig is the internal language.
Architectural commitments
The README lists the architecture stack from CLI / SDK at the top down to the platform sandbox at the bottom. Three commitments are visible in that stack:
- The C ABI is the contract. Every SDK goes through
src/lib/ffi.zig. That means a bug fix or feature addition in the agent core propagates to every language without touching the binding code. - Vtable-based runtime polymorphism. Providers, tools, and sandbox backends are all selected via vtables. New providers, new tools, and new sandbox implementations slot in without changing the agent loop.
- OS-native sandboxing. The sandbox layer ships
bwrap(Linux bubblewrap),darwin(sandbox-exec / Seatbelt),allowlist,restricted, andnoopbackends. No Docker required, no container overhead. If neither bubblewrap nor sandbox-exec is available, the restricted mode falls back to environment filtering and command allowlisting.
What is in scope, and what is not
The README is explicit about scope. tokenworm is an agent SDK and a CLI; it is not a hosted runtime, not an evaluator, not an orchestrator, not a model fine-tuning toolkit. It is the layer between an LLM API and the local machine, with a small, fast, embeddable footprint as the central design constraint.
Some specific things the README documents that we did not reinvent:
- Skills. Reusable instruction sets via
SKILL.mdfiles. The built-insoftware-developmentskill teaches the agent best practices. - 18 lifecycle hooks. Shell-based hooks that receive JSON via stdin and can cancel operations by returning non-zero. Examples:
on_tool_call_start,on_llm_call_complete,on_session_end. - MCP integration. Model Context Protocol over stdio and SSE. Auto-start MCP servers from
config.json. - Context compaction. Automatic trimming at the 80% context-window threshold, preserving recent messages and tool-call chains.
- Trace export.
--trace-file trace.jsoncaptures every agent event for debugging and evaluation. - Doctor.
tokenworm --doctorruns a system health check across providers, sandbox availability, and MCP servers.
What it is part of
tokenworm is a neul-labs project. Project documentation lives at docs.neullabs.com/tokenworm/ — neullabs uses a path-based docs subdomain so the same site serves docs for every project.
How to engage
Install with brew install tokenworm, npm install -g tokenworm, or pip install tokenworm. The Go SDK is go get github.com/tokenworm/tokenworm-go. Build from source with Zig 0.16 via zig build -Doptimize=ReleaseSmall. The source is at github.com/neul-labs/tokenworm under the MIT license.