Skip to main content
A Box ships with coding-agent harnesses installed and wired up: Claude Code, Codex, pi, OpenCode, Prime Agent, and Kimi Code. box prompt hands one of them a task, streams back what it does, keeps its memory, runs many tasks at once, survives the Box stopping and resuming, and lets you switch model or harness mid-task. None of that is magic. It is exactly what you would build if you rented a bare cloud computer and put an agent on it. This page shows that boilerplate, how Box implements it, and where you plug in your own instructions, tools, keys, or even your own harness.

What you’d have to build

Put a coding agent on a plain cloud machine and you always end up writing the same pieces: You can still do any of these by hand. Box never stops you from box ssh-ing in and running whatever you like (see Bring your own harness).

How it fits together

The agent server is a small always-on process on every Box. Each conversation owns one harness process and one history. The harnesses are ordinary processes running as user in /home/user, reading ordinary config files and credentials, which is why everything below is inspectable and replaceable.

Harnesses and models

Pick the harness per prompt with --provider, or omit it to use the one you chose on the Agents dashboard. Every model accepts a different set of reasoning levels, and the catalog changes often, so it is served live rather than written here: box prompt --help prints it, GET /provider-models returns it as JSON. Change model or thinking level on any prompt, in the same conversation:

Whose keys: yours or your users’

Two situations, one mechanism. The harness reads its credentials from the Box’s environment and auth files, and Box fills those from one of two sources: Subscriptions connect on the Agents dashboard the same way for all three vendors: Claude (Pro or Max), ChatGPT (Plus, Pro or Team) and Kimi (Kimi Code). Click Sign in, approve on the vendor’s page (ChatGPT and Kimi show a short code to confirm), and the dashboard reports the subscription as connected. Box keeps the sign-in alive for you: the token is refreshed server-side before every prompt and every Box start, so a Box never comes up on an expired one. Sign out on the same row to drop it everywhere. --no-env withholds every credential of yours; the -e values are the only ones the Box ever has. That is the shape of a product where each end user brings their own key or subscription and picks a harness in a selector: Variables the harnesses read (any subset works; a harness whose vendor key is missing refuses the prompt with a credential error, the others keep working): Kimi Code reads no credential from the environment itself; the Box writes these into its ~/.kimi-code/config.toml and token file before the first prompt, then the CLI refreshes the subscription token on its own. Keys are per Box, not per conversation. A Box shared by several users runs on one set of credentials; give each paying user their own Box when their keys must stay apart, and share one Box across conversations when the keys are yours.

DeepSeek

Claude Code and Codex can run on DeepSeek’s models instead of Anthropic’s or OpenAI’s. One credential covers both: a DeepSeek platform key, a single string starting with sk-. DeepSeek publishes an Anthropic-shaped endpoint and an OpenAI-shaped one against the same key, so neither harness is modified and neither needs a gateway in front of it. What the Box exports to each harness, and which model ids to pass:
pi, OpenCode and Prime Agent reach DeepSeek a different way: through your OpenRouter key, with no DeepSeek account at all. Those models are openrouter:deepseek/deepseek-v4.1-flash, openrouter:deepseek/deepseek-v4-flash-0731 and openrouter:deepseek/deepseek-v4-pro-0813, and they need only OPENROUTER_API_KEY.

Amazon Bedrock

Claude Code and Codex can run on models served by your AWS account instead of Anthropic’s or OpenAI’s API. The simplest credential is a Bedrock API key: one string starting with ABSK, generated in the Bedrock console under API keys, valid in every region. IAM access keys (access key id, secret, optional session token) work too. What the Box exports to each harness, and which model ids to pass:

Model access is granted per AWS account and region

The catalog above lists what Amazon Bedrock offers for each harness, not what your account may call today. Bedrock grants model access per AWS account and per region, so a model is listed here as soon as Bedrock serves it, including frontier models AWS has not granted you yet. Whether you can call one is between your account and AWS. To request access: open the Amazon Bedrock console in the region your credential uses, go to Model catalog, find the model, and choose Request model access. Some models ask for a short use case form and are approved by AWS rather than instantly. Access granted in one region does not carry to another. Pick a model your account has not been granted and the prompt comes back naming the model, the reason and the fix, for example:
Two related failures read differently. A key AWS rejects outright surfaces as an authentication error, with the harness naming the endpoint it called. A model id whose region prefix does not match your credential’s region comes back as The provided model identifier is invalid: the us. profiles above only resolve from US regions, so from eu-west-1 pass eu.anthropic.claude-sonnet-4-6 instead, and likewise au. or jp.. A global. prefix works from any supported source region and needs a wider IAM policy, see global cross-region inference.

Conversations: the harness’s memory

