Back to Microsandbox

Sandbox commands

docs/cli/sandbox-commands.mdx

0.6.425.4 KB
Original Source

msb run

Create a sandbox and optionally run a command. Without --name, the sandbox is ephemeral and removed when the command finishes. With --name, it persists for later use.

bash
# Ephemeral: runs and cleans up
msb run python -- python -c "print('hello')"

# Named: persists after exit
msb run --name devbox ubuntu -- bash

# With volumes, ports, and environment
msb run --name api \
  -v ./src:/app \
  -v pydata:/data \
  -p 8000:8000 \
  -e DEBUG=true \
  --label user.id=alice \
  -w /app \
  python

# Detached (boots in background; run work later with exec)
msb run -d --name worker python
msb exec worker -- python worker.py

# Publish on all IPv4 host interfaces instead of the default 127.0.0.1
msb run --name public-api -p 0.0.0.0:8000:8000 python

Common flags:

FlagDescription
-n, --nameSandbox name. If omitted, the sandbox is ephemeral
-c, --cpusVirtual CPU limit
--max-cpusBoot-time maximum possible virtual CPUs for future resize capacity
-m, --memoryMemory limit, such as 512M or 1G
--max-memoryBoot-time maximum hotpluggable memory, such as 2G or 8G
-v, --volumeMount a host path or named volume, such as ./src:/app:ro
--mount-dir, --mount-file, --mount-disk, --mount-namedMount a source with an explicit kind (SOURCE:DEST[:OPTIONS] or NAME:DEST[:OPTIONS]). --mount-named creates missing named volumes idempotently and accepts kind=dir|disk, size=..., and quota=...
-p, --portPublish a port, such as 8000:8000 for loopback-only or 0.0.0.0:8000:8000 for all host interfaces
-e, --envSet an environment variable
--labelAttach a label for metric attribution (KEY=VALUE, or bare KEY). Repeatable
-w, --workdirSet the working directory
-d, --detachBoot in the background. Run work later with msb exec
--no-ttyDisable PTY allocation and run non-interactively
--replaceReplace an existing sandbox with the same name
--no-netDisable network access
--net-ruleAdd a network policy rule
--secretInject a host-held secret for an allowed destination
--tmpfsMount an in-memory filesystem
--copy, --copy-file, --copy-dir, --mkdir, --rmPatch the rootfs before boot

Use msb run --help for the full flag list.

Published ports bind to 127.0.0.1 by default. Use an explicit bind address only when the sandbox service should be reachable beyond localhost. On Windows, opening a published port can trigger a Windows Defender Firewall prompt for msb.exe; keep the bind on 127.0.0.1 for local-only development, and allow private/public network access only when you intentionally bind beyond loopback.

Network rule syntax

--net-rule takes one or more comma-separated rule tokens. The token grammar is:

<action>[:<direction>]@<target>[:<proto>[:<ports>]]
FieldValues
actionallow, deny
directionegress (default), ingress, any
targetSee Targets below
prototcp, udp, icmpv4, icmpv6, any (default)
ports<port>, <lo>-<hi>, or any (default)

Targets

FormExampleNotes
IP / CIDR198.51.100.5, 10.0.0.0/8, [2001:db8::]/32IPv6 must be bracketed
Domain (exact)example.comUse domain=public to disambiguate from the public group
Domain suffix*.example.com, suffix=example.comMatches the apex and any subdomain at any depth. Suffixes must be at least two labels: *.com and suffix=local are rejected to prevent accidental blast radius
Grouppublic, private, multicast, loopback, link_local, metadata, anyPre-defined IP groups

Wildcard quoting: the rule grammar uses @, :, and , which are shell-significant, so always quote --net-rule values. The *. in suffix shorthand mirrors the syntax already used by --tls-bypass and --secret.

Common compositions

bash
# Allowlist: deny by default, allow specific destinations
msb run alpine --net-default deny --net-rule "[email protected],allow@*.githubusercontent.com"

# Blocklist: allow by default, deny specific destinations
msb run alpine --net-default allow --net-rule "deny@*.tracking.com,deny@*.ads.example"

# Airgapped: equivalent to `--net-default deny`
msb run alpine --no-net

# Airgapped except one host (allowlist with --no-net sugar)
msb run alpine --no-net --net-rule "[email protected]"

msb create

