# Use Slicer

> Use Slicer to launch, name, tag, prepare, and cold-fork Linux microVMs for sandboxed builds, E2E tests, Docker, headless browser and DOM rendering, CI, and isolated development — works from macOS and Linux hosts

- Skill: `slicervm/use-slicer` (Agent Skill, multi-file: 17 files)
- Install (CLI): `npx skillmds@latest add slicervm/use-slicer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/slicervm/use-slicer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- Author: slicervm (https://skillmd.com/u/slicervm)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/slicervm/use-slicer

---


# Use Slicer — Launch Linux MicroVMs

Slicer gives you instant Linux microVMs through Firecracker on Linux and Apple
Virtualization on macOS. Use it when you need:

- A real Linux environment with systemd, Internet access, and SSH preinstalled (especially from macOS)
- Sandboxed builds, CI, or E2E tests
- Docker/container workflows with port forwarding
- Isolated environments for untrusted or destructive operations
- Kubernetes (k3s) clusters for testing
- GPU/PCI passthrough workloads (via cloud-hypervisor backend)
- Automated code review pipelines in ephemeral microVMs
- Preparing one builder VM, then cold-forking clean runners without repeating setup
- Running coding agents in isolated microVMs (Amp, Claude Code, Codex, OpenCode, GitHub Copilot CLI) then copying out the outcome - code, files, reports, binaries, images, etc.

VMs boot in 1–3 seconds, have full systemd, internet access, and SSH pre-installed.

Docs: https://docs.slicervm.com
Go SDK: https://github.com/slicervm/sdk (`github.com/slicervm/sdk`)

On macOS, the CLI drives **Slicer for Mac** — a persistent Linux VM plus an `sbox` host group for sandboxes. See [references/macos.md](references/macos.md).

## Install or update Slicer itself

Use Slicer's own installation and update paths. **Never run `arkade get
slicer`**: Slicer is not an arkade tool. Use arkade for other CLI tools when
appropriate, including tools installed inside a guest, but do not infer that
it installs or upgrades Slicer.

Fresh Linux installation (and the Slicer CLI on macOS):

```bash
curl -sLS https://get.slicervm.com | sudo bash
```

Update an existing installation atomically, then verify it:

```bash
sudo slicer update
slicer version
```

For a non-destructive side-by-side version test, let the installed Slicer
client fetch the correct OS/architecture binary into a temporary directory:

```bash
TEST_DIR=$(mktemp -d)
slicer update --version 0.1.216 --path "$TEST_DIR"
"$TEST_DIR/slicer" version
# Remove TEST_DIR after testing.
```

Follow the official [Linux installation
guide](https://docs.slicervm.com/getting-started/install/) or [Slicer for Mac
installation guide](https://docs.slicervm.com/mac/installation/) for platform
setup, dependencies, storage backends, licensing, and daemon installation.

## Reference files

Deeper material is split into reference files — read the relevant one when a task calls for it:

- [references/macos.md](references/macos.md) — Slicer for Mac (slicer-mac)
- [references/daemon-setup.md](references/daemon-setup.md) — generate a config and run your own daemon
- [references/workflows.md](references/workflows.md) — worked recipes (E2E, Docker, builds, k3s, DB, SSH)
- [references/custom-images.md](references/custom-images.md) — select a published Ubuntu, Rocky Linux, or Arch base image; custom rootfs images; and userdata
- [references/bg-exec.md](references/bg-exec.md) — background exec detail
- [references/file-transfer.md](references/file-transfer.md) — binary and recursive copies, exclusions, destinations, and legacy-agent compatibility
- [references/arkade.md](references/arkade.md) — installing CLI tools with `arkade get` (one call, parallel downloads, `tool@version` pinning)
- [references/interactive-tui.md](references/interactive-tui.md) — driving interactive TUIs and coding agents (guest tmux via exec, or host tmux + vm shell)
- [references/networking.md](references/networking.md) — bridge, isolated, and macvtap (LAN-direct) networking
- [references/headless-browser.md](references/headless-browser.md) — render post-JavaScript DOM and screenshots with a lean, real browser inside a VM
- [references/headless-x11.md](references/headless-x11.md) — run X11 applications headlessly with Xvfb and capture terminal video with ffmpeg (Slicer for Mac and Slicer for Linux)
- [references/vm-names-and-tags.md](references/vm-names-and-tags.md) — friendly CLI names, canonical hostnames, mutable tags, and raw API lookup
- [references/agent-sandboxes.md](references/agent-sandboxes.md) — coding-agent sandbox detail
- [references/cold-forking.md](references/cold-forking.md) — cache a prepared builder and fork clean runners

Companion skills: **`use-slicer-worktrees`** (git worktrees in a VM), **`use-slicer-proxy`** (filtered egress + secret injection).

### Direct guest-agent administration

Normal automation should use the host-side `slicer vm` commands in this
skill. If a task genuinely needs to administer `slicer-agent` from inside a
guest, generate and load its version-matched guidance first:

```bash
mkdir -p ~/.config/opencode/skills/use-slicer-agent
slicer-agent skill > ~/.config/opencode/skills/use-slicer-agent/SKILL.md
```

That generated skill covers the complete guest CLI and, in particular, the
boundary between CA-only setup and transparent proxy installation. Do not
infer a DNS-only mode from `slicer-agent proxy install --dns`: proxy install
always manages the HTTP/HTTPS OUTPUT redirects, while `--dns` only toggles
the additional DNS listener.

## Prerequisites — You Need a Running Daemon

Slicer is **not a SaaS** — it requires a running daemon that manages VMs.

### Deterministic Workflow (Default)

For agent tasks that can create infrastructure, use this default pattern:

1. Reuse the session VM when already known. Otherwise choose a unique friendly reference, pass it as the `--name` input, and add a descriptive workflow tag.
2. Capture the generated `.hostname` output separately for diagnostics and raw API/SDK calls. Do not try to extract the friendly name from launch output: the agent chose it before launch.
3. Pass the friendly reference to subsequent `exec`, `bg`, `cp`, `fs`, `shell`, health, logs, and lifecycle commands.
4. Tag VMs so they are identifiable later, for example `workflow=<slug>`.
5. Run in-VM commands with native `slicer vm` operations (`exec`, `bg exec`, `cp`, `shell`).
   - Use `slicer vm exec` for short, atomic commands.
   - Use `slicer vm bg exec` for long-running processes (dev servers, builds) that should survive client disconnect — check back with `bg logs`, `bg wait`, and clean up with `bg kill` + `bg remove`.
   - Use `slicer vm shell` for long sessions or multiple related commands (interactive PTY).
6. Prefer native Slicer commands over SSH even when SSH is available.

Example:

```bash
WORKFLOW=ci-$(date +%Y%m%d-%H%M%S)
# Reuse the friendly reference if already set for this run.
if [ -n "${SLICER_SESSION_VM_REF:-}" ]; then
  VM_REF="$SLICER_SESSION_VM_REF"
  VM_HOSTNAME="${SLICER_SESSION_VM_HOSTNAME:-}"
