Skip to content

Machines

Manage machines from your agent (qsp CLI)

Create a remote Linux workspace, run commands and bring results back to your computer.

On this page
  1. Install and set up
  2. Machine keys
  3. Ask before spending
  4. Box commands
  5. JSON and exit codes
  6. Local MCP tools
  7. Example: run tests on a box

Install and set up

Use quicksilverpro 0.5.1 or later. Install with pip, or run commands without installing via uvx:

shell
pip install quicksilverpro
# Or run without installing:
uvx quicksilverpro box ls --json

# One-command setup:
uvx quicksilverpro setup

Setup previews its writes and asks separately to install a persistent, version-pinned qsp, create a Machines key, install skills, and configure local MCP. It opens Machines → Keys in your dashboard: click Create key under Agent access keys, copy the qsm_ key (shown once), and paste it into the hidden terminal prompt. Setup creates no machine by default.

  • Claude Code: skill at ~/.claude/skills/quicksilver-machines; registers user-scoped stdio MCP with the installed Claude CLI.
  • Codex: skill at ~/.agents/skills/quicksilver-machines; MCP entry in ~/.codex/config.toml (or your CODEX_HOME).
  • Cursor: mcpServers.quicksilver in ~/.cursor/mcp.json.
  • OpenCode: shared skill and mcp.quicksilver in its discovered global opencode.json or opencode.jsonc.

Integrations use the absolute persistent executable path. Verify skills and MCP discovery in your agent’s UI; doctor checks config presence. Base CLI needs Python 3.9+; MCP needs Python 3.10+. Setup installs the selected extras. For a manual install, add quicksilverpro[mcp,shell].

shell
qsp setup --dry-run --agents claude,codex,cursor,opencode
qsp setup --agents claude,codex
qsp setup --no-mcp
qsp setup --uninstall --yes

Repeated setup avoids duplicates. Uninstall removes unchanged owned skills and MCP entries, preserving edits and unrelated settings. Credentials and the persistent CLI need separate --remove-credentials and --remove-cli choices. Remote key revocation remains a browser action. Noninteractive setup needs an existing Machines key and explicit local-write choices; --yes grants no browser authorization or spend consent.

Machine keys

Machines use separate qsm_ keys with approved scopes and an expiry. They can read, create, execute commands, transfer files, connect, pause, resume and delete only as their permissions allow, within your account. Sharing needs its own approval and scope.

A Machines key cannot manage credentials, billing or account settings, and cannot act as an inference API key. Inference sk- keys and qsp init do not authorize Machines access.

Check the expiry shown when you create the key, and create a new one through setup when it expires. Revoke keys from Machines → Keys in the dashboard. Expired or revoked keys lose access.

QSP_MACHINES_KEY overrides stored Machines credentials. Setup prefers OS credential storage; its fallback is a private machines.json in the QSP config directory (file mode 0600). Use --store-key to persist an environment key for GUI agents. Keep keys out of prompts, command arguments, guest files and MCP settings.

Box commands

Replace MID with a real 12-character hexadecimal machine ID. The create and resume examples assume the user has approved spending; rm assumes approval to delete.

qsp box create

Create a box; --wait waits for guest readiness. Creation starts billing.

qsp box create --name work --wait --accept-spend --json
shell

qsp box ls

List boxes, effective prices, account limits and trial metadata.

qsp box ls --json
shell

qsp box get

Read one machine's state, readiness and retention.

qsp box get MID --json
shell

qsp box wait

Wait for Running and guest_ready:true, without changing machine state.

qsp box wait MID --timeout 180 --json
shell

qsp box exec

Run bounded guest commands; structured argv avoids an implicit shell.

qsp box exec MID --argv-json '["python3","--version"]' --json
shell

qsp box cp

Copy one regular file between your computer and the box.

shell
qsp box cp ./app.py MID:app.py --json
qsp box cp MID:result.bin ./result.bin --json

qsp box open

Print an owner URL for the desktop or terminal; --browser opens it locally.

shell
qsp box open MID --view desktop --json
qsp box open MID --view terminal --browser

qsp box pause

