Coding agent · Go
loopcraft
An agent harness in Go that starts from the design of pi, the minimal agent harness, and tries to go further. Everything the model reads is listed so you can read it too.
- 4default tools: read, write, edit and bash
- <1ktokens for the system prompt with all four tool definitions
- 13providers in the built-in catalog
- 723models in the registry
Why I built it
I started from pi's design and wanted to go further with it: a sandbox on by default, MCP and subagents that don't hide context from you, and a single static Go binary where pi needs Node.
The rule I kept from pi is that nothing gets injected behind your back. Every context file loopcraft loads is listed at startup with its token estimate, and /context breaks the window down by system prompt, tool, file and message.
A loop and four tools
An agent is a loop. Stream the model's reply, run any tools it asked for, append the results, and go round again until it stops asking. Read-only calls from one reply run side by side, up to eight at a time, and anything that changes files runs alone and in order.
The default tools are pi's four: read, write, edit and bash. The architecture notes say models already know how to use them and extra tools mostly cost context, so a test holds the default prompt plus those four definitions to a 1,000 token budget. Sessions are append-only JSONL files whose entries carry an id and a parent id, so /tree can branch from any point and the first attempt stays.
The command line is built on coding.Session, the same type the Go SDK exposes. It runs in five modes: interactive, print, JSON events, RPC over stdin and stdout, and ACP so Zed, JetBrains IDEs and Neovim can use it as their agent.
Extensions as separate processes
pi loads TypeScript extensions into its own process. Before fixing a protocol I compared four options in an ADR: Go's plugin package, Yaegi-interpreted Go, WebAssembly through wazero, and child processes speaking JSON-RPC. Go plugins were out because they need cgo, and the release build is a static CGO_ENABLED=0 binary.
I went with child processes. A round trip carrying a 200-byte tool call measured 15 µs at the median, small next to a model response. Extensions can be written in any language, a crash costs only that extension's features, and an interceptor that crashes or times out fails closed, so a broken permission gate blocks the tool call.
MCP follows the same idea about context. By default the model sees one mcp tool that names each server and looks up a server's tools only when it needs them. A server can opt in to loading its tools up front, and /context shows what that costs.
Measured against pi
Against a scripted model that answers instantly, so every number is the harness itself, loopcraft printed its version in 15 ms to pi's 174 ms and peaked at 70 MB over 100 file reads to pi's 624 MB. The install is a 21 MB binary, where pi takes 255 MB.
On real tasks the two come out level. Over 152 paired runs of the Aider polyglot Python exercises on four models, loopcraft solved 68 and pi 64, a gap within chance (p = 0.6), at the same total cost. Three loopcraft runs looped inside an edit until they hit the token cap. pi was sending strict tool schemas and loopcraft wasn't, so I added them.
What's next
The roadmap reaches pi parity first and then goes past it. Still to build: the sandbox (Landlock and seccomp on Linux, Seatbelt on macOS, with control over network access), subagents whose transcripts become branches of the session tree, plan mode and memory, LSP diagnostics after edits, an HTTP server and a GitHub Action. Release binaries, a Homebrew tap and opening up the source are planned too.