else
  VM_REF="$WORKFLOW" # input chosen here; --name stores it as name=<value>
  VM_HOSTNAME=$(slicer vm add sbox --name "$VM_REF" \
    --tag "workflow=$WORKFLOW" --wait --json | jq -r '.hostname')
  export SLICER_SESSION_VM_REF="$VM_REF"
  export SLICER_SESSION_VM_HOSTNAME="$VM_HOSTNAME"
fi

# Keep using the friendly reference, not the generated hostname.
slicer vm exec "$VM_REF" --uid 1000 -- "uname -a"
slicer vm cp ./local.txt "$VM_REF":/tmp/local.txt --uid 1000
# for longer interactive work, open a shell session instead of repeating many one-off execs:
slicer vm shell "$VM_REF" --uid 1000

# use exec for deterministic one-liners; use shell for ongoing interactive workflows
```

### Connecting to a daemon

**macOS — slicer-mac.** If slicer-mac is installed the daemon is already running and the socket auto-detects — no flags needed. Launch sandboxes into the `sbox` host group. See [references/macos.md](references/macos.md).

**Slicer Box — hosted.** A managed instance included with Slicer Home Edition — one persistent VM (2 vCPU, 4GB RAM, 10GB disk) over HTTPS:

```bash
export SLICER_URL=https://box.slicervm.com
export SLICER_TOKEN_FILE=~/.slicer/gh-access-token   # a GitHub personal access token
```

You get one VM to recycle; its disk persists between sessions (installed packages, files, services). Factory-reset by `slicer vm delete VM_REF` then `slicer vm launch` + `slicer vm ready`.

**Existing Linux daemon.** Connect to a daemon already running locally or on the LAN. **Ask the user** for the URL and token path — don't guess.

```bash
# Local unix socket (no auth; may need sudo to read the socket)
export SLICER_URL=/path/to/slicer.sock

