# Quickstart In about five minutes you'll install the CLI, sign in, start a full Ubuntu VM, run commands in it, move files, open a port, run an agent, stop and resume it, fork it, and clean up. Then you'll do the same from code. Every command on this page is run by HareBox's test suite against a live server. **You need** a HareBox account with a plan, or the 7-day trial. The trial needs a card, charges nothing until day 7, and includes 25 hours of machine time. See [Pricing](../start/pricing.html) and [Free trial](../start/trial.html). ## 1. Install the CLI On Linux or macOS: ```sh curl -fsSL https://harebox.com/install.sh | sh ``` The installer picks the build for your system, **checks that HareBox signed it before installing anything**, and puts `harebox` in `~/.local/bin` without root. Set `HAREBOX_INSTALL_DIR` to install somewhere else, or `HAREBOX_VERSION` to pin a version. On Windows, download `harebox_windows_amd64.zip` from [harebox.com/releases](https://harebox.com/releases/latest/VERSION). The installer and `harebox self-update` check that HareBox signed the release before anything is installed. The list of SHA-256 sums is signed with HareBox's release key (OpenSSH signature format, checked with `ssh-keygen -Y verify`), and so is the pointer to the latest version. The CLI never moves to an older release unless you pass `--version`. Set `HAREBOX_SKIP_SIGNATURE=1` only if you can't install `ssh-keygen` and have checked the download some other way. Keep it current with `harebox self-update`, which checks every download the same way. `harebox version` prints what you have. ## 2. Sign in Create an API key in the [dashboard](https://app.harebox.com/), under **API keys**, then give it to the CLI on stdin, so it never lands in your shell history: ```sh harebox login --key-stdin ``` Paste the key and press Enter. The CLI saves it in its config file. You can also set `HAREBOX_API_KEY` instead, which wins over saved settings, as `HAREBOX_API_URL` does for the API address (`https://api.harebox.com` by default). Check who you are: ```sh harebox whoami ``` **Are you an agent?** Run `harebox login --agent`. It signs you up and prints a `claim_url` for your human, who claims the account and adds a card. See [Sign up from an agent](../start/agent-signup.html). ## 3. Start a sandbox ```sh harebox new --name first ``` `harebox new` returns when commands will work, and prints the machine's hourly price. It also remembers the sandbox as `current` in this folder, so the next commands don't need its ID. | You get | | |---|---| | Machine | A full VM with its own Linux kernel, on KVM. Not a container | | System | Ubuntu 24.04 LTS, systemd, passwordless `sudo` for the `user` account | | Size | `default`: 4 vCPU, 8 GB RAM, 51 GB disk, at $0.03564 an hour. See [Sizes](../reference/sizes.html) | | Inside | Docker with Compose, nested `/dev/kvm`, Node, Python, Go, Rust, Bun, Java, Chrome, VS Code in the browser and agent CLIs. See [Base image](../reference/base-image.html) | | Auto-stop | One hour after it starts or resumes, so a forgotten sandbox stops by itself. Change it with `--ttl SECONDS`, or `--no-auto-stop` | | Billing | Per second, from the moment a machine is assigned until a stop begins. Egress is free | Pick another size with `--size small|default|large|xlarge`, or any shape such as `--size 6c12g`. ## 4. Run commands ```sh harebox exec current -- uname -a harebox exec current -- echo "hello from the VM" ``` `harebox exec` streams output as it arrives and **exits with the command's own exit code**, so it works in scripts and CI as is. A waiting command can run for up to an hour; for anything longer, detach it and check on it later: ```sh CMD=$(harebox exec current --detach -- sleep 1 | jq -r .id) harebox exec current "$CMD" --status ``` Every command is kept in the sandbox's history: `harebox history current`. ## 5. Move files ```sh echo "notes for the agent" > notes.txt harebox file write current --path /home/user/notes.txt --from notes.txt harebox file read current --path /home/user/notes.txt ``` To copy a whole project, use `harebox push current .`. It skips `.git` and `node_modules`. ## 6. Open a port ```sh harebox host current 3000 --title Preview ``` This prints a private HTTPS URL for port 3000. Anyone with the full URL can open it, so treat it like a password; rotate it with `harebox host rotate`. If the sandbox is asleep, the first request wakes it. See [Public endpoints](endpoints.html). ## 7. Run a coding agent Connect your model key once. It's stored outside your sandboxes: they only ever see a placeholder, and the credentials proxy adds the real key on the way out. See [Credentials proxy](../agents/credentials-proxy.html). ```sh harebox ai key set default anthropic-api-key --value "$ANTHROPIC_API_KEY" harebox proxy rule add --secret-ref anthropic-api-key --host api.anthropic.com --header x-api-key --template "{secret}" ``` Then give an agent a task, with a spending cap. Events stream back as it works: ```sh harebox prompt current "Clone github.com/acme/app, fix the failing test, and open a pull request" --harness claude --budget 3 ``` The `shell` harness needs no key, so you can try the whole pipeline right now: ```sh harebox prompt current "echo hello from a turn" --harness shell --budget 1 ``` Add guidance mid-turn with `harebox steer`, or stop it with `harebox interrupt`. The next prompt continues the same conversation; `--new` starts another. See [Harnesses](../agents/harnesses.html). ## 8. Stop and resume ```sh harebox stop current harebox resume current ``` **Stop** saves the whole disk and ends the bill. The disk is kept free for 14 days, then moves to paid cold storage instead of being deleted. **Resume** brings it back with your files, packages and enabled services. To keep running programs and memory as well, put it to **sleep** instead. A sleeping sandbox is billed like a running one and still stops at its auto-stop, so use sleep for short breaks: ```sh harebox sleep current harebox wake current ``` ## 9. Fork it ```sh harebox fork current --count 2 ``` Each fork is an exact copy: files, installed packages and, from a running sandbox, its memory and programs. Each gets its own identity, IP and disk, so forks never share secrets or step on each other. Give each one a different task. See [Parallel agents](parallel-agents.html). ## 10. Clean up ```sh harebox list harebox delete current ``` `harebox delete` erases the disk, memory and every snapshot by destroying the sandbox's encryption key. It can't be undone, so stop instead when you might come back. Set a budget so nothing runs away while you're learning: ```sh harebox budget new --limit 25 --action stop ``` ## From code Every CLI command is an API call. The base URL is `https://api.harebox.com/v1`, and every request carries `Authorization: Bearer $HAREBOX_API_KEY`. Create a key for code with a narrow preset, such as `harebox api-key new --name ci --preset ci`. See [API keys](../account/api-keys.html). ### HTTP ```sh ID=$(curl -fsS -X POST "$HAREBOX_API_URL/v1/sandboxes" \ -H "Authorization: Bearer $HAREBOX_API_KEY" -H "Content-Type: application/json" \ -H "Idempotency-Key: quickstart-$RANDOM-$RANDOM" \ -d '{"name": "from-http", "ttl_seconds": 3600}' | jq -r .id) curl -fsS -X POST "$HAREBOX_API_URL/v1/sandboxes/$ID/commands" \ -H "Authorization: Bearer $HAREBOX_API_KEY" -H "Content-Type: application/json" \ -d '{"command": "echo hello"}' | jq -r .stdout ``` A command waits for the sandbox to be ready, for up to 60 seconds. Send the same `Idempotency-Key` when you retry a create, and the retry never makes a second machine. ### Python ```sh pip install harebox ``` ```python from harebox import HareBox hb = HareBox() # reads HAREBOX_API_KEY, and HAREBOX_API_URL if set box = hb.create(name="from-python", ttl_seconds=3600) print(box.run("echo hello")["stdout"]) for event in box.prompt("echo hi", harness="shell"): print(event["type"]) box.stop() ``` ### TypeScript ```sh npm install @harebox/sdk ``` ```ts import { HareBox } from "@harebox/sdk"; const hb = new HareBox(); // reads HAREBOX_API_KEY, and HAREBOX_API_URL if set const box = await hb.create({ name: "from-typescript", ttl_seconds: 3600 }); console.log((await box.run("echo hello")).stdout); for await (const e of box.prompt("echo hi", { harness: "shell" })) console.log(e.type); await hb.stopSandbox(box.id); ``` Every API operation is also a typed method, such as `hb.get_limits()` in Python and `hb.getLimits()` in TypeScript. Errors carry a `code` and a `fix`. See [SDKs](../reference/sdks.html). ## If something goes wrong | You see | It means | Do this | |---|---|---| | `card_required` | The trial starts machines once a card is on file | A person adds one with `harebox billing card` | | `invalid_credential` | No key, or an expired or revoked one | `harebox login --key-stdin`, or set `HAREBOX_API_KEY` | | `start_rate_limited` | You've used this minute's starts | Wait `retry_after_seconds`, or send `--queue` to wait in the free queue | | `sandbox_starting` | It's still booting after 60 seconds | Retry the same request | | `budget_exceeded` | A budget you set stopped it | Raise the budget with `harebox budget set` | | A turn fails with an install hint | That harness's CLI isn't in the machine | `harebox exec current -- harebox-harness install NAME` | Every error has a `fix` field that says what to do next, and a `docs_url` that links to [its entry in the error reference](../reference/errors.html). When in doubt, run `harebox doctor current`. ## Next - [Concepts](../start/concepts.html): every word, defined once - [Lifecycle](lifecycle.html): every state, and what survives each change - [Environments](environments.html): repositories, secrets and setup scripts for new sandboxes - [Templates](templates.html): save a prepared machine and start from it in one call - [An agent on your repository](agent-on-repo.html) and [parallel agents](parallel-agents.html) - [One sandbox per end user](sandbox-per-user.html): build a product on HareBox - [Use HareBox from your coding agent](../agents/use-from-your-agent.html) - [Limits](../reference/limits.html) and [errors](../reference/errors.html)