Create and boot a sandbox without running a command. Takes the same flags as msb run (except --detach).

bash
msb create python --name worker -c 2 -m 1G
msb create --replace python --name worker            # Replace existing
msb create --replace-with-timeout 30s python --name worker  # Give the old one 30s to exit
msb create --replace-with-timeout 0 python --name worker    # SIGKILL immediately

msb start

Resume a stopped sandbox. Name one or more sandboxes, or select them by label.

bash
msb start devbox
msb start --label app=engine          # start every sandbox labelled app=engine
FlagDescription
--labelStart every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
-q, --quietSuppress progress output

msb stop

bash
msb stop devbox                # Graceful shutdown (10s grace)
msb stop --force devbox        # Force kill immediately
msb stop -t 30 devbox          # 30s grace before force kill
msb stop --label app=engine    # stop every sandbox labelled app=engine

Graceful shutdown gives the sandbox a chance to finish writing any pending data to disk before it exits, so files written inside the sandbox aren't lost across a later msb start. If the sandbox is still running after the timeout, it is force-killed.

--force and a timeout that elapses both end in a force-kill. Pending writes that the workload hasn't fsync'd at that point may be lost — same durability semantics as a sudden power loss on a physical machine. For durable writes, workloads should fsync important data themselves.

FlagDescription
--labelStop every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
-f, --forceForce terminate immediately. Pending writes may be lost
-t, --timeoutSeconds to wait for graceful shutdown before force-killing. Defaults to 10
-q, --quietSuppress progress output

msb restart

Stop and start one or more sandboxes. Running, draining, and paused sandboxes are stopped first, then started from their persisted configuration. Stopped, crashed, and created sandboxes skip the stop phase and are started directly.

bash
msb restart devbox
msb restart api worker
msb restart --label app=engine
msb restart --force devbox
msb restart -t 30 devbox

msb restart uses the same stop controls as msb stop: --force kills immediately, and --timeout controls how long graceful shutdown gets before force-kill escalation.

FlagDescription
--labelRestart every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
-f, --forceForce terminate immediately before starting again. Pending writes may be lost
-t, --timeoutSeconds to wait for graceful shutdown before force-killing. Defaults to 10
-q, --quietSuppress progress output

msb ping

Check whether one or more running sandbox agents are reachable. msb ping talks to agentd with core.ping and does not refresh the sandbox idle timer.

bash
msb ping devbox
msb ping api worker
msb ping --label app=engine
msb ping api --touch

Use --touch when a successful health check should also refresh the idle timer. Without --touch, ping is a pure reachability check.

FlagDescription
--labelPing every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
--touchRefresh the sandbox idle timer after a successful ping
-q, --quietSuppress progress output

msb touch

Explicitly refresh the idle timer for one or more running sandboxes. msb touch sends core.touch; it is the intentional keepalive command for long-lived idle sandboxes.

bash
msb touch devbox
msb touch api worker
msb touch --label app=engine
FlagDescription
--labelTouch every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
-q, --quietSuppress progress output

msb modify

Change a sandbox's configuration. msb modify plans every requested change, classifies each one (live, next start, requires restart, unsupported), and applies all-or-nothing. CPU count and memory apply live to a running sandbox when the target fits inside the boot-time capacity (max_cpus / max_memory); raising the capacity itself requires a restart or --next-start.

bash
msb modify api --cpus 4                    # live when 4 <= max_cpus
msb modify api --memory 4G                 # live when 4G <= max_memory
msb modify api --env MODE=prod --restart   # restart so the change is active now
msb modify api --max-memory 16G --next-start
msb modify api --cpus 8 --dry-run          # show the plan, apply nothing

max_cpus and max_memory are boot-time reservations chosen at create time. They default to the effective cpus/memory, which leaves no headroom — live growth beyond them is impossible without a restart. Reserving capacity costs almost nothing (parked vCPUs and lazily-backed memory), so set them above the initial values at create time if the sandbox may need to grow.

Live resize is not necessarily instant. When an accepted resize has not fully settled, the apply output includes a convergence table with a STATE column: applied (requested, actual, and enforced values match), converging (the guest is still onlining CPUs or plugging memory), guest-refused (the guest would not cooperate; the host enforces the new limit anyway), and failed. JSON output (--format json) carries the same states in resize_status.

Env and workdir changes on a running sandbox apply to future execs only — running processes keep their current environment. The plan reports this as a warning.