# Local or remote TCP
export SLICER_URL=http://127.0.0.1:8080
export SLICER_TOKEN_FILE=/var/lib/slicer/auth/token   # may need sudo to read
# or pass the value directly:
export SLICER_TOKEN=$(sudo cat /var/lib/slicer/auth/token)
```

Check for a running daemon with `ps aux | grep -E "slicer|firecracker" | grep -v grep`. If the user supplies `SLICER_TOKEN` / `SLICER_TOKEN_FILE` or a specific endpoint, use those exactly and do not infer defaults.

### Plain HTTP on a trusted LAN

For a non-local `http://` API URL, Slicer warns that the connection is not
encrypted. In CLI 0.1.216 and later, the warning goes to stderr so JSON stdout
remains pipeable:

```bash
slicer vm group --json | jq -r '.[].name'
```

Do not use `2>&1 | jq`: that deliberately merges the warning and real errors
into jq's JSON input. On an explicitly trusted LAN, suppress only the warning
when quiet stderr is required:

```bash
export SLICER_TLS_WARN=0       # "false" also disables it
export SLICER_TLS_WARN=1       # restore warnings; unsetting it does the same
```

Suppression does not encrypt the connection; prefer HTTPS outside a trusted
LAN. CLI 0.1.215 and earlier may print this warning to stdout. If
`2>/dev/null` still leaves `Warning: Slicer URL...` in a JSON pipeline, run
`slicer version` and update the client rather than filtering non-JSON lines.

**No daemon running?** To generate a config and start your own — locally or over SSH — see [references/daemon-setup.md](references/daemon-setup.md).

### Verify connectivity

```bash
slicer info --url "$SLICER_URL" --token-file "$SLICER_TOKEN_FILE"
```

Every `slicer vm` subcommand accepts `--url` and `--token-file` (or `--token`).

---

## CLI shortcuts you should surface

Slicer exposes a few **top-level shortcuts** for common VM operations (not for every `slicer vm ...` subcommand). Prefer showing these when they match what the user asked for:

- `slicer ls` is a shortcut for `slicer vm list` (and `slicer vm list` itself has aliases `ls`/`l`)
- `slicer shell` is a shortcut for `slicer vm shell`
- `slicer cp` is a shortcut for `slicer vm cp`
- `slicer bg` is a shortcut for `slicer vm bg` (so `slicer bg exec`, `slicer bg logs`, etc. all work)

The `slicer vm` command group itself also has aliases: `slicer vm` == `slicer v`.

---

## Working with VMs

### List VMs and host groups

```bash
slicer vm list --url "$SLICER_URL" --token-file "$SLICER_TOKEN_FILE"
slicer vm group --url "$SLICER_URL" --token-file "$SLICER_TOKEN_FILE"
```

Use `--json` for machine-readable output.

### Create a VM

```bash
slicer vm add HOSTGROUP --url "$SLICER_URL" --token-file "$SLICER_TOKEN_FILE"
```

