Forking a running machine is fun right up until you ask what else you just copied.

Memory is obvious. Filesystem state is obvious. The process tree, page cache, open descriptors, random state, and half-finished work are all part of the appeal.

Authority is easier to miss.

A checkpoint can contain enough of a machine to resume execution, but it cannot be allowed to resume yesterday’s identity as if nothing happened.

That is the rule behind MVM’s fork and restore work:

A child may inherit computation. It does not inherit trust.

Why agents want forks

Agent workloads naturally branch.

One worker reaches a useful state, then the controller wants to try three different next steps. A code agent installs a large dependency set, indexes a repository, and then explores several repairs. A browser agent logs into a test environment and needs to compare alternative actions from the same starting point.

Starting from zero every time is wasteful.

A snapshot can turn the expensive prefix into a reusable parent:

flowchart LR
    B[Boot] --> S[Set up environment]
    S --> W[Warm useful state]
    W --> C[Checkpoint]
    C --> A[Branch A]
    C --> D[Branch B]
    C --> E[Branch C]

The performance case is easy to understand.

The security case is where the design gets serious.

A snapshot contains more than bytes

Suppose a VM is running under a signed execution plan. The plan binds:

  • workload image
  • resource limits
  • network policy
  • service grants
  • secrets
  • host shares
  • audit identity
  • validity window
  • replay protection

Now capture the machine and create a second one from it.

If the child simply resumes the saved state, several bad things can happen:

  • two machines believe they are the same VM
  • both reuse the same host channel session
  • a secret issued to the parent remains live in the child
  • sequence numbers and replay state diverge
  • an expired plan continues through restored memory
  • audit events from two machines share one identity
  • a parent with permission to spawn one child effectively creates many

The snapshot mechanism can be perfectly correct while the security model is broken.

The parent is data, not authority

The useful mental model is to treat the checkpoint as an immutable input to a new admission.

sequenceDiagram
    participant P as Parent VM
    participant H as Host runtime
    participant C as Checkpoint store
    participant A as Admission
    participant N as Child VM

    P->>H: checkpoint request
    H->>C: save memory and machine state
    H->>P: resume parent
    H->>A: request fresh child plan
    A->>A: verify image, limits, grants, lineage
    A-->>H: signed child admission
    H->>N: restore checkpoint with fresh identity
    H->>N: deliver new channels and secrets
    N-->>H: child ready

The checkpoint gives the child a computational starting point.

Admission gives it permission to exist.

MVM’s user-facing machine fork and machine restore paths route the child back through the same admit-and-boot boundary used for a new machine. The child gets a new VM identity, new per-instance secrets, and fresh host-channel state.

That is slower than blindly cloning everything.

It is also the only version I trust.

Identity has to include the boot

A machine name is not enough.

A VM can stop and start under the same name. A checkpoint can be restored more than once. A branch can move to another host later.

The identity used for authorization needs a per-boot component:

VmInstanceIdentity {
  node_id,
  vm_id,
  boot_id,
  plan_digest,
}

The boot_id prevents a stale channel from becoming valid again after restart.

The plan_digest binds the instance to the exact admitted contract.

The node and VM identifiers tell the control plane where this instance belongs without pretending that a transport coordinate is an identity.

The tuple is more important than any individual field.

Channels must die at the restore boundary

A vsock connection is not just a stream of bytes. In MVM it carries authorization context, sequence numbers, and session state.

That state cannot survive a fork as-is.

The parent and child need separate:

  • session keys
  • sequence counters
  • flow registries
  • network leases
  • writer leases
  • audit context
  • service bindings

If both machines continue from the same authenticated session state, each can produce frames the other thinks belong to itself. Even if the cryptography remains valid, identity has split.

Restore therefore has to invalidate the old session and establish a new one before useful work resumes.

This is one of those places where snapshot performance and security pull in opposite directions. The fast path wants to resume immediately. The safe path inserts a re-keying and re-binding boundary.

The safe path wins.

Secrets cannot be part of the template

A reusable warm parent is only useful if it can be claimed by different workloads.

That means the parent cannot contain tenant authority.

No raw secrets. No live credential placeholders already bound to a tenant. No host path that points into one user’s checkout. No open external connection. No active broker session.

The prepared-machine substrate in MVM explicitly excludes those values from template identity.

A clean parent may include:

  • kernel and initramfs
  • immutable rootfs layers
  • verified runtime overlay
  • backend and VMM version
  • guest-agent protocol
  • CPU and memory shape
  • device topology
  • warmup profile

It must not include:

  • secrets
  • tenant grants
  • mutable workload state
  • live vsock sessions
  • host directory contents
  • reusable authority

That line makes warm reuse possible without turning one tenant’s machine into another tenant’s starting point.

Delegation must only get smaller

Forking becomes more interesting when a VM is allowed to request children.

A controller may need to create workers. A worker may need to create a narrower helper. That can be useful, but the capability relation must be monotonic:

CchildCparentC_{\text{child}} \subseteq C_{\text{parent}}

The child can receive less authority than the parent, never more.

The same applies to budget:

iBchildiBparent\sum_i B_{\text{child}_i} \leq B_{\text{parent}}

Without that rule, “may spawn a worker” becomes “may manufacture authority.”

In practice, attenuation means the runtime checks that every child request is a subset of the parent plan:

  • fewer repositories, not more
  • shorter lifetime, not longer
  • smaller network allow-list
  • lower CPU and memory budget
  • fewer descendants
  • narrower service grants

A snapshot makes branching cheap. It should not make permission amplification cheap.

Lineage should survive even when authority does not

A fresh child identity does not mean losing ancestry.

The system still needs to answer:

  • which checkpoint produced this child
  • which parent created it
  • which plan authorized the fork
  • which artifacts were shared
  • which decisions diverged afterward

That is audit lineage, not identity reuse.

The parent and child should have distinct execution histories connected by an explicit causal edge.

flowchart LR
    P[Parent execution] --> K[Checkpoint]
    K --> C1[Child 1 execution]
    K --> C2[Child 2 execution]
    P -. authorized .-> C1
    P -. authorized .-> C2

This distinction becomes important in investigations. “These machines came from the same state” and “these machines had the same authority” are not equivalent statements.

Dirty snapshots are not warm parents

There are two kinds of reuse that people often collapse.

A clean warm parent is prepared for reuse and contains no tenant-specific state.

A dirty checkpoint captures a real workload in progress.

Both are valuable. They need different rules.

A clean parent can feed a pool. A dirty checkpoint belongs to an execution lineage and should require explicit authorization to restore or branch.

Treating every checkpoint as a reusable template is how secrets, open sessions, and mutable state leak across boundaries.

The storage format may be the same. The trust class is not.

The practical test

The easiest way to review a fork design is to ask what remains identical after the operation.

It is fine for these to match:

  • immutable artifact digests
  • kernel version
  • rootfs lower layers
  • saved memory pages
  • checkpoint lineage

These should not match:

  • boot identity
  • plan nonce
  • session keys
  • network lease
  • secret material
  • audit stream identity
  • child budget allocation

If the implementation cannot clearly separate the two lists, the fork boundary is not finished.

Cheap branching, expensive trust

I want MVM to make speculative agent work cheap.

Checkpoint a useful state. Branch it. Try several paths. Keep the winner. Discard the rest.

That is a compelling execution model.

The part I will not optimize away is fresh authority.

A child must be admitted, named, budgeted, connected, and audited as a new machine. The snapshot is allowed to save work. It is not allowed to save the security decision.

Memory can be cloned.

Trust has to be minted again.


Next: 200 Milliseconds Is Not a Boot Time