Skip to main content
app.devbox(...) declares a container you reach over SSH whose root filesystem is a disk. It runs while something is connected and stops after 30 idle minutes. Packages, dotfiles and code stay on the disk from one start to the next, on whichever machine it lands.

Define one

Save this as dev.py:
lazycloud devbox box ssh opens a shell as root in /root. The app’s source is not mounted, so git clone your code onto the disk. The image needs no sshd. disk= sizes the root disk, which is named after the devbox. It takes at least 10Gi, plus room for the image’s unpacked root, which the first start copies onto it. A disk too small for its image fails the deploy with the size to set. Disks bill for what they store, not their size, so headroom costs nothing. Disk pricing covers the rates.

Find and inspect boxes

list shows deployed devbox names and apps in the current workspace; status shows a box’s live state and resources. Neither starts a sleeping box. --app picks the app when several share a name, --workspace picks another workspace, and both take --json. A page holds up to 100 boxes; --limit shrinks it and --cursor with the returned next value continues.

Coding agents

When the image builds, a devbox installs Codex, Claude Code, OpenCode, Pi, Node.js 22, Git, and the process utilities the selected agents need, such as ps for Codex. The SDK pins the agent and Node.js versions. agent_harnesses=[AgentHarness.Codex], with AgentHarness imported from lazycloud, installs only Codex; agent_harnesses=[] installs none, which Image.from_id() and images that supply their own tools need. Installation needs a Debian or Ubuntu image with root build access. After deploying, sign an agent in from an interactive terminal on your laptop:
The command checks that the agent and the system commands it needs are on the devbox. If any is missing, it stops and prints the install instructions to run there; it installs nothing itself. It then runs the agent’s own login on the devbox and opens your laptop’s browser, with SSH carrying the localhost callback back, so no public ports entry or device code is needed. The agent saves its credentials on the devbox disk, outside the image. When the login ends, the command says whether the agent saved a new login and, if not, the command to retry. After a login it offers to open a shell on the devbox. Running it again signs the agent in again, which is how you switch accounts. Codex and Claude Code stay open after you sign in, so the command closes them. For Claude Code it also skips the first-run setup. Project trust and permission prompts still appear when Claude starts. OpenCode prompts for a provider and login method; pick browser login. In Pi, run /login, pick the provider’s browser login, and exit Pi. Methods depend on the provider, and API keys can come through secrets instead. Browser login needs OpenSSH on a macOS, Linux, or WSL computer, so it runs locally, not in a dashboard terminal. Where no browser opens, such as over SSH, open the link the agent prints in any browser; Claude Code then shows a code to paste at its prompt. One login at a time per port; a port a local service already holds fails the command before the browser opens. Anyone with access to the devbox can read its saved credentials, so separate accounts get separate devboxes.

What persists

Everything under / is on the disk, except:
  • /dev/shm and /volumes: memory, empty on each start
  • Volumes you attach: kept in the volume
  • /artifacts: the app’s artifacts, read-only
  • /etc/hosts, /etc/resolv.conf, /run/lazycloud: rewritten on each start

What a devbox defaults to

deploy prints the resolved settings: disks= adds more disks at other paths. Other options work as they do on a pod.

Remote editors

This adds a host named lazycloud-<workspace>-<app>-<name> for each devbox to ~/.ssh/config, so VS Code and Cursor Remote-SSH list it and plain ssh works. Connections go through the LazyCloud API with a short-lived certificate the config refreshes, so there are no keys to copy.

When it runs

Connecting starts a stopped devbox, and the terminal shows each step until it is up. An open SSH session keeps it running; the idle time counts from when the last one closes. On the devbox’s dashboard page, Start boots it and Stop ends it. After three failed starts in a row a devbox stops trying, and its page and lazycloud devbox box status show the last failure. Fix the cause, then Start or a new connection tries once more. Within about 20 seconds of the last failed start, Start returns that error instead of trying again.

Stop and clean up

Stopping or deleting the devbox keeps its disk; deleting the disk removes its files.

The same thing as a pod

A devbox is a pod with a role. app.pod(ssh=True, disks=[Disk("box-root", size="100Gi")], command=["sleep", "infinity"]) builds the same machine with pod defaults, for when you need ports beside SSH or several named disks.