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 asdev.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 asps 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:
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/shmand/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
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 andlazycloud 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
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.