Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

CLI: runner

The customer CLI over the public API. (Not runnerctl, the operator's host-local tool.) Every flag below was checked against runner <command> -h.

Environment

Variable
RUNNER_API_URLThe API root, such as https://api.example.com. Required.
RUNNER_API_KEYAn API key with the scopes the command needs.
RUNNER_SSH_ADDRSSH gateway host:port. Default: the API's host, port 2222.

Output and exit codes

Built for programs:
  • A command's result is JSON on stdout. exec and cp move raw bytes.
  • A failure is one JSON line on stderr, {"error":{"code","message","remedy"}}, with the API's typed code (errors.md). Exit 1.
  • exec exits with the command's own exit status; its own failures exit 125, as do ssh's.
  • A usage mistake prints usage, then the invalid_argument line; exit 2. Running with no command prints the command list and exits 2.

Commands

create

runner create [flags] creates a sandbox and waits until it runs, then prints it.
Flag
-template NAME[:TAG]Required; there is no default. A host template (default, coding-agents) or one of yours.
-vcpus N, -memory MiB, -disk MiBDefault: one slot's.
-meta k=vMetadata, repeatable.
-env k=vEnvironment for every process, repeatable.
-allow-domain HOSTRepeatable; then only these hostnames are reachable over HTTP(S).
-idempotency-key KEYA retried create returns the first one's sandbox.
-lease-seconds NHow long the sandbox lives unless renewed: 60 to 604800. Default: the API's, one hour.
-public-port NPublish a port at create; repeatable. Needs the previews scope and previews enabled.
-no-waitReturn at once, still allocating.
-wait-timeout DURDefault 5m0s; exceeded is the timeout error.
runner create -template default -lease-seconds 7200 -env API_TOKEN=abc -allow-domain pypi.org
Template note. The API requires a template and has no default, and the CLI adds none: runner create without -template fails with the API's invalid_argument. See api.md for the shipped definitions.

renew

runner renew ID SECONDS moves the sandbox's lease to SECONDS (60 to 604800) from now, not from the current deadline, and prints {"generation","expires_at"}. Only a renewal extends a lease (leases).

get, delete

runner get ID and runner delete ID print the sandbox. Delete returns immediately (the sandbox is destroying).

exec

runner exec [flags] ID CMD [ARG...] streams stdout to stdout and stderr to stderr, and exits with the command's status. CMD is a program, not a shell line: runner exec ID sh -c 'a | b'.
Flag
-cwd DIRWorking directory.
-user NAMEThe sandbox user to run as.
-env k=vRepeatable.
-timeout DURKill after this long; the timeout error. 0: no limit.
-jsonPrint the API's NDJSON events instead of the output.
Put flags before ID; everything after CMD belongs to the command.

cp

runner cp [flags] SRC DST: exactly one side is ID:/path (scp style); - is stdin or stdout.
runner cp ./app.py sbx_123:/workspace/app.py runner cp sbx_123:/workspace/out.csv - # to stdout runner cp sbx_123:/workspace/out.csv ./ # into a directory
Flags: -mode 0644 (octal, uploads), -user NAME. A broken download leaves no partial file.

files

runner files <sub> [flags] ID ..., JSON on stdout where there is a result:
ls ID PATHList a directory.
stat ID PATHDescribe a path.
mkdir [-mode 0755] ID PATHMake a directory.
mv ID FROM TOMove.
rm [-r] ID PATHRemove; -r for a directory tree.
All take -user NAME.

logs

runner logs ID prints {"events": [...]}, the sandbox's lifecycle log (needs the exec scope; see GET .../events in api.md).

ssh

runner ssh [flags] ID [COMMAND [ARG...]] grants a key through the API and runs the system ssh through the gateway (so ssh must be installed).
Flag
-i KEYFILEUse this private key (its .pub is granted). Default: a throwaway key for this session.
-ttl DURGrant lifetime. Default: the API's, an hour.
-o OPTAn ssh -o option, repeatable.
The gateway's host key is checked as ssh always does, and there is no pinning yet. An unattended caller has nobody to answer the first-login prompt, so pass -o StrictHostKeyChecking=accept-new (or manage your own known_hosts). There is no PTY: a shell runs over pipes.

templates

runner templates <sub>; see api.md for what the pieces are.
listYour templates.
build [flags] NAMEBuild a version and follow its log (to stderr), then print the finished build. A failed build exits 1 with its typed error.
builds NAMEBuilds, newest first.
status NAME BUILDOne build.
logs [-from N] [-json] NAME BUILDA build's log, followed to the end.
cancel NAME BUILDCancel a running build.
versions NAMEVersions and tags.
tag NAME TAG VERSIONPoint a tag at a version (a rollback, for latest).
build flags: -f FILE (Dockerfile, default Dockerfile, - is stdin), -tag TAG (default latest), -ready CMD, -disk MiB, -arg k=v (repeatable), -no-follow, -json.
runner templates build -f Dockerfile -ready 'test -x /usr/bin/python3' mytool runner create -template mytool