--secret NAME@HOST adds or rotates a secret from the same-named host environment variable, recording a source reference — the value itself never rides in the command. The inline NAME=VALUE@HOST form is rejected, same as on msb create: shell history and process listings would leak the value, so providing a raw value is SDK-only.

FlagDescription
--cpusDesired effective vCPU count
--max-cpusBoot-time maximum possible vCPUs (restart-backed)
--memoryDesired effective guest memory, such as 512M or 4G
--max-memoryBoot-time maximum hotpluggable memory (restart-backed)
--env, --env-rmSet (KEY=VALUE) or remove an environment variable for future execs
--label, --label-rmSet (KEY=VALUE) or remove a label
--workdirWorking directory for future execs
--secret, --secret-rmAdd or rotate a secret from a host environment variable (NAME@HOST), or remove one
--dry-runShow the plan without applying anything
--next-startSave changes for the next start without mutating a running VM
--restartRestart if needed so restart-required changes become active now
--format jsonEmit the plan/result as JSON

msb exec

Execute a command inside a running sandbox.

bash
msb exec devbox -- python -c "print('hello')"
msb exec devbox -- ls -la /app
FlagDescription
-t, --ttyAllocate a pseudo-terminal (enables colors, line editing)
--no-ttyDisable PTY allocation and run non-interactively
-e, --envSet an environment variable (KEY=VALUE)
-w, --workdirOverride working directory
-u, --userRun the command as the specified guest user
--timeoutKill the command after this duration (e.g. 30s, 5m, 1h)
--rlimitSet a POSIX resource limit (e.g. nofile=1024, nproc=64)
-q, --quietSuppress progress output
<Tip> The CLI auto-detects whether stdin is a terminal. When interactive, `msb exec` uses `attach` mode (TTY, line editing). When piped, it captures output. Use `--no-tty` to force captured, non-interactive execution even from a terminal. </Tip>

msb copy

Copy files between the host and a sandbox.

bash
msb copy ./local.txt devbox:/tmp/local.txt
msb copy devbox:/tmp/out.txt ./out.txt
msb copy devbox:/tmp/a devbox:/tmp/b
msb copy devbox:/tmp/a otherbox:/tmp/a

Host-to-sandbox and sandbox-to-host forms follow docker cp syntax. Same-sandbox and cross-sandbox forms are microsandbox extensions.

msb copy connects to an existing sandbox and starts it temporarily if needed, following the same lifecycle ownership behavior as msb exec. The shorter msb cp form is available as an alias.

FlagDescription
-q, --quietSuppress progress output

msb logs

Read captured output from a sandbox. Each sandbox stores its captured stdio under <sandbox-dir>/logs/exec.log as JSON Lines, plus runtime/kernel diagnostics in runtime.log/kernel.log. The command works on running and stopped sandboxes alike — there is no protocol traffic, just a file read.

bash
# Captured user-program output (default sources: stdout + stderr + output)
msb logs devbox

# Tail and follow
msb logs devbox --tail 100
msb logs devbox -f --grep ERROR

# Time-bounded
msb logs devbox --since 5m
msb logs devbox --since 2026-04-30T20:00:00Z --until 5m

# JSON Lines passthrough — feed to jq, vector, etc.
msb logs devbox --json | jq 'select(.s == "stderr")'

# Multi-session view: prefix each line with [id:N] so you can tell sessions apart
msb logs devbox --show-id

# Color each session's output a distinct color (implies --show-id)
msb logs devbox --color-sessions

# Include runtime/kernel diagnostics
msb logs devbox --source system
msb logs devbox --source all                # everything, chronologically merged
FlagDescription
--tailShow only the last N entries
--sinceShow entries at or after this time (RFC 3339 or relative 5m/2h/1d)
--untilShow entries strictly before this time (same formats)
-f, --followFollow in real time (200 ms polling, rotation-aware)
--timestampsPrefix each line with the entry timestamp
--sourceSources to include: stdout, stderr, output, system, all. Repeat or comma-separate. Default: stdout,stderr,output
--grepClient-side regex filter on the entry body
--jsonEmit raw JSON Lines without decoding (one entry per line)
--rawOpt into base64 encoding for non-UTF-8 bytes
--show-idPrefix each line with [id:N] (the session correlation id)
--color-sessionsColor each session's lines a distinct color (implies --show-id)
--colorANSI handling: auto (default), always, never
--no-colorAlias for --color=never

