Freestyle Docs

Freestyle / Docs

VM CLI

Create and operate VMs, snapshots, terminals, and guest files with the Freestyle CLI.

The VM CLI accepts either a VM ID or your team-local slug wherever it asks for <vmId>. See Freestyle CLI for installation and authentication.

Create, List, And Inspect

freestyle vm create --slug development --display-name "Development VM"
freestyle vm list
freestyle vm get development

create is the default action: freestyle vm --slug development creates a VM.

At a terminal, vm create opens a shell in the new VM, which keeps running after you exit. --no-ssh prints the record instead. Scripts, CI, and coding agents get the record without passing anything.

A new VM can reach the Internet. --no-internet leaves it with no outbound access. Inbound access is separate: see Firewall.

If --slug is already taken, the CLI asks whether to take it from the VM holding it, which keeps running without a slug. --replace-slug answers yes up front. Scripts, CI, and coding agents get an error naming the flag instead of a question.

freestyle vm create --snapshot-id freestyle/ubuntu --slug builder
freestyle vm create --vpc private --ipv4 10.40.0.10
freestyle vm create --slug scratch --no-ssh

Use repeatable --metadata key=value flags on create or update. Filter lists with --state, --slug, --snapshot-id, or comma-separated --metadata key:value pairs.

Run Commands

Put the guest command after -- so its flags are passed through unchanged:

freestyle vm exec development -- uname -a
freestyle vm exec development --timeout-ms 60000 \
  --env NODE_ENV=production -- npm test -- --runInBand

vm exec streams stdout and stderr, then exits with the guest command’s exit status. Allocate an interactive PTY with -it:

freestyle vm exec -it development -- bash
freestyle vm exec -it development --linux-user developer -- python3

For a login shell, use freestyle vm ssh development. Despite the name, the CLI opens the same Freestyle PTY API directly and does not need a local SSH key. The session runs bash where the guest has it, and the login shell where it does not.

Update And Lifecycle

freestyle vm update development --display-name "Build worker" \
  --idle-timeout-seconds 600 --metadata environment=staging
freestyle vm resize development --cpu 8 --memory 16384 --storage 81920
freestyle vm pause development
freestyle vm start development
freestyle vm delete development

Memory and storage are measured in MiB. Resizing is grow-only.

Snapshots

Capture a VM you already have, and manage the snapshots you keep:

freestyle snapshot create development --slug configured-worker
freestyle snapshot list --source-vm-id development
freestyle snapshot get configured-worker
freestyle snapshot update configured-worker --display-name "Configured worker"
freestyle snapshot delete configured-worker

snapshot create returns once the snapshot is materialized and ready to boot from. Each of these is also available as freestyle vm snapshot ....

Taken slugs work as they do for VMs: the CLI asks, --replace-slug answers yes up front, and the snapshot that held the slug keeps its data under its id.

Without --slug, snapshot create offers to name the snapshot once it exists. Press Enter to leave it addressable by id.

Build A Snapshot From Scratch

Without a VM, snapshot create boots one, opens a shell in it, captures it when you exit, and deletes the VM. create is the default action here too, so freestyle snapshot --slug configured-worker says the same thing:

freestyle snapshot create --slug configured-worker

--base sets the snapshot to start from. The VM has Internet access; --no-internet removes it:

freestyle snapshot create --base freestyle/ubuntu-lg --slug build-box

A command after -- runs in place of the shell, with your keyboard attached to it. The VM is captured when the command exits:

freestyle snapshot -- claude login
freestyle snapshot --slug configured-worker -- npm install -g @anthropic-ai/claude-code

--script runs a local script instead, streamed to your terminal as it runs. A script with a shebang runs under it; one without runs under bash, or sh on a guest without bash:

freestyle snapshot create --script ./setup.sh --slug configured-worker

A command or script that exits non-zero deletes the VM and takes no snapshot, as does Ctrl-C during a script. --keep-vm keeps the VM instead.

Building by hand requires a terminal. In CI, in a pipeline, or under a coding agent, snapshot create requires a command or --script unless you pass --interactive.

Files And SCP

freestyle vm fs write development /root/app.tar ./app.tar
freestyle vm fs read development /var/log/app.log --out ./app.log
freestyle vm fs ls development /root
freestyle vm fs mkdir development /root/output
freestyle vm fs stat development /root/app.tar
freestyle vm fs rm development /root/output

freestyle vm scp ./app.tar development:/root/app.tar
freestyle vm scp development:/var/log/app.log ./app.log
freestyle vm scp ./site development:/srv/site
freestyle vm scp development:/root/results ./results

A directory copies recursively, in either direction. A destination that already exists as a directory receives the copy under the source’s own name, so scp ./site development:/srv writes /srv/site.

scp and the fs commands operate as root inside the VM, while vm exec and vm ssh run as the VM’s default user (uid 1000, or root where the image has no such account). A file you copy in is therefore root-owned: chown it with freestyle vm exec <vm> --linux-user root "chown ubuntu:ubuntu /path" if the default user needs to write to it.

The filesystem commands stream large files and use the SDK’s resumable upload transport automatically.

JSON Output

--output is a global option. Use it instead of the removed --json flag:

freestyle --output json vm list | jq '.vms[] | {id, state}'
esc