State
Fork, checkpoints and diff internals
Copy-on-write children of a running VM, checkpoints that store only what differs, and a file-level diff from inside the guest.
FlashVMM fork and checkpoints are copy-on-write operations on a running FlashVM: a fork captures the VM and starts up to 64 children that continue from the same instant, a checkpoint is the same capture kept under the VM as a numbered diff against a base, and flash diff compares guest file manifests on the host.
All three are built from the snapshot and clone operations of the snapshot format and the page tracking of the memory model, so children and checkpoints cost the pages that differ rather than a copy of the VM. A child is running in 36 ms. An agent uses this to try several fixes from one prepared state, undo a failed step with flash rewind, and see exactly which files a command changed.
Key facts
| Runs on | Linux (KVM) · macOS (Hypervisor.framework) · Windows (WHP) |
|---|---|
| Interfaces | CLI flash fork, checkpoint, checkpoints, history, rewind, diff · MCP flash_cli, flash_exec, flash_diff · REST POST /v1/flashvm/snapshots with fork, then PUT /v1/flashvm per child |
| Fork time | 36 ms (macOS), 38 ms (Windows x86), child running |
| Children per fork | 1 to 64 |
| Checkpoints kept | 20 unpinned by default (--keep up to 1000), plus up to 50 pinned |
| Rebase trigger | A checkpoint diff of at least 64 MiB and an eighth of the VM's memory |
| Diff limits | 20,000 entries per side; files up to 64 MiB hashed; text diffs up to 1 MiB per file |
How it works
Live fork
flash fork PARENTreads the parent's shape, caps, egress policy and secret proxies from its API.- It sends
POST /v1/flashvm/snapshots {"fork": true}. All-zero RAM is never written, so the capture is as large as what the guest used. The parent keeps running. - It runs one
flash cloneper child from that capture. Each child maps RAM copy-on-write and pages it in as it touches it, so N children cost the pages each one writes. Each child gets its own identity, inherits the parent's egress policy, and takes its own NIC from--nic(withpool=ID, one per child from aflashnetdNIC pool). - Each child holds a link to the capture (
<registry>/<child>.fork.snap);flash rmon the last child removes it.
Forkable VMs on Linux
A VM started with --forkable keeps its RAM in a MAP_SHARED file. Its first fork capture freezes that file in place as the base and remaps the parent privately over it, so the fork copies no RAM; every later capture is a diff of the pages dirtied since that base or since the newest rebase.
Checkpoints, rewind and branch
A checkpoint is a fork capture that is kept under the VM instead of handed to children, numbered, labeled, and recorded with the exit code of the command it was taken for. flash run --checkpoints takes one before every flash exec and every MCP flash_exec, and implies --forkable. When a diff grows to the rebase trigger, the next checkpoint is written self-contained as the new base. flash rewind VM N rebuilds the VM under the same name from checkpoint N, with its memory, disk and running processes as they were; later checkpoints are kept, so a rewind can be undone. flash fork VM --from N branches children from any checkpoint while the VM carries on.
File-level diff
flash diff A B takes two VMs, or a VM and a snapshot file. On each side the guest lists its own files with BusyBox over exec (type, mode, size, inode, link target), and the host compares the listings. Only files the listings cannot settle (same path and size, or a possible rename) are hashed with sha256sum in the guest, so a diff never hashes a whole root. The result lists added, changed, deleted and renamed files with line diffs for text; /proc, /sys, /dev, /run, /var/log, /var/cache and shell history are left out unless --all. flash exec --json --changes returns the same shape for one command.
Interfaces
CLI
flash run --bundle ./bundle --id work --vcpus 2 --mem-mib 1024 --cpu-template host-raw --checkpoints --entry 'sleep 3600' --detach
flash exec work -- sh -c 'cd /work && sh setup.sh'
flash checkpoint work --label ready --pin
flash history work
flash fork work --from 1 --count 2
flash rewind work 1
flash diff work-fork1 work-fork2 --patch
flash exec work --json --changes -- sh -c 'make'
MCP
flash_exec(vm_id: "work", argv: ["sh", "-c", "cd /work && sh setup.sh"], checkpoint: true)
flash_cli(args: ["history", "work"])
flash_cli(args: ["fork", "work", "--from", "1", "--count", "2"])
flash_cli(args: ["rewind", "work", "1"])
flash_diff(a: "work-fork1", b: "work-fork2")
flash_exec(vm_id: "work", argv: ["sh", "-c", "make"], changes: true)
REST
POST /v1/flashvm/snapshots {"path": "...", "fork": true} → 202 {"operation": "..."}
POST /v1/flashvm/snapshots {"path": "...", "fork": true, "rebase": true}
PUT /v1/flashvm {"source": {"type": "snapshot", "path": "..."}, "allow_identity_mismatch": true, "diff_base": "...", ...} (each child's socket)
POST /v1/flashvm/guest/execs {"argv": ["sh", "-c", "make"]}
Checkpoints, history, rewind and branch are composed by flash from these routes and keep their record under the VM in the registry. Contract: rebase without fork returns 422 invalid_body; a VM started with --disable-dirty-tracking takes full captures. A forked or rewound VM starts with no execs, since execs belong to the VMM that ran them.
Guarantees
- Children pay for their own writes. RAM is shared copy-on-write from one capture.
- Every child is its own machine. New identity, own NIC and reseeded randomness, with the parent's limits and egress policy.
- Undo is undoable. Rewind keeps every checkpoint, later ones included.
- Exact file changes. Diffs come from the guest's own listing and hashes, in the shape agents parse.