Source tags (the s field in --json output):

  • stdout / stderr — captured from the session's pipes when running in pipe mode (streams stay separated end to end).
  • output — captured from the session in pty mode. pty allocation merges stdout and stderr at the kernel level inside the guest, so they arrive as a single stream — tagged output rather than mislabelled as stdout.
  • system — synthetic lifecycle markers (--- sandbox started --- / --- sandbox stopped ---) plus diagnostic lines from runtime.log/kernel.log when --source system is requested.
<Tip> If a sandbox failed to start, `msb logs` prepends a styled error block reconstructed from `boot-error.json`. The block tells you the failure stage, errno, and a hint — even though no user-program output was ever captured. </Tip>

msb ls

List all stored sandboxes.

bash
msb ls                    # All sandboxes (running and stopped)
msb ls --running          # Running sandboxes only
msb ls --stopped          # Stopped sandboxes only
msb ls --label app=engine # Only sandboxes labelled app=engine
msb ls --format json      # JSON output
msb ls -q                 # Names only
FlagDescription
--runningShow only running sandboxes
--stoppedShow only stopped sandboxes
--labelShow only sandboxes carrying this label (KEY=VALUE). Repeatable; AND-matched
--formatOutput format (json)
-q, --quietShow only sandbox names

msb status / ps

Show sandbox status with process details.

bash
msb ps                    # Running sandboxes
msb ps my-app             # Single sandbox
msb ps -a                 # All sandboxes (including stopped)
msb ps --format json      # JSON output
FlagDescription
-a, --allShow all sandboxes, not just running ones
--labelShow only sandboxes carrying this label (KEY=VALUE). Repeatable; AND-matched. Not combinable with a sandbox name
--formatOutput format (json)
-q, --quietShow only sandbox names

The CPUS and MEM columns show the sandbox's allocation as effective / max, where max is the boot-time hotplug ceiling — the headroom available to a live resize. Values come from the active config for running sandboxes (so an accepted msb modify shows immediately) and from the stored config for stopped ones. For usage rather than allocation, see msb metrics.

msb metrics

Show live CPU, memory, disk, network, and optional upper disk metrics for running sandboxes.

bash
msb metrics                 # All running sandboxes (one-shot table)
msb metrics my-app          # Single sandbox, in any state
msb metrics --watch         # Refresh the table in place (like docker stats)
msb metrics --follow        # Stream JSON Lines, one object per sandbox per tick
msb metrics --all           # Include recently exited sandboxes
msb metrics --sort cpu      # Sort by CPU instead of name
msb metrics --format json   # One-shot JSON output
FlagDescription
-w, --watchContinuously refresh the table in place. Ctrl-C to quit. Requires a terminal
-f, --followStream one JSON Lines object per sandbox per interval to stdout
--intervalRefresh interval for --watch/--follow (e.g. 500ms, 2s). Default 1s
-a, --allInclude exited rows — terminal metrics preserved in the registry until the slot is reused
--sortSort rows by name (default), cpu, or mem
--formatOutput format (json)

Columns. --watch and the one-shot table render identically:

  • STATErunning (fresh sample from a live runtime), stalled (runtime alive but no sample within 3× its sampling interval; the row shows how long ago the last sample landed), or exited (the preserved terminal sample of a stopped or crashed sandbox).
  • CPU — vCPU-seconds per wall-second over the allocation, e.g. 0.80 / 2c means 0.8 cores busy out of 2 allocated.
  • MEM — guest-used memory over the configured limit.
  • DISK R/W /s, NET RX/TX /s — per-second rates derived from two consecutive samples. The one-shot form samples twice ~500 ms apart to compute them; exited rows show cumulative totals instead.

The CPU and MEM denominators come from the catalog's active config, so they track live resizes immediately. Sandboxes whose runtime crashed without cleanup are detected by owner-PID liveness and reported as exited, not running.

Invocation semantics:

InvocationShows
msb metricsrunning + stalled sandboxes
msb metrics --allthe above plus exited ones still present in the registry
msb metrics <name>that sandbox in any state

--format json and --follow keep the raw cumulative counters (no rate conversion) and add state and cpus fields.

msb inspect

Show detailed configuration and status.

bash
msb inspect devbox
msb inspect devbox --format json
FlagDescription
--formatOutput format (json)

