How to reuse and save machine state

Initialize the runtime as described in installation. Use unused machine names and artifact paths. These examples need native branch and checkpoint support on the host. A supported host can still reject a machine’s resource or device configuration.

(require '[ol.smolvm :as smol])

Run work from a prepared machine

Create a branchable source, prepare its files, then branch for each task. Keep the source open until its children have closed:

(with-open [source (smol/create {:name "prepared-source"
                                :branchable? true})]
  (smol/file-write source "/tmp/input" "prepared data")
  (with-open [child (smol/branch source "task-child")]
    (smol/exec child ["cat" "/tmp/input"])))

Check the returned :stdout and :exit-code. Closing the child deletes its machine and storage, not the source. Closing the outer scope deletes the source. The engine refuses to delete a source with dependent children.

For an existing machine, stop it before calling start-branchable. That function does not convert an already running machine. For several children, branch-batch returns a vector, not a Closeable handle:

(with-open [source (smol/create {:name "batch-source" :branchable? true})]
  (let [children (smol/branch-batch source ["task-a" "task-b"])]
    (try
      (mapv #(smol/exec % ["echo" "ready for work"]) children)
      (finally
        (doseq [^java.io.Closeable child children]
          (.close child))))))

Omit explicit ports for a multi-child batch. Empty ports remap any source forwards to fresh host ports rather than removing them. Neither branch call checks application listeners. Use host-port to find a mapping, then apply your application’s readiness check separately.

Run one command in a disposable branch

Use branch-exec when the child needs only one command. Supply an unused child name and ordinary exec options:

(with-open [source (smol/create {:name "single-task-source"
                                :branchable? true})]
  (smol/file-write source "/tmp/input" "prepared data")
  (smol/branch-exec source "single-task-child" ["cat" "/tmp/input"]
                    {:timeout-ms 5000}))

Check :stdout and :exit-code as with exec. A nonzero exit does not throw. The helper deletes its child after execution, including after an execution error. It does not delete a pre-existing machine if the name conflicts. Cleanup failure after success throws. If execution also failed, its exception carries the cleanup failure as a suppressed exception. The helper does not delete the source, though branching can briefly pause it. It does not wait for application listeners or accept extra branch options.

Save a checkpoint and restore a separate machine

Use a branchable source without host mounts, staged mounts, remote volumes, GPU or CUDA state. Other host-bound features can also prevent capture. Choose an output path that does not exist and ends in .checkpoint or the legacy .smolcheckpoint suffix (case-insensitive). This applies to portable files and stored checkpoint directories.

(with-open [source (smol/create {:name "checkpoint-source"
                                :branchable? true})]
  (smol/file-write source "/tmp/input" "saved data")
  (smol/checkpoint source "/tmp/saved-machine.checkpoint"))

(with-open [restored (smol/checkpoint-restore
                     "/tmp/saved-machine.checkpoint" "restored-task")]
  (smol/exec restored ["cat" "/tmp/input"]))

The restored command should return "saved data" in :stdout. Closing either machine does not delete the checkpoint. Delete the artifact explicitly when it is no longer needed. A failed restore start or policy update cleans up the newly installed machine, not the artifact.

Restore can fetch referenced images on the host even when guest networking is disabled. Saved-memory restores cannot switch network backends.

For repeated captures, pass {:store "/absolute/checkpoint-store"} to checkpoint and use a new directory such as /tmp/capture-2.checkpoint as its output. Use checkpoint-export to make a portable file from that directory. The export destination must not exist. A .checkpoint suffix is useful for recognition but is not required for export. checkpoint-prune deletes unreferenced store objects, not active checkpoints. Keep checkpoint directories and their store together until export.

Suspend work and continue later

Use pause to save execution durably and resume to continue it:

(with-open [machine (smol/create {:name "pause-example" :branchable? true})]
  (smol/file-write machine "/tmp/input" "continue here")
  (smol/pause machine)
  (smol/resume machine)
  (smol/exec machine ["cat" "/tmp/input"]))

Pause permits ordinary host mounts but rejects staged mounts, remote volumes, GPU and CUDA state. To leave a paused machine for another session, connect to an existing machine instead of creating a deleting handle in with-open. Closing a create handle deletes the machine even if it is paused.

Increase capacity during a task

Pass target totals, not increments. For example, grow a machine from 256 MiB to 384 MiB:

(with-open [machine (smol/create {:name "resize-example" :memory-mib 256})]
  (smol/resize machine {:memory-mib 384}))

Check the returned resource totals. The guest must support live growth and the host must have enough memory. RAM growth uses 128 MiB increments from boot RAM, within runtime capacity. RAM and disks cannot shrink. Disk changes fail while dependent branches exist. CPU changes have narrower platform support.

Resize is not transactional. A later failure can leave an earlier resource change applied. Inspect the machine before retrying.

Package a stopped machine

Stop the machine, then pack its disk state:

(with-open [machine (smol/create {:name "pack-example"})]
  (smol/file-write machine "/tmp/input" "packaged data")
  (smol/stop machine)
  (smol/pack machine "/tmp/prepared-machine"))

This writes both /tmp/prepared-machine, a runnable file, and /tmp/prepared-machine.smolmachine, the artifact. The return value is the artifact path. Packing uses the helper included in the native runtime. Neither file is deleted when the machine closes. Remove both explicitly when finished. Use checkpoints, not pack, to save running memory state.

See Local API reference for resource limits, platform restrictions and complete option tables.