Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/deeplethe/forkd/llms.txt

Use this file to discover all available pages before exploring further.

Snapshots are the foundation of the forkd fork-on-write model. A snapshot captures a paused, warmed parent VM — its vCPU state, memory image, and device config — so that child processes can mmap the memory file with MAP_PRIVATE and start running immediately without a cold boot. This page documents every CLI verb that creates, inspects, modifies, or removes snapshots.

forkd quickstart

Zero-to-first-fork in one command. Designed for first-time setup on a fresh host. Run as sudo -E forkd quickstart. What it does, step by step:
  1. Runs the doctor preflight (platform, hardware virt, KVM, Firecracker binary) and fails fast if any blocking check fails.
  2. Identifies which setup steps the host still needs: guest kernel download, tap device creation, per-child netns provisioning.
  3. Lists the required steps and prompts for confirmation (or accepts --yes for non-interactive use).
  4. Executes the missing steps using embedded copies of the repo’s idempotent setup scripts (install-guest-kernel.sh, host-tap.sh, netns-setup.sh).
  5. Chooses a snapshot route: reuses an existing quickstart tag → local Docker bake via from-image → hub pull of deeplethe/python-numpy (when Docker is absent).
  6. Calls forkd fork --tag quickstart -n N --per-child-netns and prints per-child timings.
  7. Prints suggested next commands.
Quickstart is idempotent — re-running reuses an existing snapshot and skips already-completed setup steps.
--n / -n
usize
default:"10"
Number of children to fork for the demo.
--image
string
default:"python:3.12-slim"
Docker image the parent snapshot is baked from. Ignored when Docker is unavailable (hub pull route is used instead).
--yes / -y
boolean
Answer yes to all setup prompts (kernel download, tap creation, netns provisioning) without interactive confirmation. Suitable for CI / non-interactive use.
sudo -E forkd quickstart
sudo -E forkd quickstart --n 50 --yes
sudo -E forkd quickstart --image ubuntu:24.04 --n 5

forkd snapshot

