Skip to content
tokenworm ★ GitHub

← Back to writing

When systems languages start winning the agent layer

tokenworm / neullabs · ·
systems-languageszigdesign

The first wave of AI agent SDKs all look similar. They are packages on top of Python or Node. They wrap a model API, expose an agent loop, add some tools, and ship as pip install or npm install. The two SDKs tokenworm’s README explicitly benchmarks against — Claude Agent SDK and OpenAI Agents SDK — are both members of that first wave, both ship in Python and TypeScript, and both look like the natural answer when your starting audience is data scientists and ML engineers.

That choice is not wrong. It is the right choice for the first wave, because the first wave is mostly being written by people who already live in Python and Node. The agent loop is glue, the LLM call dominates the latency budget, and the tooling everyone already uses for ML — Jupyter, FastAPI, the Hugging Face ecosystem — speaks Python natively.

The README’s bet is that the second wave looks different. This post is the long version of that claim.

What changes between the first and second wave

The first wave of agent SDKs was sold to the people building the agent. Make it easy to wire up an LLM call. Make the loop legible. Make the tools easy to define. The user is the data scientist or ML engineer at the keyboard.

The second wave is sold to the people deploying the agent. The agent has already been built; the question is how to embed it everywhere the team wants to use it. The user is now an SRE wiring it into a CI pipeline, an editor team integrating it into an LSP, a platform team running thousands of fan-out workers, a product team shipping a desktop CLI to customers who do not have Node installed.

The constraint set inverts. The first wave optimises for iteration speed at write time. The second wave optimises for runtime characteristics at deploy time: small binary, fast cold start, low idle memory, embeddability, no runtime dependency, sandboxed execution, predictable performance.

That is the slot tokenworm is aiming for. Every README number reads like a deployment metric: 960KB binary, 8ms cold start, 2.4MB idle, zero runtime dependencies, OS-native sandbox, embeddable shared library. None of those are write-time properties. All of them are deploy-time properties.

Why a systems language helps

You can, in principle, get to those numbers from many languages. People have built small, fast binaries in Go, Rust, Nim, OCaml, plain C. The README picks Zig 0.16. Worth asking why.

Zig has three properties that line up specifically with what an agent runtime wants:

Explicit allocators. Every allocation in Zig flows through an allocator passed as a parameter. There is no hidden allocation. For an agent loop that manages conversation history, tool buffers, network responses, and stream chunks, that gives you a path to bound and audit memory use that languages with implicit allocation simply do not offer. The 2.4MB idle figure is achievable because there is no hidden runtime sitting in the background.

Comptime metaprogramming. Zig’s comptime lets you generate code at compile time without macros. For tokenworm specifically, that supports the vtable-based runtime polymorphism the README cites: providers, tools, and sandbox backends can be selected through vtables that get generated at compile time, without paying for dynamic dispatch in places it would be a tax.

Real C interop. Zig was designed to be a better C. Importing C headers, exporting C ABI symbols, linking against C libraries — these are first-class operations. That matters because the C ABI is, as I argued in the previous post, the load-bearing decision behind the multi-language SDK story. Picking a language where the C boundary feels native, not bolted on, makes the rest of the architecture cheap.

None of these properties are unique to Zig in absolute terms. Rust has them, modulo borrow-checker friction. Modern C++ has them, modulo template syntax. Plain C has them, modulo every other ergonomic problem in plain C. What is unique about Zig is the combination, plus a small enough language surface that the binary stays small. That combination is what gets you a 960KB ReleaseSmall build with the README’s feature set.

What you give up

The honest version of this argument has to name the trade.

You give up the casual contributor base. A Python agent SDK can be modified by anyone who knows Python; that is a lot of people. A Zig 0.16 agent SDK has a much narrower pool. The README’s bet is that for a project whose value proposition is runtime characteristics, the right contributor pool is people who already think about those characteristics. That is a smaller, sharper community by design.

You give up some iteration speed at write time. Zig is faster to write than C and slower to write than Python. If your day job is prototyping new agent architectures every week, the Python SDKs will let you ship faster. tokenworm is for the case where the agent loop has stabilised and the question is “how do we run this at scale, in lots of places, cheaply”.

You give up some ecosystem reach. The Python ML ecosystem is enormous; tokenworm cannot tap into it directly without going through the FFI boundary. That is what the SDKs are for, but they will always feel one step removed from the native language ecosystem.

In exchange you get the numbers. A 960KB native binary you can ship anywhere. An 8ms cold start that makes deployment shapes tractable. A 2.4MB idle that lets you run many concurrent agents on one host. A C ABI you can embed in any language. An OS-native sandbox that does not need Docker. Multi-provider support so you are not bound to a vendor.

Where it slots in

This is not a takeover argument. The first-wave SDKs are not going away, and they should not. If your agent is a Jupyter notebook calling a model, you want the Python SDK; if it is a Next.js backend with an LLM call, you want the TypeScript SDK; if it is a tightly Anthropic-integrated assistant, the Claude Agent SDK is the right answer.

The second-wave SDK is for the cases the first wave was not built for: CI runners, pre-commit hooks, LSPs, fleet workers, desktop CLIs, embedded copies of an agent shipped inside another binary. The README is direct about this: tokenworm ships as a library as much as a CLI, and the library is the design centre.

If the first wave answered “how do I build an agent”, the second wave answers “how do I deploy one as if it were a normal piece of software”. Systems languages are good at the second question. They have been good at it for decades — every time a workload matures past the prototyping stage, there has been a migration from the high-level language it was first written in to the systems language it eventually runs in. Compilers. Databases. Editors. Browsers. Operating systems. The pattern is consistent.

Agent runtimes are following the same arc, just compressed. The first agents were written in Python and Node because that is where the model APIs are. The agents that have to run in lots of places, cheaply, predictably, are going to be written in Zig and Rust and Go because that is what those languages are for.

tokenworm is the bet, made concretely. The numbers in the README — 960KB, 8ms, 2.4MB, zero runtime deps — are the artifact of taking that bet seriously and executing on it for a year. Whether the second wave moves to systems languages broadly is a market question. Whether tokenworm has built a credible systems-language answer for the agent layer specifically is, at this point, just reading the spec.

The answer, on the README, is yes.