msb rm

Remove one or more sandboxes and their associated state.

bash
msb rm devbox
msb rm --force devbox            # Stop and remove in one step
msb rm worker-1 worker-2         # Remove multiple
msb rm --force --label app=engine  # Remove every sandbox labelled app=engine
FlagDescription
--labelRemove every sandbox carrying this label (KEY=VALUE). Repeatable; AND-matched. Unioned with any named sandboxes
-f, --forceStop the sandbox if running, then remove it
-q, --quietSuppress progress output

msb install

Install a sandbox as a system command. Creates an executable in ~/.microsandbox/bin/ that launches msb run with the specified image and options.

bash
msb install ubuntu                   # Install as 'ubuntu' command
msb install --name nodebox node      # Custom command name
msb install --tmp alpine             # Fresh sandbox every invocation
msb install -c 2 -m 1G python  # With resource limits
msb install --list                   # List installed commands
FlagDescription
-n, --nameCommand name for the alias (defaults to image name)
-c, --cpusNumber of virtual CPUs to allocate
-m, --memoryAmount of memory (e.g. 512M, 1G)
-v, --volumeMount a host path or named volume (SOURCE:DEST[:OPTIONS], e.g. ./src:/app:ro,noexec)
--mount-dir, --mount-file, --mount-disk, --mount-namedMount a source with an explicit kind (SOURCE:DEST[:OPTIONS] or NAME:DEST[:OPTIONS]). --mount-named creates missing named volumes idempotently and accepts kind=dir|disk, size=..., and quota=...
--securityIn-guest security profile (default or restricted)
-w, --workdirWorking directory inside the sandbox
--shellShell for interactive sessions
-e, --envSet an environment variable (KEY=VALUE)
-f, --forceOverwrite an existing alias with the same name
--no-pullDon't pull the image before installing
--tmpCreate a fresh sandbox on every invocation (no persistent state)
-l, --listList all installed sandbox commands

msb uninstall

Remove an installed sandbox command.

bash
msb uninstall nodebox
msb uninstall ubuntu alpine   # Remove multiple

msb self

Manage the msb installation itself.

bash
msb doctor                   # Alias for msb self doctor
msb doctor --fix             # Try supported host setup fixes
msb self doctor              # Check runtime and host virtualization prerequisites
msb self check               # Alias for doctor
msb self update               # Update msb and libkrunfw to latest
msb self update --force       # Re-download even if up to date
msb self downgrade 0.6.0      # Downgrade to a supported older release
msb self downgrade 0.6.0 -y   # Skip downgrade confirmations
msb self uninstall            # Remove msb (with confirmation prompt)
msb self uninstall --yes      # Skip confirmation
SubcommandDescription
doctor (alias: check)Check runtime files and host virtualization prerequisites such as Windows Hypervisor Platform
update (alias: upgrade)Update msb and libkrunfw to the latest release and refresh command links
downgrade <version>Downgrade msb and compatible local state to a supported older release at or above 0.6.0, refusing unsafe downgrades before touching files or state
uninstallRemove msb, libkrunfw, and command links

msb self update always targets the latest release; it does not accept a version argument. Use msb self downgrade <version> to move to a supported older release.

Before a downgrade changes local state, msb checks the target release, confirms it can understand the current local database, refuses targets below 0.6.0, refuses irreversible state changes, and blocks the operation while matching running sandboxes are active. When a database rollback is needed, msb creates a retained SQLite backup under ~/.microsandbox/db/ unless --no-backup is passed. If rollback metadata marks the image cache affected, msb purges the cache after the database rollback unless --keep-cache is passed. The target binary is always installed fresh and checked with msb --version before command links are refreshed.

FlagSubcommandDescription
--fixdoctorTry supported host setup fixes; on Windows this opens an elevated PowerShell prompt to enable Windows Hypervisor Platform without forcing an immediate reboot
-f, --forceupdateRe-download even if already on the latest version
-f, --forcedowngradeAccepted for an explicit reinstall request; downgrade always reinstalls the target and this flag does not bypass safety checks
-y, --yesdowngradeSkip destructive-step confirmations
--keep-cachedowngradeKeep the image cache even when rollback metadata marks it affected
--no-backupdowngradeSkip the database backup before rolling back local state
-y, --yesuninstallSkip confirmation prompt