Boot a fresh parent VM from a kernel and rootfs, warm it up, pause it, and write the snapshot to $XDG_DATA_HOME/forkd/snapshots/<tag>/. Alternatively, with --from-sandbox, branch a running child sandbox via the controller daemon — no local boot required. Local boot path (default): boots a Firecracker VM, waits --boot-wait-secs for the guest to settle (imports, JIT warmup, model loading), pauses the vCPUs, writes vmstate and memory.bin, then kills the parent VM. The snapshot.json metadata file records volume specs for subsequent forkd fork calls. Daemon branch path (--from-sandbox): calls POST /v1/sandboxes/<id>/branch on the controller. The source sandbox is paused only for the snapshot window (0.5–8 s for Full; ~200 ms for Diff; sub-50 ms for Live). After this call, --kernel, --rootfs, --tap, --boot-wait-secs, --mem-size-mib, and --volume are all ignored — the branch inherits those settings from the source’s snapshot.
--tag
string
Name of the snapshot tag. The snapshot is stored at $XDG_DATA_HOME/forkd/snapshots/<tag>/. With --from-sandbox, leave unset to let the daemon auto-generate branch-<sandbox-id>-<unix-ts>. Required on the local-boot path. Must match [A-Za-z0-9_][A-Za-z0-9._-]{0,63}.
--from-sandbox
string
Sandbox ID to branch from. When set, calls the daemon branch endpoint instead of booting a local parent VM. Requires --daemon-url and optionally --daemon-token.
--diff
boolean
Use v0.3 Diff snapshot mode (only with --from-sandbox). Source pause is ~200 ms vs seconds for Full. Mutually exclusive with --live.
--live
boolean
Use v0.4 Live (UFFD_WP-based) BRANCH mode (only with --from-sandbox). Source pause drops to sub-50 ms; memory is streamed asynchronously from the running parent after it resumes. Requires the source sandbox to have been created with --live-fork. Mutually exclusive with --diff. Requires Linux ≥ 5.7 and the vendored Firecracker fork.
--no-wait
boolean
With --live: return as soon as the source VM resumes (~10 ms) instead of waiting for the background memory copy to finish. The snapshot reaches status: ready later — poll GET /v1/snapshots or forkd ls --snapshots. Requires --live.
--daemon-url
string
default:"http://127.0.0.1:8889"
Controller daemon base URL. Used when --from-sandbox is set. Also read from the FORKD_URL environment variable.
--daemon-token
string
Bearer token for the controller daemon. Read from FORKD_TOKEN when unset.
--kernel
path
Path to the vmlinux kernel image. Required on the local-boot path (unless --from-sandbox is set). Also read from FORKD_KERNEL.
--rootfs
path
Path to the rootfs image. Pass .ext4 for read-write, or .squashfs for read-only. Required on the local-boot path (unless --from-sandbox is set). Also read from FORKD_ROOTFS.
--rw
boolean
Mount the rootfs read-write. Auto-enabled when --rootfs has a .ext4 extension.
--tap
string
Host tap device name to attach as the guest’s eth0 (e.g. forkd-tap0). Create with sudo bash scripts/host-tap.sh. Also read from FORKD_TAP.
--boot-wait-secs
u64
default:"10"
Seconds to wait for the guest to settle after boot before taking the snapshot. Increase for memory-intensive warmup workloads (browser recipes, LLM model loading).
--mem-size-mib
u32
Parent VM memory size in MiB. Defaults to 512 (set by BootConfig). Override for memory-hungry warmup workloads: browser recipes need ≥2048, large SciPy / LLM warmups may need more.
--keep-workdir
boolean
Keep /tmp/forkd-parent-<tag>/ after the snapshot completes (default: removed). Useful for inspecting the parent VM console log post-snapshot.
--volume
string
Attach a persistent volume to every child forked from this snapshot. Format: HOST_FILE:GUEST_PATH[:ro]. Repeatable for up to 24 volumes (vdb..vdy). The host file must be an existing ext4 image. Use volumes for pip caches, model weights, or agent scratch space — content survives across forks of the same tag.
# Create an ext4 volume:
sudo dd if=/dev/zero of=/var/lib/forkd/vol/cache.img bs=1M count=512
sudo mkfs.ext4 -F /var/lib/forkd/vol/cache.img

# Attach on snapshot:
sudo forkd snapshot --tag myagent \
    --kernel ./vmlinux-6.1.141 \
    --rootfs ./myagent.ext4 \
    --tap forkd-tap0 \
    --volume /var/lib/forkd/vol/cache.img:/opt/cache
Examples:
# Local boot — full snapshot from kernel + rootfs
sudo forkd snapshot \
    --tag pyagent \
    --kernel ./vmlinux-6.1.141 \
    --rootfs ./python-rootfs.ext4 \
    --tap forkd-tap0

# Branch a running sandbox into a new tag (Full mode)
sudo forkd snapshot --from-sandbox sb-abc-0001 --tag checkpoint-1

# Branch with Diff mode (~200 ms source pause)
sudo forkd snapshot --from-sandbox sb-abc-0001 --tag checkpoint-diff --diff

# Branch with Live mode (sub-50 ms source pause, async memory copy)
sudo forkd snapshot --from-sandbox sb-abc-0001 --tag checkpoint-live --live --no-wait

# Use environment variables instead of flags
FORKD_KERNEL=/var/lib/forkd/kernels/vmlinux \
FORKD_TAP=forkd-tap0 \
sudo -E forkd snapshot --tag myagent --rootfs ./myagent.ext4

forkd snapshot-diff