The VM inherits its base image from the daemon configuration; `slicer vm add`
does not have an image flag. To use Rocky Linux 9, Arch Linux, a different
Ubuntu release, or another supported hypervisor/architecture image, configure
`config.image` before starting the daemon. See
[references/custom-images.md](references/custom-images.md#published-base-images).

The hostgroup argument is optional when only one host group is configured — the SDK resolves it automatically. When there are multiple host groups you must specify one explicitly.

If SSH access is needed, configure key material at launch time:
- for local keys: pass a real public key string via `--ssh-key`
- for GitHub key import: pass via `--import-user USERNAME`

Use `slicer vm add --help` first to verify current flag names and supported auth options before constructing the launch command.

```bash
slicer vm add --help
```

The hostname is printed on creation (e.g. `demo-3`). Key flags:

| Flag | Purpose |
|------|---------|
| `--cpus N` | Override vCPU count |
| `--ram-gb N` | Override RAM (also `--ram-mb`, `--ram-bytes`) |
| `--userdata '#!/bin/bash\n...'` | Bootstrap script |
| `--userdata-file ./setup.sh` | Bootstrap from file |
| `--ssh-key "ssh-ed25519 ..."` | Inject SSH public key |
| `--import-user USERNAME` | Import SSH keys from GitHub user |
| `--shell` | Open shell immediately after boot |
| `--name NAME` / `-n NAME` | Assign a unique friendly CLI name |
| `--tag env=ci` | Metadata tags |
| `--secrets secret1,secret2` | Allow access to named secrets |
| `--persistent` | Keep VM state across daemon restarts/shutdowns (default `true`); pass `--persistent=false` for ephemeral |

For automation, use `--wait --json` to return only after the guest agent is
ready. When using `--name`, keep the chosen name as `VM_REF` for later CLI
commands and store `.hostname` separately as `VM_HOSTNAME`; do not replace the
friendly reference with the JSON hostname or expect a separate name output
field. `--name` is an input convenience that adds the immutable `name=<value>`
tag. Use `--wait-userdata --json` when userdata must also finish before the
command returns. `slicer vm ready <VM_REF>` remains useful when a VM was
launched asynchronously.

When creating VMs for mutable tasks, do not target or reuse `slicer-1` on slicer-mac unless the user explicitly requests it. Reuse the session's tagged VM when known; otherwise create a new VM with explicit `--tag`.

### Persistent temporary VMs

VMs created with `slicer vm add` are persistent by default, they survive daemon restarts and shutdowns. Pair every launch with descriptive `--tag`s so the sandbox can be rediscovered later. Pass `--persistent=false` only when you want a one-shot ephemeral VM that disappears with the daemon.

**On slicer-mac**: launch into the `sbox` host group explicitly — the `slicer` group is reserved for the persistent Linux twin.

```bash
VM_REF=rustfs-demo
VM_HOSTNAME=$(slicer vm add sbox --name "$VM_REF" \
  --tag "workflow=rustfs" --tag "purpose=s3-demo" \
  --wait --json | jq -r '.hostname')
slicer vm ready "$VM_REF"

# Rediscover later by tag:
slicer vm list --json \
  | jq -r '.[] | select(any(.tags[]?; . == "workflow=rustfs")) | .hostname'
```

### Friendly names and mutable tags

Use `--name` / `-n` when a stable human-readable reference helps:

```bash
slicer vm add sbox --name papermaking --tag workflow=docs --wait
slicer shell papermaking
slicer vm cp papermaking:~/guide.html .
```

`--name` is an input: choose and retain it before launch. It is CLI sugar for
adding the immutable `name=papermaking` tag, not a separate API name field or
an output that must be captured. Capture launch JSON's generated `hostname`
separately, then continue using the known friendly name for Slicer CLI
commands. The guest's own `hostname` command still prints the generated
hostname; this does not mean friendly-name resolution failed.

The generated hostname remains the API identity. Do not combine `--name` with
a manual `--tag name=...`, add a `name` API field, or invent an alias endpoint.
Ordinary tags can be changed with `slicer vm tag`.

For raw API/SDK lookup, tag mutation, validation rules, list rendering, and
the CLI's direct-hostname-first resolution, read
[references/vm-names-and-tags.md](references/vm-names-and-tags.md).

**On Slicer for Linux**: host group names vary per deployment. Either:

1. List groups first and pick an appropriate one:
   ```bash
   slicer vm group --url "$SLICER_URL" --token-file "$SLICER_TOKEN_FILE"
   slicer vm add <group> --tag "workflow=..." ...
   ```
2. Or skip the check and launch into the default group by omitting the positional arg:
   ```bash
   slicer vm add --tag "workflow=..." ...
   ```

### Wait for readiness

```bash
# Block until the slicer-agent is responsive (default)
slicer vm ready VM_REF --agent --timeout 5m

# Block until userdata script has finished
slicer vm ready VM_REF --userdata --timeout 5m
```

`--agent` waits for the in-VM slicer-agent (vsock RPC). `--userdata` waits for the bootstrap script to complete (guarded by `/etc/slicer/userdata-ran` in the guest). Polling interval: `--interval 100ms` (default).

Prefer `slicer vm shell` for interactive workflows that need command history, incremental state, and a stable PTY.

### Non-blocking health check

```bash
slicer vm health VM_REF --json    # Agent version, uptime, stats — does not block
```

---

## Running Commands

### Execute a command (foreground)

```bash
slicer vm exec VM_REF -- "whoami"
```

`slicer vm exec` blocks until the command exits and streams stdout/stderr inline.
For long-running processes that should survive client disconnect (dev servers,
multi-minute builds, agent-driven workflows), use `slicer vm bg exec` instead —
see [Background Exec](#background-exec-long-running-processes) below.

By default, `slicer vm exec` executes the command through a shell, so use direct command strings.
For plain exec with no shell interpretation, use `--shell ""`.
Avoid wrapping with `/bin/bash -lc` or explicit shell launches unless you intentionally need shell-specific parsing.
Anti-pattern: `slicer vm exec ... -- /bin/bash -lc "..."` (unless required for nested shell logic).

The default user is auto-detected (typically `ubuntu`, uid 1000). Override with `--uid`:

```bash
slicer vm exec VM_REF --uid 1000 -- "sudo apt update && sudo apt install -y nginx"
```

Key flags:

| Flag | Purpose |
|------|---------|
| `--uid` | Run as target user UID (non-root default is auto-detected, typically `1000`) |
| `--cwd string` | Set working directory (`~` and `~/path` supported, `../` traversal is blocked) |
| `--env stringArray` | Pass environment variables as `KEY=VALUE` pairs (repeatable) |
| `--shell ""` | Skip shell interpreter, exec directly |

`--cwd` and `--env` are direct `slicer vm exec` flags (confirmed from `slicer vm exec --help`).

Example:

```bash
slicer vm exec VM_REF --uid 1000 --cwd ~/project --env FOO=bar --env DEBUG=1 -- "env | sort | head -n 5"
```

Pipes and stdin work:

```bash
# Pipe local file into VM
cat script.sh | slicer vm exec VM_REF -- "bash"

# Pipes inside VM
slicer vm exec VM_REF -- "ps aux | grep nginx"
```

### Create scripts and configuration files safely

Create multi-line scripts and configuration files locally, then copy them into
the VM. Do not construct them with an interactive heredoc or one tmux
`send-keys` call at a time.

```bash
# Create or edit setup.sh locally using the agent's normal file-editing tool.
slicer vm cp ./setup.sh VM_REF:/home/ubuntu/setup.sh \
  --uid 1000 --permissions 0755
slicer vm exec VM_REF --uid 1000 --shell="" -- \
  /bin/bash -n /home/ubuntu/setup.sh
```

If the shell displays its `>` continuation prompt after `cat > file <<'EOF'`,
send `Ctrl-C` before doing anything else; the heredoc body or terminator did
not arrive. See [references/file-transfer.md](references/file-transfer.md) for
the guarded non-interactive fallback and configuration-file verification.

### Interactive shell

```bash
slicer vm shell VM_REF
```

Flags (from `slicer vm shell --help`): `--uid`, `--cwd`, `--shell`, `--bootstrap "command"` (run on connect).

- `--env` is **not** a `slicer vm shell` flag; pass env vars inside the shell once connected or use `slicer vm exec --env`.
- `--shell` in `slicer vm shell` is shell-choice only; do not assume `zsh` is installed.

Use `slicer vm shell` for longer interactive work; keep `slicer vm exec` for bounded command calls.
It opens an interactive PTY, so it is not suited to non-interactive stdin pipelines.

### Background Exec (long-running processes)

Use `slicer vm bg exec` when the command should survive client disconnect — dev servers, builds, test runs.
Do **not** use `slicer vm exec ... &` — that ties the child to the local shell and you can't reconnect.

**Critical difference from `vm exec`:** `bg exec` defaults to **direct exec** (no shell).
`vm exec` defaults to `/bin/bash`. This means:
- Positional: pass binary + args as separate tokens. `-- npm run dev` ✓. `-- "npm run dev"` ✗ (error).
- Shell features needed? Use `--shell=/bin/bash`. For daemons, prefix with `exec`: `--shell=/bin/bash -- "cd /app && exec ./server"`.
- Explicit form (`-c`/`-a`): always direct-exec, no quoting issues, mutex with `--shell` and positional.

**Three command forms:**

```bash
# 1. Positional — separate tokens after --
slicer vm bg exec VM_REF --uid 1000 -- npm run dev

# 2. Explicit — preferred for agents
slicer vm bg exec VM_REF --uid 1000 -c npm -a run -a dev

# 3. Shell — opt-in for $VAR, pipes, &&
slicer vm bg exec VM_REF --uid 1000 --shell=/bin/bash -- "cd /app && exec npm run dev"
```

**Capture exec_id** from JSON for later management. Human-readable output
uses labels such as `Exec ID`; do not parse it with `awk` or rely on its layout.
Use `jq` and Bash's `pipefail` to stop the script if launch or ID extraction fails:

```bash
VM_REF=devserver # friendly name assigned with --name
set -o pipefail
EX=$(slicer vm bg exec "$VM_REF" --uid 1000 --cwd /home/ubuntu/app --json \
     -- npm run dev \
     | jq -er '.exec_id | select(type == "string" and length > 0)') || exit 1
```

Keep `--follow` out of ID capture: it streams subsequent events and waits for
the child to exit. Attach separately with `bg logs --follow`. Keep stderr
separate from JSON stdout; do not pipe `2>&1` into `jq`.

If launch may have succeeded but the ID was not captured, inspect
`slicer vm bg list "$VM_REF" --json` and confirm the command and start time
with `bg info` before reusing an ID. Do not blindly relaunch or select the
first entry: another job may already be running.

**Management subcommands:**

```bash
slicer vm bg list   "$VM_REF"                     # list running + exited
slicer vm bg info   "$VM_REF" "$EX"               # JSON status of one exec
slicer vm bg logs   "$VM_REF" "$EX"               # dump ring buffer (--follow to stream)
slicer vm bg wait   "$VM_REF" "$EX" --timeout 10m # block until exit
slicer vm bg kill   "$VM_REF" "$EX"               # SIGTERM (→ SIGKILL after 5s)
slicer vm bg remove "$VM_REF" "$EX"               # only after exit; frees the control record
```

CLI 0.1.216 and later accept friendly names consistently across background
subcommands. Update older clients that require a canonical hostname rather
than designing the workflow around that inconsistency. `bg remove` does not
kill a live child: kill and wait before removing it, or the process continues
without a control handle.

Key flags: `--uid`, `--cwd`, `--env KEY=VALUE`, `--ring-bytes 4M` (buffer cap, default 1M), `--follow`, `--json`. If binary not on `$PATH`, use full path: `-- /usr/local/bin/nats-server -p 4222`.

See [references/bg-exec.md](references/bg-exec.md) for the full flag table, ring buffer details, and worked examples.

---

## File Transfer

```bash
slicer vm cp ./local-file.txt VM_REF:/tmp/file.txt --uid 1000
slicer vm cp VM_REF:/etc/os-release ./os-release.txt
slicer cp -r ./my-project/ VM_REF:/home/ubuntu/project/ --uid 1000
```

Use binary mode without `-r` for one file. Always use `-r` / `--recursive`
for a directory in either direction. Add `.slicerignore` and `--exclude` rules
to avoid copying caches and build outputs.

Read [references/file-transfer.md](references/file-transfer.md) for permission
flags, recursive destination shape, exclusions, and old guest compatibility.

---

## Port Forwarding

Forward traffic from VMs to the host with `slicer vm forward` using SSH-style
`-L` syntax. Check that each local port is free before starting the forward.

```bash
PORT=8080
if ! command -v lsof >/dev/null 2>&1; then
  echo "Install lsof or verify port $PORT manually before continuing."
  exit 1
fi
if lsof -i TCP:"$PORT" -sTCP:LISTEN >/dev/null 2>&1; then
  echo "Local port $PORT is already in use."
  exit 1
fi
slicer vm forward VM_REF -L 8080:127.0.0.1:8080
slicer vm forward VM_REF -L 127.0.0.1:2375:/var/run/docker.sock
slicer vm forward VM_REF -L /tmp/docker.sock:/var/run/docker.sock
```

Forwards run in the foreground. Read
[references/networking.md](references/networking.md) for bind adapters,
multiple forwards, sockets, and bridge, isolated, macvtap, and macOS details.

---

## VM Lifecycle

```bash
slicer vm pause VM_REF       # Freeze (saves CPU, instant resume)
slicer vm resume VM_REF      # Unfreeze
slicer vm shutdown VM_REF    # Graceful shutdown
slicer vm delete VM_REF      # Remove VM
slicer vm suspend VM_REF     # Save state to disk (snapshot)
slicer vm restore VM_REF     # Restore from snapshot
```

### Cold fork a prepared VM

Prepare a persistent builder once, shut it down, commit its disk, then fork
allocator-named runners. On macOS, use the `sbox` host group:

```bash
slicer vm shutdown "$BUILDER"
COMMIT=$(slicer vm commit "$BUILDER" --cache-key "$CACHE_KEY" --json | jq -r '.commit_id')
RUNNER=$(slicer vm fork "$COMMIT" --tag "workflow=$WORKFLOW" --json | jq -r '.hostname')
```

Do not pass a child hostname to `vm fork`; Slicer allocates it. The same CLI
and SDK workflow works with Slicer for Mac. macOS forks are disk-only APFS
clones of `sbox` VMs. Network allow/drop settings apply to the whole macOS
`sbox` host group, so give hot builders and restricted runners different
Slicer Proxy clients; do not rely on per-fork network overrides. On Linux,
`--allow`, `--no-allow`, and `--drop` require an isolated host group;
bridge-mode forks inherit their host group's networking.

For cache hits, no-egress runners, cleanup, and agent-safety notes, read
[references/cold-forking.md](references/cold-forking.md).

### Monitoring

```bash
slicer vm health VM_REF       # Agent status, version, stats (--json)
slicer vm top                 # Live metrics for all VMs
slicer vm top VM_REF          # Live metrics for one VM
slicer vm logs VM_REF         # Boot/console log (--lines N)
```

---

## Agent Sandboxes (Coding Agents in VMs)

Slicer can provision agent sandboxes with `slicer amp`, `claude`, `codex`,
`copilot`, `opencode`, or `pi`; use `slicer workspace` for a plain VM and
shell.

```bash
slicer codex --worktree .    # push current git worktree and attach
slicer codex ./my-project    # copy ./my-project in, then attach
slicer codex                 # provision-only: VM + codex + creds, then stop
slicer codex --name builder  # provision-only with a friendly CLI name
slicer codex builder         # reattach by friendly name
```

No argument is provision-only; pass `.` explicitly to copy the current
directory. Agent VMs are persistent by default; use `--rm` for a disposable
VM. Read [references/agent-sandboxes.md](references/agent-sandboxes.md) for
credentials, modes, names, tmux, worktrees, and `.slicerignore`.

## Related skills

Companion skills cover Slicer features in depth — load them when a task calls for them:

- **`use-slicer-worktrees`** — get a git worktree or repository into a VM with a working, self-contained `.git`, then pull commits back. Prefer agent `--worktree`; use `slicer wt push` / `pull` / `list` for manual VM flows.
- **`use-slicer-proxy`** — filter, audit, and inject secrets into HTTP(S) egress from VMs with Slicer Proxy: default-deny allow rules, credential injection (Bearer, Basic, OAuth), and audit / passthrough modes, on Linux and macOS.
- **`use-xvfb-terminal-recording`** — record a terminal/TUI (coding agent) demo as a real video with Xvfb + xterm + ffmpeg inside a VM; clean ordering, MAD trimming (ships `scripts/mad_trim.py`), and delivery.
- **`use-dual-terminal-race`** — record two agents racing the same task side by side: one agent per fresh VM, each bridged into a host xterm on a host Xvfb display.
- **`use-k3s`** — single-node local K3s with k3sup: no traefik, svclb LoadBalancer, kubeconfig merged into `~/.kube/config`, nginx smoke test via 127.0.0.1.
- **`use-k3sup`** — k3sup / k3sup-pro for remote and HA clusters over SSH.

---

## Common Workflows

Worked recipes — E2E tests, remote Docker, cross-compiling Go/Rust, k3s clusters, database testing, SSH/SCP — are in [references/workflows.md](references/workflows.md).

---

## Base Images, Custom Images & Userdata

Selecting a compatible published Ubuntu, Rocky Linux, or Arch image, building a
custom rootfs (`slicer disk export` → OCI image), and userdata (cloud-init style
first-boot scripts) are covered in
[references/custom-images.md](references/custom-images.md).

---

## Secrets Management

```bash
slicer secret create --name my-secret --value "s3cret"
slicer secret list
slicer secret update --name my-secret --value "new-value"
slicer secret remove --name my-secret
```

VMs access secrets via `--secrets` on `slicer vm add`.

---

## Images & Disks

```bash
slicer image list              # List cached images
slicer image remove IMAGE      # Remove an image
slicer image wipe              # Remove all images

slicer disk list               # List disk leases
slicer disk export VM_HOSTNAME # Disk commands use the canonical API identity
slicer disk archive ...        # Archive sparse images
slicer disk sparsify ...       # Reclaim space
slicer disk transfer ...       # Compress + transfer via lz4
```

See [references/custom-images.md](references/custom-images.md) for selecting a
published base image or building a custom rootfs image.

---

## Utility Commands

```bash
slicer info             # Client + server version
slicer version          # Client version only
slicer vm route ./cfg.yaml   # Show routing commands (for remote access from Mac/Linux)
slicer install TOOL     # Install additional tools via OCI
slicer update           # Supported Slicer upgrade path; normally run with sudo
slicer activate         # Legacy command for GitHub Sponsors and for trial users only. Most users should get a license key from their email and save it to ~/.slicer/LICENSE
```

---

## Important Notes

1. **Default user**: uid auto-detected (ubuntu/1000). Use `--uid 1000` to be explicit. On non-Ubuntu images, the user is `slicer`
2. **First boot pulls image**: may take 30–60s on first run; subsequent boots are 1–3s.
3. **Port forwards block**: run them in background with `&`.
4. **Internet access**: VMs have outbound internet by default (bridge mode).
5. **Storage modes**: `image` (persistent, default), `devmapper`, `zfs`.
6. **Userdata runs once**: guarded by `/etc/slicer/userdata-ran` in the guest. Delete `.img` + `.lock` files to reset.
7. **.slicerignore**: place at workspace root to skip files during `slicer workspace/amp/claude/codex` copies.

## Troubleshooting

| Problem | Fix |
|---------|-----|
| Connection refused | Slicer daemon not running — start with `sudo -E slicer up config.yaml` |
| Permission denied | Use `sudo` for unix socket access, or verify `--token-file`/`--token` and local TCP credentials |
| VM not responding | `slicer vm ready VM_REF --timeout 60s` |
| Command hangs | Long-running processes block `vm exec` — use `slicer vm bg exec` instead |
| Stale state | Delete `.img` and `.lock` files to reset persistent disks |
| `invalid mode: cp-v1-*` | Update the Slicer CLI to a build using Go SDK v0.0.67 or later; compatibility fallback is client-side, so do not patch the daemon or guest first |

