← Guides

Guide

Pi Coding Agent — Run the Pi CLI in a Hosted Cloud Workspace

Pi is an open-source terminal coding agent from Earendil Works, published as @earendil-works/pi-coding-agent and run as pi. It has read, bash, edit and write tools, session management, and an extension system. This guide covers what Pi is, how to run it in a managed cloud workspace, how to point it at a model, how to drive it non-interactively, and the one thing about its security model you should understand before pointing it at a repository.

What Is Pi?

Pi is a coding agent you run in a terminal. You give it a task in natural language and it reads files, runs shell commands, and edits code to carry the task out — the same shape as Claude Code, Codex CLI, OpenCode or Aider. It is MIT licensed and developed in the open, and it ships as a single npm package with a pi binary.

Two things distinguish it in practice. First, it is broadly model-agnostic: Pi reads provider API keys straight from the environment and supports a long list of providers rather than being tied to one vendor's models. Second, it is deliberately minimal about permissions — which is a real strength when you run it in the right place, and a real hazard when you do not. Both are covered below.

Running Pi in a Coding Workspace

A Coding Workspace is a managed cloud dev box with the major terminal coding agents pre-installed. Pi is one of them, so there is nothing to install: you pick Pi when you deploy the workspace, open the browser terminal, and run it.

  1. Open your dashboard and deploy a Coding Workspace.
  2. Choose Pi from the coding agent dropdown before you deploy.
  3. Open the workspace terminal and run pi to start an interactive session, or pi "your task here" to give it a task straight away.

Your code lives in /workspace, which persists across a reset of the box. Sign-ins and CLI config live in the home directory, which also persists — so you authenticate once rather than on every rebuild.

Already have a workspace?

Pi is only present in workspaces created from the image that includes it. A box you created earlier runs the image it was built from, so it will not have pi on its path yet. Hit Reset on the workspace to move it to the current image — a reset keeps both your code in /workspace and your CLI logins, and only replaces the box around them. If you trigger a Pi run through the API against a workspace that predates it, the API answers with a harness_unavailable error telling you to reset, rather than failing halfway through the run.

Pointing Pi at a Model

Pi picks a provider from the API keys it can see in the environment, and --model selects a specific model. It accepts a plain pattern, a fully qualified provider/id, and an optional thinking level:

pi --model <provider>/<model-id> "Refactor the auth module"
pi --model sonnet:high "Work out why this test is flaky"
pi --list-models              # see what your keys unlock
pi --provider openrouter      # pin a provider explicitly

The simplest route is an OpenRouter key, which gives one credential covering many models. How you supply it depends on how you are running Pi, and the two paths are deliberately different:

  • In the workspace terminal — sign in with /login, or export the key yourself. A key saved on your account is not pushed into the box automatically: keys are never injected under the names a CLI reads, because an environment key silently overrides a sign-in you did yourself and quietly moves your billing. Pi keeps its own credentials in the persisted home directory, so a one-time sign-in survives a reset.
  • On an API run — save the key under API Keys, then pass "use_saved_key": true on the request. Without that flag the run uses whatever login already lives in the box. It is opt-in per request rather than an account setting, for the reasons in the security section below.

See API keys and bring your own key for how key storage works.

One detail worth knowing: pi --help shows a default provider, but that default only applies when nothing else is available. With a single provider key present, Pi selects that provider on its own — you do not have to pass --provider to make an OpenRouter key work.

Non-Interactive and Scripted Runs

Pi has a normal interactive terminal UI, and three modes for running it without a human present:

  • -p / --print — run the prompt, print the answer, exit.
  • --mode json — emit every event as JSON lines, for programmatic consumption.
  • --mode rpc — RPC mode, for integrating Pi into another process.

Print mode also reads piped stdin and merges it into the prompt, which makes it easy to feed a file or the output of another command into a task:

cat CHANGELOG.md | pi -p "Summarise this for a release note"
pi -p --mode json "List every TODO in src/ with file and line"
pi @src/auth.ts @src/session.ts "Review these two files together"

The @file syntax attaches specific files to the prompt. Sessions can be continued with -c, resumed with -r, or kept out of history entirely with --no-session.

You can also start Pi runs from outside the box entirely. The workspace API accepts a harness of pi, starts the run in the background, and hands back a run id you poll for progress and log output — useful for wiring an agent into CI or a script.

Extensions and Skills

Pi has a package system for extending what it can do. Extensions are TypeScript modules; skills, prompt templates and themes can also be loaded from files or directories.

pi install <source>     # add a package
pi list                 # what is installed
pi update --extensions  # update packages only
pi --skill ./my-skill   # load a skill for one run

Project-local extensions and settings are gated behind a trust decision, which matters for the security model below.

Security: Pi Has No Built-In Sandbox

This is the most important thing to understand about Pi, and its own documentation is direct about it: Pi does not include a built-in sandbox. Its tools read files, write files, and run shell commands with the permissions of the user that started it, and extensions run with the same permissions. Pi treats real isolation as the operating system's job rather than something it can meaningfully provide in-process.

Upstream's own recommendation is that untrusted repositories, unmonitored work, and unattended automation should run Pi inside a container or VM with only the files and credentials the task needs. That is exactly what a Coding Workspace is: a container per workspace, running as a non-root user, with dropped Linux capabilities, no access to the host Docker socket, resource caps, and its own volumes. Your own machine stays out of reach — your laptop's files, your SSH keys and your browser profile are not in the box and cannot be touched by a run.

Be clear about what that does not cover, because a container is a boundary around your machine, not around your credentials. Anything the workspace itself holds is inside the blast radius: the CLI logins kept in its persisted home directory, any key you export in its terminal, and — on an API run you explicitly fund with a saved key — that key too. The agent runs with approvals bypassed and the box has outbound internet, so a prompt injection carried in repository content could read a credential and send it somewhere. Those credentials work outside the box, which is precisely why this matters.

The practical rules that follow: keep the credentials you put in a workspace scoped to what the work needs, prefer a key you can rotate cheaply over one that unlocks everything, and treat a run over an untrusted repository as something to review rather than trust. For API runs, funding with your saved key is opt-in per request rather than an account-wide setting for this exact reason — you decide, run by run, whether the prompt is trustworthy enough to hold the key.

Project trust is a separate, narrower control: it decides whether Pi loads settings and extensions that a repository ships with, so cloning a repo cannot silently change how your agent behaves. In the non-interactive modes it never stops to ask — by default those project-local resources are simply ignored, and --approve / --no-approve override that for a single run. Note that this guards what Pi loads, not what the model does once it is running; prompt injection from repository content is a real risk for every agent of this kind.

How Pi Compares

Pi occupies a similar space to the other terminal agents, with different emphases:

  • Claude Code and Codex are tied to one vendor's models and have the deepest integration with them. Pi is provider-agnostic by design.
  • OpenCode is the closest comparison — open source and model-agnostic. See OpenClaw vs OpenCode.
  • Aider is the most git-centric of the group, built around commits and diffs. See OpenClaw + Aider.

Because a Coding Workspace ships all of them, you do not have to choose in advance — you can run Pi on one task and a different agent on the next, in the same box, against the same code.

A Coding Agent Is Not a Chatbot

Pi is a coding tool: you drive it from a terminal, and it stops when the task stops. If what you want is an assistant that stays online and answers messages on Telegram, Discord, WhatsApp or WeChat, that is a different product shape — see what OpenClaw is. The two pair well: an agent for always-on chat, a workspace for the coding work.

Related Guides