Derive a new diff snapshot from a base tag by running an installer command inside a transient one-shot sandbox. This is the primary tool for building v0.5 snapshot chains without manually managing sandboxes. What it does:
  1. Spawns one sandbox from --from via POST /v1/sandboxes.
  2. Waits up to 30 s for the guest agent to respond.
  3. Runs --exec via the agent’s exec endpoint (with --exec-timeout-secs deadline).
  4. Issues a Diff BRANCH with parent_tag set to record the chain edge: POST /v1/sandboxes/<id>/branch with mode: "diff" and parent_tag: <from>.
  5. Kills the transient sandbox unconditionally on both success and error paths.
The resulting snapshot has parent_tag pointing at --from and a parent_content_hash that pins the parent’s memory bytes. The daemon verifies this hash at spawn time so re-snapshotting the base under the same tag fails loudly rather than silently restoring wrong bytes.
--from
string
required
Base snapshot tag to derive from. Must already be registered with the daemon (check with forkd images or GET /v1/snapshots).
--tag
string
required
Tag for the new diff snapshot. Must not already exist. Must match the tag format rules.
--exec
string
required
Shell command to run in the spawned sandbox to produce the delta. Shell-split on whitespace with basic quote handling (single and double quotes supported). Example: --exec "pip install pandas==2.0.0".
--exec-timeout-secs
u64
default:"600"
Maximum wall-clock seconds for the exec step. Long installs like pip install torch can approach this limit — increase as needed.
--daemon-url
string
default:"http://127.0.0.1:8889"
Controller daemon base URL. Also read from FORKD_URL.
--daemon-token
string
Bearer token for the controller daemon. Also read from FORKD_TOKEN.
Examples:
# Build a 2-layer chain: numpy on top of a base Python snapshot
forkd snapshot-diff \
    --from py-base \
    --tag py-numpy \
    --exec "pip install numpy==2.0.2"

# Add pandas on top of numpy
forkd snapshot-diff \
    --from py-numpy \
    --tag py-pandas \
    --exec "pip install pandas==2.2.3"

# Longer install with extended timeout
forkd snapshot-diff \
    --from py-base \
    --tag py-torch \
    --exec "pip install torch==2.3.0 --index-url https://download.pytorch.org/whl/cpu" \
    --exec-timeout-secs 1800

forkd from-image

Build a forkd snapshot from a Docker image in a single pipeline step. Wraps forkd parent build (Docker → ext4) followed by forkd snapshot (boot + warmup + pause + register tag). After this completes, the snapshot is ready to fork from.
image
string
required
Docker image reference (positional argument). Examples: python:3.12-slim, ghcr.io/user/repo:tag, registry.example.com/foo:bar.
--tag
string
required
Forkd snapshot tag to register the result under.
--extra
string[]
Extra apt packages to install into the rootfs. Repeatable.
--size-mib
u32
default:"1536"
Rootfs image size in MiB.
--cache
path
default:"/var/cache/forkd"
Cache directory for built rootfs .ext4 files. Re-running with the same image skips the Docker → ext4 step when the cached file exists. Also read from FORKD_RUN_CACHE.
--kernel
path
Kernel image path. When unset, searches ./vmlinux-6.1.141, ./vmlinux, /var/lib/forkd/kernels/vmlinux, and /usr/local/share/forkd/vmlinux. Also read from FORKD_KERNEL.
--tap
string
default:"forkd-tap0"
Host tap device for the boot warmup. Also read from FORKD_TAP.
--boot-wait-secs
u64
default:"10"
Seconds to wait for the guest to settle after boot before snapshotting.
--mem-size-mib
u32
Parent VM memory size in MiB. Defaults to 512 (set by BootConfig).
Examples:
# Build a Python + numpy snapshot (2–3 min first run; cached after)
sudo -E forkd from-image python:3.12-slim \
    --tag py-numpy \
    --extra python3-numpy

# Larger image with more memory
sudo -E forkd from-image python:3.12 \
    --tag py-scipy \
    --extra "python3-numpy python3-scipy" \
    --mem-size-mib 2048 \
    --boot-wait-secs 30

