ooga

Docs

ooga gives every agent its own Linux virtual machine. Each sandbox is a full Ubuntu 24.04 VM with its own kernel, public IP and disk, driven from the ooga CLI or the HTTP API.

Install

The installer downloads the CLI for your platform, checks its SHA-256 and puts it in ~/.local/bin. Set OOGA_BIN_DIR to install somewhere else, or OOGA_VERSION=v0.1.0 to pin a version. There is no native Windows build yet: on Windows, use the CLI inside WSL.

Quickstart

ooga is invite-only during the beta. Once you're invited, sign in to the dashboard with Google and create an API key there.

# paste an API key from the dashboard; also registers ~/.ssh/id_ed25519.pub
$ ooga login

# a running VM in about 10 seconds, then a root shell
$ ooga new my-box
$ ooga ssh my-box

# run commands without SSH, from scripts or agents
$ ooga exec my-box -- 'git clone https://github.com/you/app && cd app && make test'

# snapshot the disk and stop billing; ooga start my-box resumes
$ ooga stop my-box

A new sandbox finishes installing its toolchain in the background for a few minutes after it starts. ooga exec my-box -- cat /var/lib/ooga/status prints ready when it's done.

Sandboxes

Each sandbox is a VM with a dedicated public IPv4 and IPv6 address. You log in as root with your SSH keys; password login is disabled. The SSH host key is generated by ooga and pinned by the CLI, so ooga ssh and ooga scp verify the machine they connect to.

Sizes

SizevCPUMemoryDisk
small24 GB40 GB
default48 GB80 GB
large816 GB160 GB
xlarge1632 GB320 GB

vCPUs are shared. Pick a size with ooga new NAME --size large.

What's installed

Ubuntu 24.04 with Docker (and Compose), Node.js 22, Bun, Python 3.12, Go, Rust, build-essential, git, the GitHub CLI, Google Chrome, tmux, ripgrep and jq, plus the Claude Code, Codex and OpenCode CLIs.

Idle auto-stop

A sandbox that sees no API activity for its TTL (default 1 hour) is stopped automatically, which snapshots its disk first, so nothing is lost. An open ooga ssh session keeps it awake. Set the TTL with ooga new NAME --ttl 4h, or --ttl 0 to never auto-stop.

Pricing

SizevCPU / memory / diskPer hourAlways on, per month
small2 / 4 GB / 40 GB$0.025about $18
default4 / 8 GB / 80 GB$0.035about $26
large8 / 16 GB / 160 GB$0.06about $44
xlarge16 / 32 GB / 320 GB$0.12about $88
  • You pay while a sandbox runs. Each run (new, start, fork or restore) is billed for at least one hour, then per second.
  • Stopped sandboxes and automatic snapshots are free. Saved snapshots cost $0.056 per snapshot per day.
  • In any month you use ooga, the minimum charge is $20, which includes that much usage. A month without usage costs nothing.
  • On your own Hetzner, Hetzner bills you for the servers and ooga charges a platform fee per running hour, billed per second with no minimum: $0.005 (small), $0.01 (default), $0.02 (large), $0.04 (xlarge).

ooga usage shows this month's usage and charges. Add a card with ooga billing before starting sandboxes: it opens a Stripe page in your browser, and ooga never sees your card number. Invoices are charged to the card at the start of each month; ooga billing portal changes the card or downloads invoices.

Snapshots & forks

A snapshot is a copy of the sandbox's whole disk.

  • Automatic snapshots are taken every hour while a sandbox runs, and when it stops. The 3 most recent are kept. They're free.
  • Saved snapshots are kept until you delete them: ooga snapshot my-box --name before-upgrade.
$ ooga snapshots my-box                        # list
$ ooga fork my-box@before-upgrade my-box-2     # new sandbox from a snapshot
$ ooga fork my-box try --count 5               # try-1 … try-5
$ ooga restore my-box@before-upgrade           # roll back in place

restore snapshots the current state first, so a restore can itself be undone. ooga stop snapshots the disk and deletes the VM, and ooga start brings it back from that snapshot: the disk is identical, but the IP address changes.

Snapshots copy the full disk, so they take time: in our tests about 35 seconds for a 3 GB disk, longer as the disk fills. Forks and starts take about 20–30 seconds. Stopping takes about 2 minutes.

Coding agents

ooga prompt runs a coding agent inside the sandbox and streams its output to your terminal:

$ ooga prompt my-box "make the failing tests pass"
$ ooga prompt my-box "add a /health endpoint" --agent codex

Agents: claude (default), codex, opencode. Each agent needs its own login inside the sandbox: run ooga ssh my-box and start the agent once to sign in, or export its API key (for example ANTHROPIC_API_KEY) in /root/.bashrc.

You can also run your agent on your own machine and give it the sandbox as a tool: ooga exec and the HTTP API return stdout, stderr and the exit code.

Desktop

$ ooga desktop my-box

Opens the sandbox's desktop (XFCE) in your browser over noVNC, tunnelled through SSH, so nothing is exposed to the internet. The first run installs the desktop, which takes a couple of minutes.

Your own Hetzner