The first box prompt on a Box starts a conversation: a thread of prompts and responses with its own memory, backed by the harness’s native session. Every later prompt continues it. You never handle the session id, but it is there when you want it: every prompt prints its conversation id (conversation: <id> under queued:, conversationId in --json and in the API response) and every event carries one.
box conversations (GET /boxes/{id}/conversations) lists them newest first with prompt count, whether a turn is running, the last harness and model, a preview of the last prompt, and which one is the Box’s current conversation. That is how a thread started yesterday, or from another shell, gets its id back for --resume. Current is per shell. Like the current Box id, the current conversation is scoped to the shell you are in: --new makes the new conversation this shell’s current one, and a bare box prompt continues it. Two shells, two people, or two machines prompting the same Box each keep their own thread and never trip over each other.

Parallel conversations

Conversations run at the same time, each in its own harness process, with isolated histories: The rules are the ones you would write yourself:
  • One turn at a time per conversation. A second prompt to the same conversation waits for the current turn, because it needs that turn’s context. Prompts to different conversations run concurrently.
  • A per-Box cap on concurrent turns, sized to the Box’s memory: a default (8 GB) Box runs roughly two dozen at once, large more, small fewer. Past the cap, prompts queue and start as turns finish; nothing is dropped. Pin an exact number with the ASCII_MAX_PARALLEL_CONVERSATIONS environment variable on the Box, or size the Box (Machine Capabilities).
  • List them with box conversations: each row says whether a turn is running in it, so you can see the parallel work at a glance.
  • Events stream all conversations by default, tagged with conversationId. Watch one with box events --convo <id>.
  • Interrupt is scoped. box interrupt --convo <id> stops one turn; the others keep running. Bare box interrupt stops everything on the Box.
  • Steer is scoped too. box steer --convo <id> "..." changes one running turn without stopping it. See Steering a running turn.

Steering a running turn

A second box prompt waits for the running turn. box interrupt throws it away. box steer is the third option: it hands the running turn a new message, the agent takes it into account, and it keeps everything it was doing. This is what typing into a coding agent while it works does.
Omit --convo and it steers the conversation this shell last prompted, exactly like a bare box prompt continues it. How it behaves per harness. Four of the six take a mid-turn message natively, so nothing is stopped. OpenCode and Kimi Code have no such primitive (their protocol has “prompt” and “cancel”, nothing in between), so Box does the next best thing transparently: A steer is always acted on, never just accepted. Handing a message to a harness is not the same as the harness doing something about it, so Box does not take the harness’s word for it. It watches the harness’s own steering queue where there is one, waits for the queue to drain before it calls the turn finished, and where it cannot see delivery it runs the instruction as its own turn the moment the turn ends. So when box steer returns and the turn later reports finished, the instruction has been carried out, not merely delivered. The API response and the event both carry native, and the event carries the exact mode: native, native-continued, fallback, or late. native-continued is the honest middle case: the harness accepted the message but its turn ended without acting on it, so Box ran it immediately as its own turn on the same session. Nothing was interrupted and nothing was forgotten, the instruction simply lands a turn boundary later. The fallback path keeps the harness session and all of its memory too, so nothing is forgotten there either; what it costs is the one tool call that was in flight, and the agent may redo a little of what it had just started. A steer is its own event in the stream, never a queued prompt:
Steering a conversation with nothing in flight is refused with no_running_turn (409). That is deliberate: you asked to change a turn that is running, and quietly queueing a new one instead would be a surprise. Use box prompt for that.

Agent lifecycle

A prompt moves through a small state machine you can observe with box events or GET /prompts/{promptId}: A steer never creates a state of its own: the turn that was already running is still the turn that finishes, and the work your message causes is part of it. The Box lifecycle sits underneath, and conversations ride along with it: Stopping snapshots the disk, including every conversation’s history and the harness’s native session files under /home/user. A resumed or forked Box restores them, so --resume <id> picks up with full memory. Processes the harness started by hand (a dev server it launched, a tunnel) do not survive a stop, same as on any reboot; conversations and every config file below do.

Switching harness or model mid-conversation

Continue a conversation on a different harness and it keeps the thread:
Box freezes the earlier harness’s transcript into the conversation and hands it to the new one, so the switch is one flag rather than a context-rebuilding script. A user-facing selector for harness and model maps directly onto provider and model on POST /prompt.

Computer use

Every Box runs a Linux desktop, and every harness on it can see and drive that desktop as ordinary tools. Nothing to install, nothing to register:
The tools come from the Cua Driver, preinstalled on every Box and registered as an MCP server named computer for all six harnesses: The daemon runs as the desktop user, so the tools act on the very screen box desktop streams: open a stream in one window and watch the agent work in it.

What the agent gets

Clicks and keystrokes are delivered in the background by default: they land on the target window without raising it or moving the real pointer, so several windows can be driven without a focus fight. When a widget only accepts input while focused, the tool says so and the agent can retry with delivery_mode: "foreground", which activates the window, acts, and puts focus back. Tool names reach box events namespaced by the harness, for example mcp__computer__click on Claude Code and Kimi Code, and mcp:computer/click on Codex.

Where it is registered

