Skip to specification

pi — the harness by subtraction

Mario Zechner's coding agent keeps the loop small enough to hold in your head — a system prompt under a thousand tokens, a handful of tools — and answers most of the eleven slots by refusing them, with a published argument for each refusal. The empty cells on this sheet are not gaps; they are the design.

Identification

Author
Mario Zechner (badlogic)
Runtime
TypeScript · four packages
System prompt
under 1,000 tokens
Core tools
read · write · edit · bash (+grep, find, ls)
Providers
15+ via its own pi-ai layer

LineageStarted as badlogic/pi-mono under Zechner's personal account; now stewarded by Earendil at earendil-works/pi with docs at pi.dev. Same project, same author — the creator of libGDX — and the same argument carried from the first commit: modern models are already trained on coding-agent semantics, so most of what a big harness adds is weight.

Read it as

A hand tool

No motor, no housing, nothing concealed. Everything the agent reads and does is in plain sight — and the safety gear is yours to bring.

The drawing, in one paragraph

The load-bearing observation is about the models, not the software: they arrive reinforcement-trained on the grammar of coding agents, so a tiny stable prompt and four tools suffice — and everything a bigger harness bolts on can be a file, a shell command, or an extension instead. No MCP: a protocol manifest can eat five figures of tokens before work starts (Zechner measured Playwright's at roughly 13,700), so pi replaces servers with small CLI tools plus a README the agent reads on demand — about 225 tokens. No plan mode: PLAN.md. No todo tool: TODO.md. No background jobs: tmux, where a human can watch. What pi does build, it builds unusually deeply — sessions are trees you can branch in place, and one embeddable loop drives the terminal UI, a JSON mode, an RPC subprocess, and an SDK.

the loop drawn whole · hatched parts are deliberately not fitted

11 parts · every selection is linkable
FIG. 2 — the harness by subtraction. The loop drawn whole on the left; on the right, the schedule of parts deliberately not fitted, hatched and struck through — each with its stated replacement.

The examination — eleven slots, one harness

Built in
Ships in the core; works with no configuration.
Via config or extension
The slot is real but you fill it — config, extension, or convention.
Deliberately omitted
Left out on purpose, with a stated argument for the gap.
  1. A system prompt under a thousand tokens, stable across releases, plus hierarchical AGENTS.md from global to project scope. Nothing is injected behind the operator's back — what the model was told is exactly what you can read.

    Built in

    <1k-token prompt · AGENTS.md

  2. The agent finds its own material the way a person would: grep, find, read. No retrieval index, no embedding store, no codebase map — the position is that a model trained to navigate repositories should navigate, and that a visible search trail beats an invisible ranking.

    Built in

    grep · find · read — no index

  3. Compaction triggers when context crosses the window minus a reserve (16,384 tokens by default): the newest 20,000 tokens survive untouched and everything older is summarized, with file lists accumulated across successive compactions. Manual /compact accepts steering instructions, and leaving a session-tree branch can write a summary of the abandoned work into the trunk.

    Built in

    reserve 16,384 · keep 20k · /compact

  4. Read, write, edit, bash — plus grep, find, and ls — defined with TypeBox schemas, streaming progress, and results split into a model-facing part and a UI-facing part. MCP is refused outright: manifests are too expensive and their results are not composable. The replacement is a small CLI tool and a short README; the agent shells out, and output can land on disk and be piped onward.

    Built in

    TypeBox · no MCP · CLI + README

  5. No permission system, no sandbox, no approval popups — pi runs with the operator's full authority, and the README says so. The stated position is that prompt-level permission gates are security theater; real isolation is a container's job, and pretending otherwise teaches false comfort.

    Deliberately omitted

    no gates — run it in a container

  6. The deepest mechanism on the sheet. Sessions are JSONL trees — every entry carries a parent id, and the live position is a leaf. Pick any earlier message and continue from it: a new branch in the same file. /tree navigates, folds, and labels the whole structure; /fork and /clone split sessions; plans and todos live as PLAN.md and TODO.md in the repo, versioned, instead of as modes in the harness.

    Built in

    JSONL session trees · /tree · PLAN.md

  7. One event-driven loop, embeddable four ways — interactive TUI, one-shot JSON, an RPC subprocess speaking JSONL over stdio, and an in-process SDK. Long-running work is deliberately pushed out to tmux, where the process is observable and a human can attach mid-debug. The harness runs the turn; the operator runs the day.

    Via config or extension

    TUI · JSON · RPC · SDK — tmux for long work

  8. No hidden delegation. When parallel work is wanted, pi spawns itself through bash, so the child's entire transcript sits in the parent's output in plain sight. The argument: a mid-task context-gathering sub-agent usually signals poor planning — gather context first, in its own session, as an artifact you can reuse.

    Deliberately omitted

    pi spawns pi, via bash

  9. Three registers, all plain files: Agent-Skills-standard SKILL.md directories with progressive disclosure (only descriptions ride in the prompt; the body loads on demand), markdown prompt templates invoked as slash commands, and TypeScript extensions that register tools, commands, and shortcuts — shareable as packages on pi.dev.

    Built in

    SKILL.md · templates · extensions

  10. Observability is the design's default state rather than a feature: every file the agent read, every command it ran, every sub-agent transcript is on screen, and tmux panes make long processes watchable. Verification machinery, though, is yours to add — an extension can intercept every tool result, and a test run is a bash call away, but nothing demands receipts unprompted.

    Via config or extension

    nothing hidden · tool_result hooks

  11. The core is deliberately frozen — a stable prompt and a fixed toolset are the point — so improvement accretes around it: skills, templates, and extensions in the global and project directories, shared as installable packages. The harness does not compound; your kit does.

    Via config or extension

    ~/.pi and .pi/ · pi.dev/packages

Where this design runs out of road

The trade is that you are the safety system. No permission gate stands between the model and your shell; the design assumes a competent operator and a container. And subtraction has a second cost: every convenience the big harnesses ship — a gate, a receipt, a scheduler — is an extension you must write, install, or decide to live without. The hand tool cuts fast and hides nothing; it also never argues when you aim it at your thumb.

02Side by sideThe comparison table — same eleven slots, opposite fills

Read from — every finding traces to one of these

UnitT02
Fills6 built in · 3 adapted · 2 omitted
Read againstThe Harness — eleven primitives