> ## Documentation Index
> Fetch the complete documentation index at: https://docs.microsandbox.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Snapshots

> Rust SDK - Snapshot API reference

Capture a stopped sandbox's writable upper layer into a self-describing, content-addressed artifact on disk, then list, verify, export, import, or boot a fresh sandbox from it. See [Snapshots](/sandboxes/snapshots) for concepts and walkthroughs; this page is the Rust SDK reference.

<Note>
  Snapshots are **local-only** and **disk-only** today: they capture a sandbox that is stopped or crashed, and every operation runs against the default local backend. Cloud snapshots and qcow2 backing chains are deferred.
</Note>

<p className="msb-label" id="typical-flow">Typical flow</p>

```rust theme={null}
use microsandbox::{Sandbox, Snapshot};

// 1. stop the sandbox you want to capture
let sb = Sandbox::get("api").await?;
sb.stop().await?;

// 2. capture its writable upper layer
let snap = Snapshot::builder("api")
    .name("after-pip-install")     // bare name in the default dir
    .record_integrity()            // hash the upper layer
    .create()
    .await?;
println!("{} ({} bytes)", snap.digest(), snap.size_bytes());

// 3. boot a fresh sandbox from it
let restored = Sandbox::builder("api-restored")
    .from_snapshot("after-pip-install")
    .create()
    .await?;
```

## Static methods

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">builder()</span>

```rust theme={null}
fn builder(source_sandbox: impl Into<String>) -> SnapshotBuilder
```

<Accordion title="Example">
  ```rust theme={null}
  let snap = Snapshot::builder("api")
      .name("baseline")
      .create()
      .await?;
  ```
</Accordion>