Run sandboxes in your own Hetzner Cloud project instead of ooga's. Hetzner bills you for the servers; ooga charges a platform fee per running hour, billed per second with no minimum.

$ ooga hetzner connect --location nbg1   # prompts for a Read & Write API token
$ ooga new my-box                        # now created in your project
$ ooga hetzner status
$ ooga hetzner disconnect                # after deleting those sandboxes

Create the token in the Hetzner Console under Security → API tokens, ideally in a project used only for ooga. ooga checks the token before saving it and stores it encrypted. ooga creates only servers named ooga-… and snapshots; please manage them with ooga rather than in the console. Locations: fsn1, nbg1, hel1.

CLI reference

ooga loginSave your API key and register your SSH public key.
ooga new [NAME]Start a sandbox. --size, --ttl, --count N, --no-wait.
ooga list · ooga status NAMEShow sandboxes.
ooga ssh NAME [-- CMD]Open a shell, or run a command over SSH.
ooga scp SRC DESTCopy files: ooga scp ./f box:/root/ or ooga scp box:/root/f .; -r for directories.
ooga exec NAME -- CMDRun a command through the API (no SSH needed). --timeout SECS.
ooga prompt NAME "TEXT"Run a coding agent and stream its output. --agent claude|codex|opencode.
ooga desktop NAMEOpen the desktop in your browser. --port.
ooga snapshot NAMESave a snapshot. --name LABEL; --delete SNAPSHOT.
ooga snapshots NAMEList snapshots.
ooga fork NAME[@SNAP] NEWNew sandbox from a snapshot (default: the current state). --count N.
ooga restore NAME@SNAPRoll back in place.
ooga stop NAME · --allSnapshot and stop billing.
ooga start NAMEResume from the latest snapshot.
ooga delete NAMEDelete a sandbox and all its snapshots. -y skips the prompt.
ooga keys list|add|rmManage the SSH keys allowed into your sandboxes.
ooga hetzner connect|status|disconnectUse your own Hetzner project.
ooga usage [--month YYYY-MM]This month's usage and charges.
ooga billing · ooga billing portalAdd a card (opens your browser) · change it, pay or download invoices.

Every command accepts --json for machine-readable output. The CLI reads OOGA_API_KEY and OOGA_API_URL from the environment, which overrides ~/.config/ooga/config.json.

HTTP API

Base URL https://api.ooga.sh/v1. Authenticate with an API key from the dashboard as a bearer token. Requests and responses are JSON; errors look like {"error": {"code": "...", "message": "..."}}.

$ curl -s https://api.ooga.sh/v1/sandboxes \
    -H "Authorization: Bearer $OOGA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"name": "ci-1", "size": "small"}'

$ curl -s https://api.ooga.sh/v1/sandboxes/ci-1/exec \
    -H "Authorization: Bearer $OOGA_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{"command": "uname -a", "timeout_secs": 60}'
{"exit_code":0,"stdout":"Linux ooga-… 6.8.0 …\n","stderr":""}

Creating, starting, forking and restoring return 402 Payment Required until a card is on file, or while an invoice is overdue. Creating, stopping, starting, forking and restoring return 202 Accepted and continue in the background; poll GET /v1/sandboxes/{name} until state is running or stopped.

GET/sandboxesList sandboxes
POST/sandboxesCreate: {name?, size?, ttl_secs?, count?}
GET/sandboxes/{name}Show one
DELETE/sandboxes/{name}Delete it and its snapshots
POST/sandboxes/{name}/execRun a shell command: {command, timeout_secs?} (max 3600)
POST/sandboxes/{name}/promptRun an agent to completion: {prompt, agent?, timeout_secs?}
POST/sandboxes/{name}/stopSnapshot and stop
POST/sandboxes/{name}/startStart from the latest snapshot
POST/sandboxes/{name}/fork{name, snapshot?, count?}
POST/sandboxes/{name}/restore{snapshot} (id or label)
GET/sandboxes/{name}/snapshotsList snapshots
POST/sandboxes/{name}/snapshotsSave one: {label?}
DELETE/sandboxes/{name}/snapshots/{snap}Delete a snapshot
GET/sandboxes/{name}/sshSSH host, user, port and pinned host key
POST/sandboxes/{name}/touchReset the idle timer
GET · POST/ssh-keysList · add {name, public_key}
DELETE/ssh-keys/{id}Remove a key
GET/accountYour account and limits
GET · POST/api-keysList · create {label?} (the key is returned once)
DELETE/api-keys/{id}Revoke a key
PUT · DELETE/account/hetznerConnect {token, location?} · disconnect your Hetzner project
GET/usage?month=YYYY-MMUsage and charges
GET/billingPayment status: {enabled, card_on_file, exempt, suspended}
POST/billing/setup · /billing/portalA Stripe page URL to add a card · manage billing

Limits

  • 5 sandboxes running at once per account by default. Ask us to raise it.
  • Sandbox names: 1–40 characters, lowercase letters, digits and dashes.
  • Up to 100 sandboxes per new or fork call; up to 20 SSH keys.
  • exec output is capped at 1 MiB per stream; timeout up to 1 hour.
  • Abuse such as crypto mining, spam or network scanning gets accounts suspended.