The registration is an ordinary entry in each harness’s own config file, written for you at Box start, and merged with anything you put there yourself: Your own MCP servers in those files are untouched. Remove computer from a file and that harness simply loses the tools; it is rewritten on the next Box start, so delete the Box’s daemon if you want it gone for good. One tool, browser_prepare, is switched off for OpenCode in opencode.json tools, because OpenCode forwards MCP tool schemas to the model provider unchanged and the Anthropic API rejects that tool’s schema, which would otherwise fail every OpenCode turn on an Anthropic model. Prime Agent reaches the server from inside its Python tool, as await mcp.call_tool("computer", "click", {...}).

Practical notes

  • One screen, shared. All conversations on a Box drive the same desktop. Two agents clicking at once will fight over it. Give each parallel GUI task its own Box, or serialize them.
  • It survives stop, resume and fork. The daemon is a systemd user service on the Box, brought back automatically. The socket lives on /run, so a resumed Box never inherits a stale one.
  • Logins persist. A Chrome profile the agent signed into is part of the Box’s disk, so it comes back on resume and travels to a fork.
  • Screenshots are large. A full-desktop screenshot is a real image in the model’s context. Ask for a specific window (get_window_state with a window id) when a task loops.
  • Watch it, and record it. Open the stream with box desktop to see the agent work, and capture the run to an MP4 with ascii-record-desktop. See Desktop Streaming.
If a prompt says it has no computer tools, check the daemon:

Customize the harness

Every harness reads its own config files from the Box home. Box adds nothing on top except its own short system prompt (which tells the harness it is running headless in a Box and that the box CLI exists) and the box skill. Everything else is yours to add, over box ssh, box exec, box scp, a file the agent writes, an environment setup script, or a named snapshot so every new Box starts with it. All of it was verified end to end through box prompt on the current harness versions; each row names the file that made the harness change its answer.

Instructions and hidden rules

Drop a rules file and every prompt on that Box obeys it, without the prompt mentioning it: One ~/AGENTS.md plus one ~/CLAUDE.md therefore covers all six. APPEND_SYSTEM.md (pi, Prime) is appended to the system prompt itself rather than to the project context. When an environment clones a single repository, Claude Code starts inside that repository, so a CLAUDE.md there applies too.

MCP servers

Remote (HTTP) servers work the same way with a URL instead of a command. Claude Code’s MCP resource browsing tools are disabled on a Box; MCP tools are not. Every Box already has one server registered this way, computer, in exactly these files. Adding yours next to it changes nothing about it, and it never overwrites yours. See Computer use.

Reach your own app from the Box

A Box has no route back to your laptop, so an MCP server, a local model, or a webhook receiver running on localhost is invisible to the agents inside it. box forward --reverse opens that route: a port on your machine starts answering at 127.0.0.1:<port> inside the Box, over the same SSH session box ssh uses, with nothing exposed publicly on either end.
Register it once inside the Box and every harness can call it:
The registration lives in the Box home, so it survives box stop, box resume, and box fork; the tunnel does not, and has to be started again next time you want the agent to reach you. A local model works the same way: box forward <id> --reverse --local 11434 puts Ollama on http://127.0.0.1:11434 inside the Box, ready for any harness pointed at that base URL. See box forward --reverse for the flags and the redial behaviour. Products that do not ship the CLI get the same tunnel in three lines, because the CLI is only wrapping stock OpenSSH:

Skills

A skill is a folder with a SKILL.md (frontmatter name and description, then the instructions). Every harness on a Box already has a skills directory with the box skill in it; add yours next to it:

Command-line tools

Anything on PATH is a tool. Put a script in ~/.local/bin or /usr/local/bin (or npm i -g, pip install, apt install it) and ask for it by name; all six harnesses run it through their shell tool.

Custom in-process tools and extensions

For a tool that should show up as a native function call rather than a shell command:

What is shared, what persists

  • Config is per Box, not per conversation. Every parallel conversation on a Box, whatever its harness, reads the same home directory: one AGENTS.md, one skills folder, one MCP list. Per-user rules need per-user Boxes, or rules stated in the prompt.
  • Everything in /home/user is captured on stop. Rules, MCP registrations, skills, extensions, tools you installed under home, and the harness sessions all come back on box resume and box fork. Tools installed outside home (apt, /usr/local) are part of the system snapshot too.
  • Bake it once. An environment setup script or a named snapshot gives every new Box the same rules, tools, and servers from the first prompt.

Bring your own harness

Box’s built-in harnesses are ordinary binaries on PATH with the same credentials the agent server uses. Three ways to go beyond box prompt:
  • Drive a built-in harness yourself. box ssh or box exec and run claude, codex, pi, opencode, prime-agent, or kimi directly, in any mode they support. The agent server does not lock the files or the processes.
  • Install a harness Box does not ship. box exec "npm i -g <harness>" (or bake it into an environment or snapshot) and drive it over box exec or SSH. It coexists with the built-in ones and reads the same per-Box -e keys.
  • Run your own agent loop. Put a small HTTP daemon in the Box and talk to it directly: the Platform Guide walks through it. box host gives it a URL, Webhooks tell your control plane when the Box is up.
Whatever you run, box events, attachments under ~/attachments, desktop streaming, snapshots, and forks keep working around it.

Reference