cps
cps gives you a hardware-isolated Linux microVM that boots instantly: root over SSH, a persistent disk, and a public HTTPS ingress — all driven from a single CLI. Machines are ephemeral by default, with automatic resource reclamation: spin one up, do your work, forget it — the TTL cleans up after you.
Under the hood it’s Firecracker + jailer: every machine is a real VM with its own kernel, isolated at the hardware level — not a container sharing a kernel with its neighbours.
Where to next
- Getting started — from install to a running machine in a couple of minutes.
- CLI reference — every command:
new,ssh,expose,snapshot,backup, and more. - API & authentication — tokens, org-scoping, and the REST API for automation beyond the CLI.
What a microVM gives you
- Instant start — boots in ~a second, not the tens of seconds of a full VM.
- Strong isolation — a dedicated kernel per machine (Firecracker + jailer); guest-to-guest networking is isolated. Not a “shared-kernel container”.
- Real Linux — root, arbitrary packages, syscalls, your own disk. Not a stripped-down sandbox.
- Persistent & portable — the disk survives restarts; snapshots/backups restore on another host.
- Ephemeral by default — a TTL reclaims resources automatically; persistent machines are
opt-in (
--ttl 0).
This is an invite-only alpha. Questions, bugs, ideas → the community chat @cps_run on Telegram.
Getting started
The path from zero to a running machine. You need an access token — the cps team issues these (invite-only alpha).
1. Install the CLI
curl -fsSL https://cps.run/install.sh | sh
The script downloads the cps binary for your OS/arch and installs it into ~/.local/bin. If that
directory isn’t on your PATH:
export PATH="$HOME/.local/bin:$PATH"
Supported: Linux and macOS, x86_64 or arm64. Verify:
cps version
2. Log in
cps login --token <your-token>
The API defaults to https://cps.run. Select your org’s project:
cps project list # shows the "default" project created for your org
cps project use <prj_id> # from the list above
3. Launch a machine
cps new ubuntu --name dev --start --wait
Defaults: 1 vCPU, 512 MiB RAM, a 4 GiB disk, and a 24h TTL (the machine auto-deletes after a day
so nothing is left running by accident). Override with --cpu, --ram 2G, --disk 10G,
--ttl 2h. Use --ttl 0 for a persistent machine that is never auto-deleted.
4. Use it
cps ssh dev # root shell over SSH
cps exec dev -- uname -a # run a one-off command
cps cp ./file dev:/root/ # copy a file in
cps expose dev 8080 # publish a port over public HTTPS
cps metrics dev # live CPU / memory
cps ps # list your machines
cps expose returns a public URL like https://rte-….cps.run that proxies to the given port
inside the machine.
5. Snapshots and backups
The machine must be stopped (cps stop):
cps stop dev
cps snapshot create dev --name base --wait # fast restore point
cps backup create dev --name daily --wait # durable off-host copy (S3)
cps snapshot restore <snap> --name dev2 --start --wait
A snapshot is a fast disk image (a restore point). A backup is a durable copy in off-host storage (S3) — it survives host loss and restores on any host in the fleet.
6. Clean up
cps rm dev --yes
Limits & etiquette (alpha)
- Your org has a resource quota and a machine-count cap.
cpswill tell you if you hit them. - Machines are hardware-isolated (Firecracker + jailer) and cannot see each other.
- Please don’t use machines for abuse (spam, scanning, mining). This is a private alpha.
- Questions, bugs, ideas → the @cps_run chat on Telegram.
Troubleshooting
cps sshhangs → Ctrl-C and retry; report persistent hangs in the chat.401/403→ your token expired or you’re pointed at the wrong project (cps project use).cps whoamishows who you’re authenticated as.
CLI reference
Every command runs in the context of the active project (see cps project use) and requires
login (cps login). The global --json flag emits machine-readable JSON instead of tables.
Environment overrides config: CPS_API_URL, CPS_TOKEN, CPS_PROJECT_ID.
Authentication & context
| Command | Purpose |
|---|---|
cps login --token <t> | Save the token and API URL to config. |
cps whoami | Show the current user/org. |
cps version | CLI version. |
cps project list | Projects in your org. |
cps project use <prj_id> | Make a project active. |
cps project create <name> | Create a project. |
Machines
cps new <image> --name <n> [--start] [--wait] [options]
| Flag | Default | Description |
|---|---|---|
--cpu <n> | 1 | vCPUs. |
--ram <n> | 512 (MiB) | Memory; accepts 2G, 512M. |
--disk <n> | 4 | Disk in GiB. |
--ttl <d> | 24h | Lifetime; 0 means persistent. Accepts 2h, 30m, 7d. |
--ssh-key <path> | — | Public key to inject. |
--region <r> | — | Preferred region/host. |
--require <label> | — | Required host labels (repeatable). |
--start | — | Start right after create. |
--wait | — | Block until ready. |
| Command | Purpose |
|---|---|
cps ps [--all] | List machines (--all includes deleted). |
cps status <m> | Detailed machine status. |
cps start <m> / cps stop <m> | Start / stop. |
cps rm <m> --yes | Delete a machine. |
cps wait <m> --timeout <s> | Block until ready. |
cps clone <src> --name <n> [--start] [--wait] | Clone a machine. |
cps console <m> | Attach to the serial console. |
Access & files
| Command | Purpose |
|---|---|
cps ssh <m> [--identity <key>] [-- <cmd>] | Root shell over SSH (via tunnel); with a command, run and exit. |
cps exec <m> [--timeout <s>] -- <cmd> | One-off command, returns stdout/stderr. |
cps cp [--recursive] <src> <dst> | Copy files (m:/path is a path inside the machine). |
cps ssh-proxy <project> <m> | Print a ProxyCommand for native ssh/scp. |
Publishing ports (ingress)
| Command | Purpose |
|---|---|
cps expose <m> <port> | Public HTTPS URL to an internal port; prints https://rte-….cps.run. |
cps routes | Active routes. |
cps unexpose <selector> | Remove a route. |
Snapshots & backups
The machine must be stopped. A snapshot is a fast restore point; a backup is a durable copy in S3 (portable across hosts).
| Command | Purpose |
|---|---|
cps snapshot create <m> --name <n> [--wait] | Take a snapshot. |
cps snapshot list [<m>] | List snapshots. |
cps snapshot show <snap> | Details. |
cps snapshot restore <snap> --name <n> [--start] [--wait] | Restore into a new machine. |
cps snapshot rm <snap> [--yes] | Delete. |
cps backup create <m> --name <n> [--wait] | Create a backup. |
cps backup list [<m>] / show <b> / restore <b> … / rm <b> [--yes] | Manage backups. |
Metrics
| Command | Purpose |
|---|---|
cps metrics <m> | Current CPU / memory. |
cps metrics <m> --history [--window <s>] | History over a window (from ClickHouse). |
cps operations | Recent async operations in the project. |
Secrets
Project secrets are encrypted at rest and available to the project’s machines.
| Command | Purpose |
|---|---|
cps secret set KEY=VALUE … | Set secrets. |
cps secret list | Secret names (no values). |
cps secret rm <name> | Delete. |
Tokens
| Command | Purpose |
|---|---|
cps token create [--name <n>] [--ttl <d>] | Issue a token (the secret is shown once). |
cps token list | Your tokens. |
cps token rm <token_id> | Revoke. |
Images
An image registry backed by S3; hosts pull an image on demand (see also the API).
| Command | Purpose |
|---|---|
cps image push <id> --kernel <vmlinux> --rootfs <ext4> [--name] [--version] [--arch] [--boot-args] | Upload and register an image. |
cps image list | Available images. |
cps image rm <id> [--yes] | Remove an image from the registry and S3. |
Administration
Requires an admin token. Not available to regular users.
| Command | Purpose |
|---|---|
cps admin org create <name> --cpu --ram --disk --max-machines | Create an org with a quota (auto-creates a default project). |
cps admin org list / usage <org> | List orgs / consumption vs quota. |
cps admin org quota set <org> … | Change a quota. |
cps admin user create <org> --name [--email] / user rm <user> | Users. |
cps admin token issue <org> <user> [--name] [--ttl] | Issue a user token. |
cps admin hosts / cps admin host <inspect|drain|cordon|uncordon|tag> <host> | Fleet management. |
API & authentication
The CLI is a thin wrapper over the control-plane REST API. You can call the same API directly for automation.
Base URL & authentication
- Base URL:
https://cps.run(override withCPS_API_URL). - Auth: the
Authorization: Bearer <token>header. Issue a token withcps token create(or, as an admin,cps admin token issue). - Scoping: a token is bound to your organization; you can only see and mutate your org’s resources.
- A token is a secret: shown once, keep it out of git, revoke with
cps token rm.
Liveness check (no auth):
curl -s https://cps.run/healthz
# {"status":"ok"}
Who am I:
curl -s https://cps.run/v1/whoami -H "Authorization: Bearer $CPS_TOKEN"
Resource model
org ──┬── project ──┬── machine ──┬── snapshot
│ │ └── backup
│ └── route (ingress) / secret
└── (quota: cpu / ram / disk / max-machines)
Almost everything is project-scoped and lives under /v1/projects/{project_id}/…. The default
project is prj_default.
Core endpoints
| Method + path | Purpose |
|---|---|
GET /v1/whoami | Current principal. |
GET /v1/projects | Org projects. |
GET /v1/projects/{p}/machines | List machines (?include_deleted=true). |
POST /v1/projects/{p}/machines | Create a machine (JSON body: image, resources, ttl…). |
POST /v1/projects/{p}/machines/{m}:start | :stop | Start / stop (async operation). |
DELETE /v1/projects/{p}/machines/{m} | Delete. |
GET /v1/projects/{p}/operations/{op} | Async operation status. |
GET | POST /v1/projects/{p}/snapshots | List / create snapshots. |
GET | POST /v1/projects/{p}/backups | List / create backups. |
GET | POST /v1/projects/{p}/routes | Ingress routes (expose). |
GET | POST | DELETE /v1/tokens | Manage tokens. |
GET | POST /v1/images | Image registry. |
Async operations
Mutating actions (create/start/stop/snapshot/backup/restore) return an operation and run asynchronously. Poll its status to wait for completion:
# create a machine → take operation_id from the response, then poll:
curl -s https://cps.run/v1/projects/prj_default/operations/$OP \
-H "Authorization: Bearer $CPS_TOKEN"
# status moves pending → running → succeeded | failed
The CLI does this for you with --wait.
Example: list machines
curl -s https://cps.run/v1/projects/prj_default/machines \
-H "Authorization: Bearer $CPS_TOKEN" | jq .
Error codes
| Code | Meaning |
|---|---|
401 | Missing/invalid token. |
403 | Token valid, but no access to the resource (another org / an admin path). |
404 | Resource not found in your scope. |
409 | State conflict (e.g. an action on a machine in the wrong state). |
429 | Rate limit exceeded; see the Retry-After header. |
The API is under active development (alpha) and may change. For stable workflows, prefer the CLI. The full request/response contract lives in the
contractsrepository.
MCP & agent runtime
cps-mcp exposes cps as Model Context Protocol
tools, so any MCP-capable agent (Claude Code, Claude Desktop, …) can create
isolated Linux sandboxes, run code in them, publish ports, and tear them down
— all over the public cps API.
A sandbox is the agent-facing name for an ephemeral machine at the MCP layer.
It’s a Firecracker microVM with VM-level isolation, a persistent disk for the task,
outbound networking, an optional HTTPS preview, and an automatic TTL — so an agent
can run untrusted code and never leak resources.
cps-mcp speaks MCP over stdio and ships inside the cps CLI — installing the
CLI installs cps-mcp too.
1. Install & get a token
Install the CLI (see Getting started for details):
curl -fsSL https://cps.run/install.sh | sh
cps version # confirms both `cps` and `cps-mcp` are installed
Log in and create a token for the agent (shown once):
cps login --token <your-token>
cps token create --ttl 24h --name mcp
2. Configuration
cps-mcp reads its settings from the environment, and falls back to your cps
CLI config after cps login (so CPS_TOKEN is optional once you’re logged in):
| Variable | Required | Default | Purpose |
|---|---|---|---|
CPS_TOKEN | yes* | — | A cps token (cpsk_…). *Optional if cps login already configured the CLI. |
CPS_API_URL | no | https://cps.run | Control-plane base URL (e.g. a lab endpoint). |
CPS_PROJECT_ID | no | auto-detected | Project to create sandboxes in; inferred from the token’s org if unset. |
3. Connect an MCP client
Claude Code — one command:
claude mcp add cps -e CPS_TOKEN=cpsk_your_token -- cps-mcp
Claude Desktop / generic MCP client — add to the client’s mcpServers config:
{
"mcpServers": {
"cps": {
"command": "cps-mcp",
"env": { "CPS_TOKEN": "cpsk_your_token", "CPS_API_URL": "https://cps.run" }
}
}
}
Verify the connection with /mcp — the cps server should show as connected with
8 tools.
4. Tools
| Tool | Purpose |
|---|---|
create_sandbox(image?, ttl_seconds?) | Boot an ephemeral microVM, wait until ready, return sandbox_id. Auto-deletes after the TTL (default 900s). |
run(sandbox_id, command[], timeout_secs?) | Run an argv array in the sandbox; returns exit_code, stdout, stderr. Not shell-parsed — use ["sh", "-c", "…"] for pipes/globs. |
write_file(sandbox_id, path, content) | Write a text file inside the sandbox. |
read_file(sandbox_id, path) | Read a text file from the sandbox. |
expose(sandbox_id, port) | Publish a port over a public HTTPS URL. |
destroy(sandbox_id) | Delete the sandbox and its routes. |
fork_sandbox(sandbox_id, ttl_seconds?) | Clone a sandbox’s disk into a new ready sandbox (briefly stops the source for a consistent copy). |
list_sandboxes() | List the sandboxes in the project. |
Typical agent flow:
create_sandbox→sandbox_idwrite_file(sandbox_id, "/root/app.py", "…")run(sandbox_id, ["python3", "/root/app.py"])expose(sandbox_id, 8080)→ public HTTPS URLdestroy(sandbox_id)(or let the TTL reap it)
5. Claude Code plugin & skill
For Claude Code, installing the cps-agent-runtime plugin gives an agent both
the cps MCP tools and the cps-agent-runtime skill, which teaches the agent
to use them correctly (TTL cleanup, argv vs shell, route reclaim on destroy).
The plugin registers the cps-mcp command — the binary must already be on PATH
(step 1). Install from the Git remote:
/plugin marketplace add https://git.codelab.vc/cps/cli
/plugin install cps-agent-runtime@cps
Or from a local checkout of the cli repository:
/plugin marketplace add /absolute/path/to/cli
/plugin install cps-agent-runtime@cps
Then ask naturally — e.g. “run this script in an isolated cps sandbox and show the
output” — and the skill drives create_sandbox → write_file/run → destroy.
6. Updating
cps-mcp, the CLI, and the plugin update independently — there is no
cps update command yet.
CLI + cps-mcp (one binary, one step) — re-run the installer, which overwrites
the binary in place, then restart your MCP client so it re-spawns cps-mcp:
curl -fsSL https://cps.run/install.sh | sh
cps version # confirm the new version
From a source checkout instead:
git pull && cargo install --path . --locked --force
Plugin + skill — refresh Claude Code’s marketplace (re-pulls the cli repo),
then re-enable the plugin:
/plugin marketplace update cps
/plugin install cps-agent-runtime@cps
/reload-plugins # apply changes without restarting the session
The plugin only registers
cps-mcp— updating the plugin does not update the binary. Update the CLI (above) to get new tool behavior.
Notes (alpha)
- Public
exposeHTTPS previews need the cps routing layer. Single-host lab deployments create the route record but do not serve traffic yet. cps-mcptalks only to the public cps API, so it works against any reachable control plane viaCPS_API_URL.- New CLI versions reach
https://cps.run/install.shonly after the cps team publishes a release — re-running the installer picks up whatever is current.