Back to blog
By Hidde Kehrer4 min read

The CLI is the API


Every sandbox product ships with a Python SDK. Some also ship TypeScript. A few have Go bindings. Everyone races to wrap their execution runtime in language-idiomatic helpers, because that's what developers expect.

boxd's interface is a single static binary — the boxd CLI — and every command it exposes is the API. There's a gRPC API under it, and thin Python and TypeScript SDKs if you want them, but the CLI is the surface everything else wraps. One command, --json on everything.

Why a CLI first

SDKs are convenient. They're also a commitment.

Every SDK has to be maintained across language ecosystems, kept in sync with the backend, updated for every API change, documented for every method. That's real engineering work — and it's work that steers your API design toward what fits cleanly in a Python decorator, not what fits cleanly in an agent's shell.

Worse: leading with an SDK binds your users to the languages you support. A JS-shop team can use your JS SDK. A Python shop uses your Python SDK. A Rust shop waits. An agent whose runtime is a prompt-to-shell loop can't use an SDK at all — not without a bespoke integration layer that translates prompt intent into method calls.

A CLI where every command speaks --json has none of these problems. The SDKs we ship are a thin convenience over it, not the thing you have to reach for.

What a CLI gives you

Anything that can run a command can drive boxd. Bash can. A Makefile can. CI can. An agent with shell access can — in fact, an agent with shell access is a CLI driver, because that's what agents fundamentally know how to do: run commands.

When the CLI is the API:

  • Any language works. Shell out to boxd from Python, Node, Go, Rust, Bash, a Justfile, your grandmother's Tcl. Every command takes --json, so the output parses anywhere.
  • Agents work natively. An agent that can run shell commands can use boxd without a wrapper. No tool definition, no "teach the agent how our API works" step — it just runs boxd.
  • The documentation is self-describing. boxd --help works. So does every subcommand's --help. The tool documents itself.
  • Shell ecosystem comes free. Tab completion, shell history, piping, grep, jq on the --json output. Nothing else has that ecosystem.

What about ergonomics

This is the objection we hear most: "Python users expect Python-idiomatic wrappers."

Fair — so there's a Python SDK and a TypeScript one, each a thin layer over the same CLI and gRPC surface. Prefer to wrap it yourself in fifteen lines around subprocess? Do that instead. We shipped the primitive; you pick the ergonomics.

The inverse doesn't work. You can always wrap a CLI. You can't unwrap an SDK that hid the primitive from you.

For agents specifically

An agent is a model that types commands and reads output. That's not a metaphor — it's what the runtime actually does. Model generates a tool call, harness executes, output returns, model generates next tool call. In that shape, "run boxd machine new and read what comes back" is the simplest possible tool: it's just shell, and the model already knows shell.

Every sandbox that leads with an SDK is a layer of translation between prompt and execution. The agent decides what to do. The harness converts to an SDK call. The SDK calls the runtime. The runtime runs it. The result comes back through the same layers. Every layer is a place bugs hide and a place latency accumulates.

An agent driving boxd skips the layers. It runs a command. It reads the output. That's the entire tool interface. And once it's inside a machine — one ssh <name>.boxd away — the interface is the whole Linux userland.

A primitive, not a framework

We're not anti-SDK. Other tools ship great SDKs for different primitives — Modal's Python decorators, E2B's agent helpers. If your shape matches those primitives, those tools will beat us.

But a computer is not a framework. You don't need a Python wrapper to run a command or to log into a machine; you just run it, and you just log in. The primitive we ship is a real Linux machine. The interface is one binary — and the SSH you've used for forty years to get inside.

One CLI. --json on everything. That's the API.

For the operational consequence — what an agent harness gets when one CLI is the whole interface — read on. For how this stacks against the closest competitor by stated positioning: boxd vs exe.dev.

Read next