> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hiloop.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Run a sandbox as a devbox

> Keep one long-lived sandbox as your remote development environment, using the ordinary sandbox verbs.

A devbox is not a separate product surface. It is a plain sandbox you keep around: durable storage
so your working tree survives a stop, managed SSH for a real shell, and the ordinary lifecycle
verbs to park it when you are done for the day.

This guide walks that setup with the verbs that work today, then says plainly what a sandbox still
does not do for a development loop, so you can decide whether it fits yours.

<Note>
  The shell in this guide needs the sandbox SSH endpoint, which an operator enables per deployment
  and which is off by default. On the hosted service it is currently enabled only in pre-release
  environments. Where it is off, a connect is refused with `unsupported_capability`. The
  authoritative status list is [what's live today](/sandboxes/overview#whats-live-today).
</Note>

## Create it once

```sh theme={null}
hiloop sandbox create devbox --storage-class durable --cpus 4 --memory-mb 8192
```

`--storage-class durable` is the part that makes this a devbox rather than a scratch sandbox. It
mounts `/workspace` as storage with its own lifetime, so files written there survive a stop and
survive losing the sandbox's node. Everything outside `/workspace` comes back from the image.

Leave `--ttl` off. An omitted TTL takes the deployment's default lifetime, which on the hosted
service is none, so the sandbox lives until you delete it. `sandbox get` shows the result in its
`expires` field.

With no `--image`, the sandbox starts from the platform default image: a Debian base carrying
Python, Node, `git`, `gcc`, `make`, and an SSH client, so you can clone a repository and build it
without installing anything first. Check [what does not work yet](#what-does-not-work-yet) before
you invest in a long setup script.

## Work in it

```sh theme={null}
hiloop sandbox ssh devbox
```

That is an interactive shell over stock OpenSSH, with no key for you to manage and no host-key
prompt. Everything after `--` is passed to `ssh`, so the usual flags work:

```sh theme={null}
# Run one command and take its exit code.
hiloop sandbox ssh devbox -- 'cd /workspace/api && cargo test'

# Reach a dev server running inside the sandbox at http://localhost:3000.
hiloop sandbox ssh devbox -- -L 3000:127.0.0.1:3000 -N
```

For scripted, non-interactive work, `exec` avoids a session entirely and returns the command's real
exit code with stdout and stderr kept separate:

```sh theme={null}
hiloop sandbox exec devbox --timeout 600 -- bash -lc 'cd /workspace/api && cargo build --release'
```

`ssh` and `exec` land in the same container and see the same filesystem, so a file you write over
SSH is visible to the next `exec`.

## Get code and files in and out

Your `/workspace` starts empty. `hiloop sandbox cp` fills it, in either direction, with `-r` for
directories. Write the sandbox side as `<sandbox>:/absolute/path`:

```sh theme={null}
# Local to sandbox.
hiloop sandbox cp ./train.py devbox:/workspace/train.py
hiloop sandbox cp -r ./dataset devbox:/workspace/dataset

# Sandbox to local.
hiloop sandbox cp devbox:/workspace/results.csv ./results.csv
hiloop sandbox cp -r devbox:/workspace/out ./out
```

Each copy prints what landed:

```
devbox:/workspace/dataset  4.2 MB in 1.6s (2.6 MB/s)
```

`cp` needs nothing installed inside the sandbox: the sandbox serves the SFTP subsystem itself, so a
copy works against any image, and it keeps working after a stop, when anything you installed
yourself is gone. A transfer interrupted by a transient network failure is retried automatically.

The sandbox path must be absolute, and exactly one of the two paths must name a sandbox. Copying a
directory without `-r` is refused rather than silently skipped.

Plain `scp` and `sftp` work too, for the same reason, if you would rather drive them yourself. Both
take their remote-shell program as a path and do not split it into words, so give them a one-line
wrapper on your `PATH` — `exec hiloop sandbox ssh "$@"` — and pass that to `-S`.

**For a repository, clone rather than copy.** A copy pays a network round trip per file, so a large
working tree is slow to push file by file — a ten-thousand-file checkout takes tens of minutes. The
default image carries `git`, so cloning into `/workspace` from inside the sandbox, over the
sandbox's own outbound network, is much faster. Use `cp -r` for directories you cannot clone:
build outputs, datasets, config, results.

`rsync` is different. It runs itself on both ends, so it needs the `rsync` binary in the sandbox,
and the default image does not carry one. Given that, point its `-e` straight at the CLI:

```sh theme={null}
rsync -av -e "hiloop sandbox ssh" ./myproject/ devbox:/workspace/myproject/
```

Anything you install with a package manager lands outside `/workspace` and is therefore lost on the
next stop, `rsync` included. Keep the setup in a script under `/workspace` and re-run it after a
start, or stay on `sandbox cp`, which needs no installation.

For large, versioned data shared across many sandboxes, the intended home is a volume
(`hiloop volume create` / `push`) rather than a per-sandbox copy. Volumes can be created, pushed,
and read back today, but mounting one into a sandbox is still refused, so a volume is not yet a way
to get data into a devbox.

## Park it and pick it up

```sh theme={null}
hiloop sandbox stop devbox
hiloop sandbox start devbox
```

Stopping releases the compute. `/workspace` reattaches on the way back with your files intact.

```sh theme={null}
hiloop sandbox list
hiloop sandbox get devbox
hiloop sandbox delete devbox
```

Delete is permanent and releases the durable `/workspace` with it. To keep a devbox's workspace
beyond the sandbox, or to branch it, snapshot it and create from the snapshot:

```sh theme={null}
hiloop sandbox snapshot create devbox --name configured
hiloop sandbox create devbox-experiment --from configured
```

Snapshots capture disk, not processes; see
[snapshots and branching](/concepts/workspaces).

## What does not work yet

These are current limitations, not settings you can change. They are the difference between this
setup and a long-lived virtual machine.

**A stop loses your processes, not just your foreground shell.** Only files under `/workspace`
survive. A running build, a dev server, a `tmux` session, and anything you installed into the
system directories are all gone on the next start, and your shell begins again from the image. You
get your files back, not your session. Plan on a start-up script rather than expecting to resume
where you left off.

**A start can report `running` before the sandbox can actually serve.** `sandbox start` returns
quickly, and `sandbox get` reads `running`, but the first `exec` or `ssh` afterwards can be refused
for up to about two minutes while the previous instance finishes releasing its storage. If a
connect fails right after a start, wait and retry rather than treating the sandbox as broken.

**The default image has no `rsync`.** It carries Python, Node, `git`, `gcc`, `make`, and an SSH
client, so you can clone a repository and build it without installing anything. `rsync` is the
exception: it has to run on both ends of the connection, and the image does not include it. Use
`hiloop sandbox cp`, or plain `scp`/`sftp`, all of which work against any image — or install
`rsync` in the sandbox and remember that a stop will lose it.

**An image has to keep a process running.** A sandbox lives exactly as long as its first process,
so an image whose entrypoint exits immediately, which is true of most base images, fails to start.
Give it something long-running after `--`:

```sh theme={null}
hiloop sandbox create dev --image ubuntu:24.04 -- sleep infinity
```

**Volume mounts are refused.** The `volume` verbs publish and version data, but naming one with
`--volume` at create is refused with `unsupported_capability`, so bulk data has to come in with
`sandbox cp` for now, per sandbox rather than shared between them.