Start configuring a new snapshot of `source_sandbox`. The builder lets you set the destination, labels, and whether to record content integrity before capturing. See [`SnapshotBuilder`](#snapshotbuilder) for all options.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>source\_sandbox</code><span className="msb-type">impl Into\<String></span></div>
    <div className="msb-param-desc">Name of the source sandbox. Must be stopped or crashed, and rooted on an OCI image.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshotbuilder">SnapshotBuilder</a></div>
    <div className="msb-param-desc">Builder for configuring the snapshot.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">create()</span>

```rust theme={null}
async fn create(config: SnapshotConfig) -> MicrosandboxResult<Snapshot>
```

<Accordion title="Example">
  ```rust theme={null}
  let snap = Snapshot::create(
      Snapshot::builder("api").name("baseline").build()?
  ).await?;
  ```
</Accordion>

Create a snapshot artifact from a stopped sandbox. Writes `manifest.json` and the captured `upper.ext4` into the destination directory atomically (the manifest is renamed into place last), then best-effort upserts a row into the local index. Index failures are logged but do not fail the call; the artifact is the source of truth. Most callers use the [builder](#snapshotbuilder)'s [`create()`](#create) instead of constructing a [`SnapshotConfig`](#snapshotconfig) by hand.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>config</code><a className="msb-type" href="#snapshotconfig">SnapshotConfig</a></div>
    <div className="msb-param-desc">Source sandbox, destination, labels, and integrity flag.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The created artifact handle.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">open()</span>

```rust theme={null}
async fn open(path_or_name: impl AsRef<str>) -> MicrosandboxResult<Snapshot>
```

<Accordion title="Example">
  ```rust theme={null}
  let snap = Snapshot::open("baseline").await?;
  println!("{}", snap.manifest().image.reference);
  ```
</Accordion>

Open an existing artifact by path or bare name. Bare names (no path separator, not starting with `.` or `~`) resolve under the default snapshots directory; anything else is treated as a path. This is a fast metadata operation: it verifies the manifest structure, recomputes the manifest digest, and checks that the upper file exists with the recorded size. It does **not** read the full upper contents; use [`verify()`](#snap-verify) for that.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>path\_or\_name</code><span className="msb-type">impl AsRef\<str></span></div>
    <div className="msb-param-desc">Bare snapshot name or filesystem path to an artifact directory.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The opened artifact handle.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">get()</span>

```rust theme={null}
async fn get(name_or_digest: &str) -> MicrosandboxResult<SnapshotHandle>
```

<Accordion title="Example">
  ```rust theme={null}
  let h = Snapshot::get("after-pip-install").await?;
  println!("{} from {}", h.digest(), h.image_ref());
  ```
</Accordion>

Look up a lightweight [`SnapshotHandle`](#snapshothandle) in the local index by name, digest (`sha256:`/`sha512:` prefix), or path.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>name\_or\_digest</code><span className="msb-type">\&str</span></div>
    <div className="msb-param-desc">Snapshot name, manifest digest, or artifact path.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">SnapshotHandle</a></div>
    <div className="msb-param-desc">Handle backed by the matching index row.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">list()</span>

```rust theme={null}
async fn list() -> MicrosandboxResult<Vec<SnapshotHandle>>
```

<Accordion title="Example">
  ```rust theme={null}
  for h in Snapshot::list().await? {
      println!("{:?} - {}", h.name(), h.digest());
  }
  ```
</Accordion>

List indexed snapshots from the local DB cache, newest first. External-path artifacts booted by full path aren't in the index and won't appear here; use [`list_dir`](#snapshotlist_dir) to enumerate artifacts on disk directly.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">Vec\<SnapshotHandle></a></div>
    <div className="msb-param-desc">Indexed snapshot handles, ordered by creation time descending.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">list\_dir()</span>

```rust theme={null}
async fn list_dir(dir: impl AsRef<Path>) -> MicrosandboxResult<Vec<Snapshot>>
```

<Accordion title="Example">
  ```rust theme={null}
  let snaps = Snapshot::list_dir("/data/snapshots").await?;
  println!("{} artifacts", snaps.len());
  ```
</Accordion>

Walk a directory and parse each subdirectory's manifest. Does not touch the index. Skips entries that don't look like snapshot artifacts (no `manifest.json`) and malformed artifacts.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>dir</code><span className="msb-type">impl AsRef\<Path></span></div>
    <div className="msb-param-desc">Directory to scan for artifacts.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Vec\<Snapshot></a></div>
    <div className="msb-param-desc">One handle per valid artifact found.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">remove()</span>

```rust theme={null}
async fn remove(path_or_name: &str, force: bool) -> MicrosandboxResult<()>
```

<Accordion title="Example">
  ```rust theme={null}
  Snapshot::remove("after-pip-install", false).await?;
  ```
</Accordion>

Remove a snapshot artifact (by digest, name, or path) and its index row. Refuses if the snapshot has indexed children unless `force` is set. The artifact directory is deleted on success and the parent's child count is decremented.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>path\_or\_name</code><span className="msb-type">\&str</span></div>
    <div className="msb-param-desc">Snapshot digest, name, or artifact path.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>force</code><span className="msb-type">bool</span></div>
    <div className="msb-param-desc">When <code>true</code>, remove even if the snapshot has indexed children.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">reindex()</span>

```rust theme={null}
async fn reindex(dir: impl AsRef<Path>) -> MicrosandboxResult<usize>
```

<Accordion title="Example">
  ```rust theme={null}
  let n = Snapshot::reindex("/data/snapshots").await?;
  println!("indexed {n} snapshots");
  ```
</Accordion>

Rebuild the local index from the artifacts in `dir`. Upserts an index row for every artifact found, then recomputes parent-edge child counts in one pass so the cache stays honest about the current set of artifacts.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>dir</code><span className="msb-type">impl AsRef\<Path></span></div>
    <div className="msb-param-desc">Directory of artifacts to index.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">usize</span></div>
    <div className="msb-param-desc">Number of artifacts indexed.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">export()</span>

```rust theme={null}
async fn export(name_or_path: &str, out: &Path, opts: ExportOpts) -> MicrosandboxResult<()>
```

<Accordion title="Example">
  ```rust theme={null}
  use microsandbox::snapshot::ExportOpts;
  use std::path::Path;

  Snapshot::export(
      "baseline",
      Path::new("/tmp/baseline.tar.zst"),
      ExportOpts { with_parents: true, with_image: true, ..Default::default() },
  ).await?;
  ```
</Accordion>

Bundle a snapshot into a `.tar.zst` archive (or plain `.tar`) at `out`. The head snapshot is verified before bundling. The recorded manifest is archived as-is, so create the snapshot with [`record_integrity()`](#record_integrity) when the archive will cross a trust boundary. See [`ExportOpts`](#exportopts) to also include ancestors and the OCI image cache.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>name\_or\_path</code><span className="msb-type">\&str</span></div>
    <div className="msb-param-desc">Snapshot name or artifact path to export.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>out</code><span className="msb-type">\&Path</span></div>
    <div className="msb-param-desc">Output archive path. Parent directories are created if missing.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>opts</code><a className="msb-type" href="#exportopts">ExportOpts</a></div>
    <div className="msb-param-desc">Bundling options. <code>ExportOpts::default()</code> writes the head snapshot only, zstd-compressed.</div>
  </div>
</div>

#### <span className="msb-recv">Snapshot::</span><span className="msb-hn">import()</span>

```rust theme={null}
async fn import(archive_path: &Path, dest: Option<&Path>) -> MicrosandboxResult<SnapshotHandle>
```

<Accordion title="Example">
  ```rust theme={null}
  use std::path::Path;

  let h = Snapshot::import(Path::new("/tmp/baseline.tar.zst"), None).await?;
  println!("imported {}", h.digest());
  ```
</Accordion>

Unpack a snapshot archive (`.tar.zst` or `.tar`, detected from magic bytes) into the snapshots directory (or `dest`), routing any bundled image-cache entries into the global cache and registering everything found in the index. Recorded integrity is verified as artifacts land. Returns a handle for the head snapshot.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>archive\_path</code><span className="msb-type">\&Path</span></div>
    <div className="msb-param-desc">Archive to unpack.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>dest</code><span className="msb-type">Option\<\&Path></span></div>
    <div className="msb-param-desc">Destination directory. <code>None</code> uses the default snapshots directory.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshothandle">SnapshotHandle</a></div>
    <div className="msb-param-desc">Handle for the head (last-listed) snapshot.</div>
  </div>
</div>

## Instance methods

Methods on an opened [`Snapshot`](#snapshotopen) artifact.

#### <span className="msb-recv">snap.</span><span className="msb-hn">digest()</span>

```rust theme={null}
fn digest(&self) -> &str
```

Canonical content digest of this snapshot's manifest (`sha256:hex`). This is the snapshot's identity.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">\&str</span></div>
    <div className="msb-param-desc">Manifest digest in <code>sha256:hex</code> form.</div>
  </div>
</div>

#### <span className="msb-recv">snap.</span><span className="msb-hn">path()</span>

```rust theme={null}
fn path(&self) -> &Path
```

Path to the artifact directory holding the canonical `manifest.json` and the captured upper file.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">\&Path</span></div>
    <div className="msb-param-desc">Artifact directory path.</div>
  </div>
</div>

#### <span className="msb-recv">snap.</span><span className="msb-hn">manifest()</span>

```rust theme={null}
fn manifest(&self) -> &Manifest
```

<Accordion title="Example">
  ```rust theme={null}
  let snap = Snapshot::open("baseline").await?;
  let m = snap.manifest();
  println!("{} @ {}", m.image.reference, m.image.manifest_digest);
  ```
</Accordion>

The parsed [`Manifest`](#manifest): schema, format, fstype, image reference, parent, creation time, labels, and upper-layer metadata.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#manifest">\&Manifest</a></div>
    <div className="msb-param-desc">Parsed snapshot manifest.</div>
  </div>
</div>

#### <span className="msb-recv">snap.</span><span className="msb-hn">size\_bytes()</span>

```rust theme={null}
fn size_bytes(&self) -> u64
```

Apparent size of the captured upper layer in bytes (the ext4 virtual size; sparse on disk).

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><span className="msb-type">u64</span></div>
    <div className="msb-param-desc">Upper-layer apparent size in bytes.</div>
  </div>
</div>

#### <span className="msb-recv">snap.</span><span className="msb-hn">verify()</span>

```rust theme={null}
async fn verify(&self) -> MicrosandboxResult<SnapshotVerifyReport>
```

<Accordion title="Example">
  ```rust theme={null}
  use microsandbox::snapshot::UpperVerifyStatus;

  let snap = Snapshot::open("baseline").await?;
  match snap.verify().await?.upper {
      UpperVerifyStatus::Verified { algorithm, .. } => println!("ok via {algorithm}"),
      UpperVerifyStatus::NotRecorded => println!("no integrity hash recorded"),
  }
  ```
</Accordion>

Recompute the upper layer's content hash and compare it against the manifest. Walks data extents only, so a multi-GiB sparse file with a little data verifies in milliseconds. Returns `NotRecorded` when the manifest has no integrity descriptor; errors with `SnapshotIntegrity` on mismatch.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshotverifyreport">SnapshotVerifyReport</a></div>
    <div className="msb-param-desc">Digest, path, and upper-layer verification status.</div>
  </div>
</div>

## SnapshotHandle methods

Accessors and lifecycle on a [`SnapshotHandle`](#snapshothandle) (an index row). Returned by [`Snapshot::get()`](#snapshotget), [`Snapshot::list()`](#snapshotlist), and [`Snapshot::import()`](#snapshotimport).

#### <span className="msb-recv">h.</span><span className="msb-hn">digest()</span>

```rust theme={null}
fn digest(&self) -> &str
```

Manifest digest (`sha256:hex`), the canonical identity.

#### <span className="msb-recv">h.</span><span className="msb-hn">name()</span>

```rust theme={null}
fn name(&self) -> Option<&str>
```

Name alias, or `None` for digest-only entries.

#### <span className="msb-recv">h.</span><span className="msb-hn">parent\_digest()</span>

```rust theme={null}
fn parent_digest(&self) -> Option<&str>
```

The parent snapshot's digest, or `None` for a root. Always `None` today; populated once chained snapshots land.

#### <span className="msb-recv">h.</span><span className="msb-hn">image\_ref()</span>

```rust theme={null}
fn image_ref(&self) -> &str
```

Image reference the snapshot was taken from.

#### <span className="msb-recv">h.</span><span className="msb-hn">format()</span>

```rust theme={null}
fn format(&self) -> SnapshotFormat
```

On-disk format of the upper layer.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshotformat">SnapshotFormat</a></div>
    <div className="msb-param-desc">Upper-layer format (<code>Raw</code> today).</div>
  </div>
</div>

#### <span className="msb-recv">h.</span><span className="msb-hn">size\_bytes()</span>

```rust theme={null}
fn size_bytes(&self) -> Option<u64>
```

Apparent size of the upper file at index time, if recorded.

#### <span className="msb-recv">h.</span><span className="msb-hn">created\_at()</span>

```rust theme={null}
fn created_at(&self) -> chrono::NaiveDateTime
```

Snapshot creation time, parsed from the manifest.

#### <span className="msb-recv">h.</span><span className="msb-hn">path()</span>

```rust theme={null}
fn path(&self) -> &Path
```

Local artifact directory path.

#### <span className="msb-recv">h.</span><span className="msb-hn">open()</span>

```rust theme={null}
async fn open(&self) -> MicrosandboxResult<Snapshot>
```

<Accordion title="Example">
  ```rust theme={null}
  let h = Snapshot::get("baseline").await?;
  let snap = h.open().await?;
  snap.verify().await?;
  ```
</Accordion>

Open the underlying artifact metadata, upgrading this lightweight handle to a full [`Snapshot`](#instance-methods). Equivalent to [`Snapshot::open(self.path())`](#snapshotopen).

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The opened artifact.</div>
  </div>
</div>

#### <span className="msb-recv">h.</span><span className="msb-hn">remove()</span>

```rust theme={null}
async fn remove(&self, force: bool) -> MicrosandboxResult<()>
```

<Accordion title="Example">
  ```rust theme={null}
  let h = Snapshot::get("baseline").await?;
  h.remove(false).await?;
  ```
</Accordion>

Remove this snapshot. Delegates to [`Snapshot::remove(self.digest(), force)`](#snapshotremove).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>force</code><span className="msb-type">bool</span></div>
    <div className="msb-param-desc">When <code>true</code>, remove even if the snapshot has indexed children.</div>
  </div>
</div>

## Sandbox entry points

Snapshot-related methods that live on the sandbox builder and handle. See [Sandbox](/sdk/rust/sandbox) for the full sandbox API.

#### <span className="msb-recv">.</span><span className="msb-hn">from\_snapshot()</span>

```rust theme={null}
fn from_snapshot(self, path_or_name: impl Into<String>) -> Self
```

<Accordion title="Example">
  ```rust theme={null}
  let sb = Sandbox::builder("api-restored")
      .from_snapshot("after-pip-install")
      .create()
      .await?;
  ```
</Accordion>

`SandboxBuilder` setter. Boot a fresh sandbox from a snapshot artifact. The snapshot already pins the image reference and digest, so this is mutually exclusive with [`image()`](/sdk/rust/sandbox#image) and [`image_with()`](/sdk/rust/sandbox#image_with). The artifact is opened and its integrity verified at [`create()`](/sdk/rust/sandbox#create) time, not here.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>path\_or\_name</code><span className="msb-type">impl Into\<String></span></div>
    <div className="msb-param-desc">Bare name resolved under the default snapshots directory, or a path to an artifact directory.</div>
  </div>
</div>

#### <span className="msb-recv">h.</span><span className="msb-hn">snapshot()</span>

```rust theme={null}
async fn snapshot(&self, name: &str) -> MicrosandboxResult<Snapshot>
```

<Accordion title="Example">
  ```rust theme={null}
  let h = Sandbox::get("api").await?;
  h.stop().await?;
  let snap = h.snapshot("baseline").await?;
  ```
</Accordion>

`SandboxHandle` method. Snapshot this sandbox under a bare name in the default snapshots directory (`~/.microsandbox/snapshots/<name>/`). The sandbox must be stopped or crashed; running sandboxes are rejected with `SnapshotSandboxRunning`. Local handles only. For an explicit destination see [`snapshot_to()`](#h-snapshot_to).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>name</code><span className="msb-type">\&str</span></div>
    <div className="msb-param-desc">Bare snapshot name.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The created artifact handle.</div>
  </div>
</div>

#### <span className="msb-recv">h.</span><span className="msb-hn">snapshot\_to()</span>

```rust theme={null}
async fn snapshot_to(&self, path: impl AsRef<Path>) -> MicrosandboxResult<Snapshot>
```

<Accordion title="Example">
  ```rust theme={null}
  let h = Sandbox::get("api").await?;
  h.stop().await?;
  let snap = h.snapshot_to("/data/snapshots/baseline").await?;
  ```
</Accordion>

`SandboxHandle` method. Snapshot this sandbox to an explicit filesystem path. The sandbox must be stopped or crashed. Local handles only. For the common case of writing under the default snapshots directory see [`snapshot()`](#h-snapshot).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>path</code><span className="msb-type">impl AsRef\<Path></span></div>
    <div className="msb-param-desc">Destination artifact directory.</div>
  </div>
</div>

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The created artifact handle.</div>
  </div>
</div>

## SnapshotBuilder

Builder for a [`SnapshotConfig`](#snapshotconfig). Obtained via [`Snapshot::builder(source_sandbox)`](#snapshotbuilder). A destination is required ([`name`](#name) or [`path`](#path)); the other setters are optional. Every setter returns `Self`, so calls chain.

```rust theme={null}
let snap = Snapshot::builder("api")
    .name("after-pip-install")     // bare name in default dir
    .label("stage", "post-deps")
    .force()                       // overwrite if it exists
    .record_integrity()            // hash the upper layer
    .create()
    .await?;
```

#### <span className="msb-recv">.</span><span className="msb-hn">destination()</span>

```rust theme={null}
fn destination(self, dest: SnapshotDestination) -> Self
```

Set the artifact destination explicitly. The [`name`](#name) and [`path`](#path) setters are convenience wrappers over this.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>dest</code><a className="msb-type" href="#snapshotdestination">SnapshotDestination</a></div>
    <div className="msb-param-desc">Name- or path-based destination.</div>
  </div>
</div>

#### <span className="msb-recv">.</span><span className="msb-hn">name()</span>

```rust theme={null}
fn name(self, name: impl Into<String>) -> Self
```

Convenience: use a bare name resolved under the default snapshots directory. Sets the destination to [`SnapshotDestination::Name`](#snapshotdestination).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>name</code><span className="msb-type">impl Into\<String></span></div>
    <div className="msb-param-desc">Bare snapshot name. Must not be empty, contain <code>/</code>, or start with <code>.</code>.</div>
  </div>
</div>

#### <span className="msb-recv">.</span><span className="msb-hn">path()</span>

```rust theme={null}
fn path(self, path: impl Into<PathBuf>) -> Self
```

Convenience: write the artifact to an explicit path. Sets the destination to [`SnapshotDestination::Path`](#snapshotdestination).

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>path</code><span className="msb-type">impl Into\<PathBuf></span></div>
    <div className="msb-param-desc">Destination artifact directory.</div>
  </div>
</div>

#### <span className="msb-recv">.</span><span className="msb-hn">label()</span>

```rust theme={null}
fn label(self, key: impl Into<String>, value: impl Into<String>) -> Self
```

Add a user label. Can be called multiple times. Labels are sorted by key in the manifest's canonical form.

<p className="msb-label">Parameters</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><code>key</code><span className="msb-type">impl Into\<String></span></div>
    <div className="msb-param-desc">Label key.</div>
  </div>

  <div className="msb-param">
    <div className="msb-param-key"><code>value</code><span className="msb-type">impl Into\<String></span></div>
    <div className="msb-param-desc">Label value.</div>
  </div>
</div>

#### <span className="msb-recv">.</span><span className="msb-hn">force()</span>

```rust theme={null}
fn force(self) -> Self
```

Overwrite an existing artifact at the destination. Without this, creation fails with `SnapshotAlreadyExists` if the destination directory exists.

#### <span className="msb-recv">.</span><span className="msb-hn">record\_integrity()</span>

```rust theme={null}
fn record_integrity(self) -> Self
```

Compute and record an upper-layer content-integrity hash during creation. Recorded integrity is what [`verify()`](#snap-verify) checks and what import/export rely on when crossing a trust boundary.

#### <span className="msb-recv">.</span><span className="msb-hn">build()</span>

```rust theme={null}
fn build(self) -> MicrosandboxResult<SnapshotConfig>
```

Materialize the [`SnapshotConfig`](#snapshotconfig) without creating the snapshot. Errors with `InvalidConfig` if no destination was set. For capturing, use [`create`](#create) instead; it calls `build` internally.

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#snapshotconfig">SnapshotConfig</a></div>
    <div className="msb-param-desc">Validated snapshot configuration.</div>
  </div>
</div>

#### <span className="msb-recv">.</span><span className="msb-hn">create()</span>

```rust theme={null}
async fn create(self) -> MicrosandboxResult<Snapshot>
```

Build and execute the snapshot in one step. Equivalent to [`Snapshot::create(self.build()?)`](#snapshotcreate).

<p className="msb-label">Returns</p>

<div className="msb-params">
  <div className="msb-param">
    <div className="msb-param-key"><a className="msb-type" href="#instance-methods">Snapshot</a></div>
    <div className="msb-param-desc">The created artifact handle.</div>
  </div>
</div>

## Types

### SnapshotHandle

<p className="msb-backref">Returned by <a href="#snapshotget">Snapshot::get()</a> · <a href="#snapshotlist">Snapshot::list()</a> · <a href="#snapshotimport">Snapshot::import()</a></p>

A lightweight handle backed by a local index row. Use [`open()`](#h-open) to read the artifact metadata, and [`Snapshot::verify()`](#snap-verify) for explicit content verification. All accessors are listed under [SnapshotHandle methods](#snapshothandle-methods).

| Method           | Type                                        | Description                                  |
| ---------------- | ------------------------------------------- | -------------------------------------------- |
| digest()         | `&str`                                      | Manifest digest (`sha256:hex`)               |
| name()           | `Option<&str>`                              | Name alias; `None` for digest-only entries   |
| parent\_digest() | `Option<&str>`                              | Parent snapshot digest, or `None` for a root |
| image\_ref()     | `&str`                                      | Source image reference                       |
| format()         | [`SnapshotFormat`](#snapshotformat)         | On-disk upper format                         |
| size\_bytes()    | `Option<u64>`                               | Upper file size at index time                |
| created\_at()    | `chrono::NaiveDateTime`                     | Creation time from the manifest              |
| path()           | `&Path`                                     | Local artifact directory                     |
| open()           | `Result<`[`Snapshot`](#instance-methods)`>` | Open the underlying artifact                 |
| remove(force)    | `Result<()>`                                | Remove this snapshot                         |

### SnapshotConfig

<p className="msb-backref">Used by <a href="#snapshotcreate">Snapshot::create()</a> · returned by <a href="#build">build()</a></p>

Inputs to create a snapshot. A type alias for `SnapshotSpec`. Usually built via [`SnapshotBuilder`](#snapshotbuilder) rather than constructed directly.

| Field             | Type                                          | Description                                          |
| ----------------- | --------------------------------------------- | ---------------------------------------------------- |
| source\_sandbox   | `String`                                      | Name of the source sandbox; must be stopped          |
| destination       | [`SnapshotDestination`](#snapshotdestination) | Where to write the artifact                          |
| labels            | `Vec<(String, String)>`                       | User-supplied labels                                 |
| force             | `bool`                                        | Overwrite an existing artifact at the destination    |
| record\_integrity | `bool`                                        | Compute and record upper-layer integrity at creation |

### SnapshotDestination

<p className="msb-backref">Used by <a href="#destination">destination()</a> · <a href="#snapshotconfig">SnapshotConfig.destination</a></p>

Where to place a new snapshot artifact. The builder's [`name()`](#name) and [`path()`](#path), and the handle's [`snapshot()`](#h-snapshot) / [`snapshot_to()`](#h-snapshot_to), construct this enum internally so callers rarely import it.

| Variant | Fields    | Description                                                  |
| ------- | --------- | ------------------------------------------------------------ |
| `Name`  | `String`  | Bare name resolved under the default snapshots directory     |
| `Path`  | `PathBuf` | Explicit absolute or relative path to the artifact directory |

### SnapshotFormat

<p className="msb-backref">Used by <a href="#h-format">format()</a> · <a href="#manifest">Manifest.format</a></p>

On-disk format of the captured upper layer. Today only `Raw` is produced; the variant exists so qcow2 chains drop in later without a schema migration.

| Value   | Description                                |
| ------- | ------------------------------------------ |
| `Raw`   | Raw ext4 image, sparse on disk             |
| `Qcow2` | qcow2 with optional backing chain (future) |

### ExportOpts

<p className="msb-backref">Used by <a href="#snapshotexport">Snapshot::export()</a></p>

Options for [`Snapshot::export()`](#snapshotexport). Implements `Default`; `ExportOpts::default()` writes the head snapshot only, zstd-compressed.

| Field         | Type   | Description                                                                                                               |
| ------------- | ------ | ------------------------------------------------------------------------------------------------------------------------- |
| with\_parents | `bool` | Walk the parent chain and include each ancestor in the archive                                                            |
| with\_image   | `bool` | Bundle the OCI image artifacts (EROFS layers, fsmeta, VMDK descriptor) from the global cache so the archive boots offline |
| plain\_tar    | `bool` | Skip zstd compression and write a plain `.tar`. Default: zstd                                                             |

### SnapshotVerifyReport

<p className="msb-backref">Returned by <a href="#snap-verify">verify()</a></p>

Result of explicit snapshot verification.

| Field  | Type                                      | Description                             |
| ------ | ----------------------------------------- | --------------------------------------- |
| digest | `String`                                  | Snapshot manifest digest                |
| path   | `PathBuf`                                 | Artifact directory                      |
| upper  | [`UpperVerifyStatus`](#upperverifystatus) | Upper-layer content verification result |

### UpperVerifyStatus

<p className="msb-backref">Used by <a href="#snapshotverifyreport">SnapshotVerifyReport.upper</a></p>

Upper-layer content verification result.

| Variant       | Fields                                          | Description                                                  |
| ------------- | ----------------------------------------------- | ------------------------------------------------------------ |
| `NotRecorded` | -                                               | No content integrity descriptor was recorded in the manifest |
| `Verified`    | - `algorithm: String` <br /> - `digest: String` | Recorded integrity matched the computed digest               |

### Manifest

<p className="msb-backref">Returned by <a href="#snap-manifest">manifest()</a></p>

The snapshot artifact manifest, the source of truth for an artifact. Re-exported as `microsandbox::snapshot::Manifest`. Its SHA-256 digest over the canonical byte form is the snapshot's identity. Field order is load-bearing (it determines the canonical byte layout) and must not be reordered.

| Field           | Type                                | Description                                            |
| --------------- | ----------------------------------- | ------------------------------------------------------ |
| schema          | `u32`                               | Manifest schema version; readers reject unknown values |
| format          | [`SnapshotFormat`](#snapshotformat) | On-disk format of the upper layer                      |
| fstype          | `String`                            | Filesystem type inside the upper (e.g. `ext4`)         |
| image           | [`ImageRef`](#imageref)             | Image the snapshot was taken from                      |
| parent          | `Option<String>`                    | Parent snapshot digest, or `None` for a root           |
| created\_at     | `String`                            | RFC 3339 creation timestamp                            |
| labels          | `BTreeMap<String, String>`          | User-supplied labels, sorted by key in canonical form  |
| upper           | [`UpperLayer`](#upperlayer)         | The captured upper layer                               |
| source\_sandbox | `Option<String>`                    | Best-effort name of the source sandbox (informational) |

### ImageRef

<p className="msb-backref">Used by <a href="#manifest">Manifest.image</a></p>

Reference to the OCI image the snapshot was taken from. Re-exported as `microsandbox::snapshot::ImageRef`.

| Field            | Type     | Description                                                           |
| ---------------- | -------- | --------------------------------------------------------------------- |
| reference        | `String` | Human-readable image reference (e.g. `docker.io/library/python:3.12`) |
| manifest\_digest | `String` | Digest of the OCI manifest, in `sha256:hex` form                      |

### UpperLayer

<p className="msb-backref">Used by <a href="#manifest">Manifest.upper</a></p>

Captured upper-layer file metadata. Re-exported as `microsandbox::snapshot::UpperLayer`.

| Field       | Type                                            | Description                                                      |
| ----------- | ----------------------------------------------- | ---------------------------------------------------------------- |
| file        | `String`                                        | Filename inside the artifact directory (e.g. `upper.ext4`)       |
| size\_bytes | `u64`                                           | Apparent size in bytes (ext4 virtual size; sparse on disk)       |
| integrity   | `Option<`[`UpperIntegrity`](#upperintegrity)`>` | Optional content integrity descriptor; `None` on local hot paths |

### UpperIntegrity

<p className="msb-backref">Used by <a href="#upperlayer">UpperLayer.integrity</a></p>

Content integrity descriptor for the captured upper layer.

| Field     | Type     | Description                                                   |
| --------- | -------- | ------------------------------------------------------------- |
| algorithm | `String` | Digest algorithm name (e.g. `msb-sparse-sha256-v1`)           |
| digest    | `String` | Algorithm output, in `sha256:hex` form for current algorithms |