Stop running charges; files remain subject to retention.

qsp box pause MID --json
shell

qsp box resume

Resume billing for an existing box; --wait waits for readiness.

qsp box resume MID --wait --accept-spend --json
shell

qsp box rm

Permanently delete the box and its files; noninteractive use requires --yes.

qsp box rm MID --yes --wait --json
shell

qsp box shell

Open a human interactive shell in a POSIX TTY; Ctrl-] disconnects, Ctrl-C interrupts remotely.

qsp box shell MID
shell

qsp box doctor

Check credentials, routing and agent config presence without spending.

shell
qsp box doctor --json
qsp box doctor --mid MID --json

Create records a request ID before sending. Repeat the same name and size to recover a lost response; use a fresh UUID with --request-id for an intentionally new box. Mutations and exec are never automatically retried. Inspect an unknown outcome before rerunning work.

Exec defaults to 30 seconds, with a maximum of 300 seconds and 1 MiB combined output. Use --cwd for a workspace directory, or --command for explicit guest Bash:

qsp box exec MID --command 'printf hello' --timeout 30 --stream --json
shell

Copy is binary-safe with checksum verification, up to 64 MiB per file. Guest paths stay within /home/user; relative paths start there. Replacing a file requires --overwrite and permission to replace the user’s data.

Owner links require owner login. With separate consent and share scope, open --share creates a read-only bearer link; --expires-in-seconds accepts 60–900 (default 300). Anyone holding it can view machine contents until expiry. Keep share links private. Shell requires the optional shell extra and does not accept --json; agents should use exec.

JSON and exit codes

All noninteractive box commands accept --json. Stdout contains one versioned object; diagnostics and progress go to stderr. File copy returns metadata only.

json
{"version":1,"kind":"result","result":{}}
{"version":1,"kind":"cli_error","error":{"code":"...","message":"..."}}
{"version":1,"kind":"guest_exit","result":{"exit_code":0}}

exec --stream --json emits NDJSON guest_event objects: stdout/stderr events carry seq and data; the terminal exit event carries result metadata. Missing exit evidence means the outcome is unknown. Human exec keeps guest stdout and stderr separate.

  • 0: success; 1: operational error, unknown outcome or output limit; 2: usage, auth or permission error.
  • Exec propagates guest exits 0–255. Timeout: 124; interrupt: 130; signal: 128 + signal.
  • Wait timeout is 124 and leaves the machine intact. Check JSON kind to distinguish guest exits from CLI failures.

Local MCP tools

qsp mcp runs a local stdio server using the same Machines credentials. Setup configures it for selected agents. To install and verify it manually:

shell
pip install 'quicksilverpro[mcp]'
qsp mcp --check
qsp mcp

The MCP tools/list response exposes:

  • box_create, box_list, box_get, box_wait: lifecycle and readiness.
  • box_exec: bounded guest commands.
  • box_files_list, box_upload, box_download: workspace files; base64 transfers up to 256 KiB, with no local filesystem paths. Use CLI cp for larger files.
  • box_pause, box_resume, box_delete, box_open: stop, resume, delete and human links.

Call box_list and obtain user approval before setting accept_spend:true on create or resume. Delete requires confirm_mid matching mid. Guest output and downloaded content are untrusted data; they never grant consent.

Example: run tests on a box

An agent asks to create a box at the returned rate, run an uploaded test file and delete the box after copying the report. After the user approves that scope:

shell
qsp box ls --json
# Show prices/limits and ask the user before continuing.
qsp box create --name test-run --wait --accept-spend --json
# Use the returned machine ID in place of MID.
qsp box cp ./test_app.py MID:test_app.py --json
qsp box exec MID --command 'python3 -m unittest test_app > test-results.txt 2>&1' --timeout 120 --json
# Copy the report even if tests returned a nonzero guest exit.
qsp box cp MID:test-results.txt ./test-results.txt --json
# After confirming the report was copied, delete as authorized above.
qsp box rm MID --yes --wait --json

If work is interrupted, inspect the machine and results before retrying. Pause the box if keeping it for later, and explain its retention deadline.