# After completion, fork children immediately
sudo -E forkd fork --tag py-numpy -n 10 --per-child-netns

forkd rmi

Remove one or more snapshot tags. Tries DELETE /v1/snapshots/:tag on the daemon first (cleanly removes both registry entry and on-disk files atomically). Falls back to direct disk removal if the daemon is not running or returns 404.
tags
string[]
required
One or more snapshot tags to remove (positional, variadic).
--cascade
boolean
Delete this snapshot and every snapshot chained off it (and their descendants). Use before removing a chain parent to avoid orphaning children. Mutually exclusive with --force.
--force
boolean
Delete this snapshot even if it would orphan child snapshots (breaks the chain — children become un-restorable). Mutually exclusive with --cascade.
--daemon-url
string
default:"http://127.0.0.1:8889"
Controller daemon base URL. Also read from FORKD_URL.
--daemon-token
string
Bearer token for the controller daemon. Also read from FORKD_TOKEN.
Behavior notes:
  • Without --cascade or --force, the daemon returns HTTP 409 if the snapshot has dependents in a chain. Use forkd snapshot-info <tag> first to see which children would be orphaned.
  • The disk fallback validation is stricter than the full tag format: only alphanumeric characters, dashes, and underscores are accepted (1–64 chars) to prevent path traversal without the daemon’s validator.
Examples:
# Remove a single snapshot
forkd rmi pyagent

# Remove multiple snapshots at once
forkd rmi pyagent langgraph python-numpy

# Remove a chain parent and all its descendants
forkd rmi py-numpy --cascade

# Force-remove even if children exist (they become un-restorable)
forkd rmi py-base --force

forkd snapshot-info

Show chain information for a snapshot by calling GET /v1/snapshots/:tag/info. Displays the parent chain, dependents, and on-disk sizes. Use this before rmi-ing a chained snapshot to see which children you would orphan.
tag
string
required
Snapshot tag to query (positional argument).
--json
boolean
Print the daemon’s raw JSON response body instead of the human-formatted table.
--daemon-url
string
default:"http://127.0.0.1:8889"
Controller daemon base URL. Also read from FORKD_URL.
--daemon-token
string
Bearer token. Also read from FORKD_TOKEN.
Example output:
forkd snapshot-info py-numpy
# tag:                  py-numpy
# dir:                  /home/user/.local/share/forkd/snapshots/py-numpy
# chain depth:          1
# parent_tag:           py-base
# parent_content_hash:  sha256:a3f1...
# memory.bin:           512.0 MiB logical / 393.2 MiB on disk
# vmstate:              128.4 KiB
# ancestors:            py-base (root → parent)
# dependents:           py-pandas (would be orphaned by `forkd rmi py-numpy` — pass --cascade or --force)
# Inspect as raw JSON
forkd snapshot-info py-numpy --json

forkd snapshot-compact

Flatten a chained snapshot into a new base snapshot by calling POST /v1/snapshots/:tag/compact. The daemon resolves the full ancestor chain, verifies parent content hashes, assembles the complete memory image, and writes a new flat snapshot with parent_tag: null. The new tag restores via the original non-chain path — useful when chain depth has grown enough that the per-link SHA-256 verification at spawn time is adding measurable latency.
--from
string
required
Source snapshot tag (the chain head to flatten).
--to
string
required
Tag for the new flat snapshot. Must not already exist. Must differ from --from.
--daemon-url
string
default:"http://127.0.0.1:8889"
Controller daemon base URL. Also read from FORKD_URL.
--daemon-token
string
Bearer token. Also read from FORKD_TOKEN.
Examples:
# Flatten a 3-deep chain to a single base snapshot
forkd snapshot-compact --from py-pandas --to py-pandas-flat

# Verify the result
forkd snapshot-info py-pandas-flat
# chain depth:  0
# parent_tag:   (none — this is a base snapshot)

Build docs developers (and LLMs) love