Skip to documentation
API + guides

01Documentation

Snapshot And Restore

Sandbox rootfs snapshots are point-in-time copies of a sandbox writable root filesystem. Use them when you want to checkpoint an initialized workspace, claim new sandboxes from that known filesystem state, roll an existing sandbox back, or fork a sandbox into an isolated child sandbox.

Use this page when you need to:

  • create named rootfs snapshots from a running or paused sandbox
  • claim a new sandbox with a named rootfs snapshot
  • restore a paused sandbox rootfs from a snapshot
  • fork a running or paused sandbox into another paused sandbox
  • inspect the Rebase contract and its current Cloud availability limitation
  • understand how rootfs snapshots differ from pause/resume
ℹ

Creating snapshots and forking accept a running or paused source sandbox. With the default filesystem-only fork, running sources are briefly barriered and checkpointed, then remain running. The storage-only restore below requires a paused target and leaves it paused. The explicit snapshot recovery operation can instead retire a running source, restore the selected snapshot and launch a fresh runtime. Claiming with snapshot_id creates a new running sandbox from an existing snapshot and does not require a paused target sandbox.

How It Differs From Pause And Resume#

CapabilityPurposeCreates a named restore pointCreates another sandboxRequires paused sandbox
Pause/resumeRelease compute and later continue the same sandbox identity from its latest checkpointNoNoPause starts from a running sandbox; resume starts from a paused sandbox
SnapshotPublish an immutable point-in-time rootfs recordYesNoNo; running sources are checkpointed first
Claim with snapshot_idCreate a running sandbox initialized from a named snapshotUses an existing snapshotYesNo target sandbox required
RestoreMove a paused sandbox rootfs back to a snapshotUses an existing snapshotNoYes
Snapshot recoveryEnd old processes, restore the selected snapshot and launch a fresh runtimeUses an existing snapshotNoNo; the operation owns source retirement
ForkCreate an isolated paused sandbox from a source sandbox rootfsNoYesNo; running sources are checkpointed first
Rebase (not exposed by the current Cloud gateway)Carry file-level changes onto another attested Base artifactRetains the old head for a bounded rollback windowNoYes

Pause/resume keeps the latest checkpoint for one sandbox identity. Rootfs snapshots are explicit records that you can list, fetch, claim from, restore, and delete. Fork creates a new sandbox with Copy-on-Write rootfs isolation from the source rootfs state.

Use sandbox rootfs snapshots when the default writable filesystem is the state you want to version or fan out into another sandbox identity.

Explicit Snapshot Recovery#

POST /api/v1/sandboxes/{id}/snapshot-restore accepts an asynchronous recovery operation. It ends old processes and replaces writable RootFS with the selected snapshot. Supply a stable Idempotency-Key and all four request fields:

json
{ "expected_runtime_generation": 7, "snapshot_id": "rootfs-snapshot-example", "snapshot_generation_id": "rootfs-generation-example", "discard_process_state": true }

Use the snapshot response's generation_id as snapshot_generation_id. Create, list, get, and capture-observation responses expose the captured storage generation; it is independent of the sandbox's current runtime generation and current RootFS head. Older servers may omit this field. In that case, conditional recovery cannot proceed until the exact snapshot identity is available; do not substitute a current head or infer a generation from the snapshot ID.

Use the observed source runtime generation and the snapshot's exact head generation. The operation pins the selected data when admitted, so later snapshot expiry or deletion does not cancel it. Source retirement, writer fencing, head replacement and fresh runtime launch are coordinated outside guest execution. Managed credential owners must complete final-capture custody before retirement; this can keep an operation in pausing until its owner acknowledges durable encrypted credential retention.

After a timeout, keep every request field and the original key. Recover the acknowledgement with GET /api/v1/sandboxes/{id}/snapshot-restore-operations?request_key=..., or read a known operation at GET /api/v1/sandboxes/{id}/snapshot-restore-operations/{operation_id}. Both reads require sandbox:read, remain independent of guest health and never submit work. Submission requires sandbox:write. A missing receipt does not prove a concurrent submission cannot still commit; an exact retry must retain the original key.

restored_rootfs_generation_id proves that head replacement and the cold resume child committed together. Only succeeded and result_runtime_generation prove the replacement runtime launched; they do not attest application health. failed and superseded remain terminal historical results. Neither a client timeout nor Ctrl-C cancels accepted work. This operation is never an automatic fallback from memory restoration.

SDK entry points are Go RestoreSandboxSnapshot, JavaScript client.sandboxes.restoreSnapshot, and Python client.sandboxes.restore_snapshot. The CLI exposes s0 sandbox restore-snapshot and the read-only restore-snapshot-status; submission requires explicit source and snapshot generation flags, an idempotency key and --discard-process-state.

Applications must separately qualify native credential restoration and forks. This runtime API does not enable unqualified native product recovery or bypass application credential guards.

State Model#

  • Create snapshot creates a snapshot record from the source sandbox's current rootfs head. If the source is running, Sandbox0 briefly barriers the sandbox, checkpoints its writable rootfs, and then releases the source back to running.
  • Claim with snapshot_id creates a running sandbox and initializes its writable rootfs from the selected snapshot before process APIs are initialized.
  • Restore changes a paused target sandbox rootfs head to the selected snapshot and leaves the sandbox paused.
  • Fork creates a new paused sandbox with the source sandbox configuration and an isolated rootfs fork. If the source is running, Sandbox0 briefly barriers the sandbox, checkpoints its writable rootfs, and then releases the source back to running. The fork request can override lifecycle ttl and hard_ttl.
  • Rebase applies the paused sandbox's file-level changes to a different attested immutable Base artifact, publishes one new durable generation, and retains the old generation for a bounded rollback window.
  • Resume is required for process execution, file watching, services, and SSH after restore or fork. The persistent Files API can read paused RootFS files without resuming; it also supports edits on filesystem-only paused sandboxes. Memory-paused sandboxes permit offline reads only. A sandbox claimed with snapshot_id starts running.
  • Deleting a snapshot does not modify any sandbox already claimed or restored from it, and it does not affect forks created from the same rootfs state.

Rootfs Path Semantics#

Snapshots, snapshot claims, restore, and filesystem-only fork use the same block-COW persistence boundary as pause and resume. Ordinary writable RootFS paths such as /var/tmp and workspace directories are captured. /tmp, virtual runtime mounts such as /proc, /dev, and /sys, and template-defined ephemeralMounts are recreated for each runtime generation and are not snapshot content.

The default /tmp capacity is half the sandbox memory limit. Its temporary filesystem uses a private disk file on the compute node. Cached file pages still count toward memory usage, but can be reclaimed under memory pressure. The capacity itself reserves no memory. A template can set an explicit /tmp capacity using ephemeralMounts. /dev/shm and other ephemeral mounts remain memory-backed. Temporary files are discarded when the runtime ends, including filesystem-only pause/resume, and never enter a RootFS checkpoint. Explicit memory checkpoints can retain supported runtime tmpfs state separately from RootFS.

ℹ

The rootfs snapshot API stores snapshot metadata including name, description, and optional expires_at. An expiry must be in the future when creating the snapshot; expired snapshots cannot be used for new claims or restores. Retention limits can also remove older snapshots. Delete snapshots explicitly when cleanup workflows no longer need them.

Capture A Specific Running Generation#

Controllers that already qualified a running instance can use POST /api/v1/sandboxes/{id}/snapshots/capture with expected_runtime_generation and an Idempotency-Key. The manager checks the generation while admitting the exact source writer. A new request against a paused or different generation returns a conflict; it never wakes the sandbox.

After an uncertain response, reuse the original key, generation and metadata. The same capture transaction returns its original immutable snapshot when complete, including after the source later pauses or changes generation. Do not fetch a fresh generation and silently create a replacement request. This is a RootFS capture: running processes continue and their memory is not part of the named snapshot. Older servers without this endpoint return an error; clients must not fall back to the unconditional snapshot endpoint.

typescript
const snapshot = await client.sandboxes.captureRootFSSnapshot(sandbox.id, { expectedRuntimeGeneration: 7, idempotencyKey: "before-edit-7", name: "before edit", });

The Go SDK exposes CaptureSandboxRootFSSnapshot; Python exposes client.sandboxes.capture_rootfs_snapshot. Each submits one conditional request and leaves any retry decision to the caller.

To resolve a lost response without permission to start more work, use GET /api/v1/sandboxes/{id}/snapshots/capture with the original Idempotency-Key and expected_runtime_generation query parameter. This reads the original immutable receipt and never starts, retries or repairs a capture. It requires sandbox read permission. JavaScript exposes getCapturedRootFSSnapshot(sandboxId, { expectedRuntimeGeneration, idempotencyKey }), Go exposes GetCapturedSandboxRootFSSnapshot, and Python exposes get_captured_rootfs_snapshot.

A pending capture or unavailable observation returns 503. A conflicting request or deleted/expired original snapshot returns 409. A 404 means the owned sandbox or original capture was not found; it does not prove cancellation and must not clear an outstanding operation fence. A caller may separately requalify a retry of the same original capture, but must never interpret lookup failure as permission to create a replacement or use a different generation.

Storage Encryption#

When application-layer object encryption is enabled, manager and ctld encrypt persisted RootFS block data and descriptors before writing them to S3-compatible storage. With aes256gcm-rsa, each object receives a random data key, its contents are independently authenticated, and the data key is wrapped with the installation's RSA key.

This is service-side encryption, not end-to-end encryption: manager and the active ctld hold the installation key and can decrypt RootFS objects while serving sandbox operations. Enabling encryption does not rewrite historical objects automatically. Sandbox0 Cloud manages the object-storage encryption configuration and keys; these settings are not part of the sandbox API.

Initialize Once, Claim Many#

RootFS snapshots plus claim-time snapshot_id can act like a lightweight custom RootFS when your changes are ordinary filesystem state. Start from a compatible template, initialize the sandbox, publish a RootFS snapshot, then claim new sandboxes from that snapshot. All compatible templates share the same resource-neutral carrier pool.

Use this pattern for:

  • package installs and dependency caches
  • cloned repositories and checked-out branches
  • generated build artifacts that future runs should inherit
  • local tool configuration written into the sandbox filesystem

Typical workflow:

  1. claim a sandbox from a compatible builtin or team-owned template
  2. install dependencies or prepare the workspace inside the sandbox rootfs
  3. create a named rootfs snapshot for the initialized state
  4. optionally pause or delete the seed sandbox after the snapshot is created
  5. claim each task sandbox with the same template and snapshot_id
bash
SEED_SANDBOX_ID="$(s0 -o json sandbox create --template default --hard-ttl 86400 | jq -r '.id')" # Initialize the rootfs with your normal sandbox commands, file writes, or SSH session. SNAPSHOT_ID="$(s0 -o json sandbox snapshot create "$SEED_SANDBOX_ID" \ --name python-deps-v1 \ --description "Default template after Python dependency install" \ | jq -r '.id')" TASK_SANDBOX_ID="$(s0 -o json sandbox create \ --template default \ --snapshot-id "$SNAPSHOT_ID" \ --hard-ttl 3600 \ | jq -r '.id')"

Claiming with snapshot_id is the preferred path for reusable custom rootfs state because the result is a fresh running sandbox that uses the snapshot's captured RootFS and image provenance, together with the requested template's compatible runtime configuration, resources, mounts, services, and network defaults. Use restore when you need to roll an existing paused sandbox back to a snapshot. Use fork when you specifically need a paused child sandbox cloned from a running or paused source.

For a longer walkthrough of this pattern, see Initialize Once, Claim Many.

ℹ

This pattern does not replace template-level configuration. Use a custom template when you need a different container image, resource limits, default network policy, environment defaults, or privileged runtime fields.

Rootfs Operation Lifecycle#

Create a snapshot from a running or paused sandbox. Pause the sandbox and wait until status is paused before restoring into it. Forking also accepts a running or paused source sandbox.

POST

/api/v1/sandboxes/{id}/pause

go
paused, err := client.PauseSandboxAndWait(ctx, sandbox.ID, nil) if err != nil { log.Fatal(err) } fmt.Printf("Sandbox status: %s\n", paused.Status)

Create A Snapshot#

Create a rootfs snapshot from a running or paused sandbox. A running source remains running after the snapshot is created.

POST

/api/v1/sandboxes/{id}/snapshots

Request Body#

FieldTypeDescription
namestringOptional snapshot name
descriptionstringOptional snapshot description
expires_atstringOptional future RFC3339 timestamp; expired snapshots are unavailable for new claims and restores
go
snapshot, err := client.CreateSandboxRootFSSnapshot(ctx, sandbox.ID, &apispec.CreateSandboxRootFSSnapshotRequest{ Name: apispec.NewOptString("before-agent-task"), Description: apispec.NewOptString("Workspace after dependency install"), }) if err != nil { log.Fatal(err) } fmt.Printf("Snapshot ID: %s\n", snapshot.ID)

On the Nomad/gVisor runtime, a running-source snapshot is bound to the exact live allocation, node incarnation, rootfs writer grant, writer epoch, and source generation observed when the operation starts. The checkpoint is published as a separate immutable filesystem, so the source writer and source rootfs head are unchanged. If the API connection or manager restarts, Sandbox0 recovers the same pending operation from PostgreSQL; it never substitutes a checkpoint from a newer source runtime.

List And Get Snapshots#

List snapshots created from a sandbox, or fetch a snapshot directly by snapshot ID.

GET

/api/v1/sandboxes/{id}/snapshots

GET

/api/v1/sandbox-rootfs-snapshots/{snapshot_id}

go
snapshots, err := client.ListSandboxRootFSSnapshots(ctx, sandbox.ID) if err != nil { log.Fatal(err) } for _, item := range snapshots.Snapshots { name := item.Name.Or("") fmt.Printf("%s %s\n", item.ID, name) } snapshot, err = client.GetSandboxRootFSSnapshot(ctx, snapshot.ID) if err != nil { log.Fatal(err) } fmt.Printf("Created at: %s\n", snapshot.CreatedAt)

Claim From A Snapshot#

Use snapshot_id on sandbox claim when you want a new running sandbox initialized from a named rootfs snapshot. The snapshot supplies the committed RootFS and its attested base image; choosing a template does not replace captured binaries with that template's current image. The requested template controls compatible runtime configuration, resources, mount declarations, services, network defaults, and other runtime settings. Sandbox0 applies the snapshot rootfs before file APIs, contexts, services, and SSH are initialized.

POST

/api/v1/sandboxes

Request Body#

FieldTypeDescription
templatestringTemplate ID to use
snapshot_idstringRootfs snapshot ID used to initialize the new sandbox writable rootfs
configobjectOptional sandbox configuration
go
sandbox, err := client.ClaimSandbox(ctx, "default", sandbox0.WithSandboxSnapshotID(snapshot.ID), sandbox0.WithSandboxHardTTL(3600), ) if err != nil { log.Fatal(err) } fmt.Printf("Sandbox ID: %s\n", sandbox.ID)

Restore A Sandbox Rootfs#

Restore moves a paused target sandbox rootfs to the selected snapshot and returns the sandbox status. The sandbox stays paused after restore. Persistent Files API access does not require resume; resume before using contexts, file watching, services, or SSH.

POST

/api/v1/sandboxes/{id}/rootfs/restore

Request Body#

FieldTypeDescription
snapshot_idstringRootfs snapshot ID to restore
ℹ

Restore is destructive for the target sandbox rootfs. Files changed after the restored snapshot are no longer the target sandbox head after restore.

go
restored, err := client.RestoreSandboxRootFS(ctx, sandbox.ID, apispec.RestoreSandboxRootFSRequest{ SnapshotID: snapshot.ID, }) if err != nil { log.Fatal(err) } fmt.Printf("Restored snapshot %s, status=%s\n", restored.SnapshotID, restored.Status) _, err = client.ResumeSandboxAndWait(ctx, sandbox.ID, nil) if err != nil { log.Fatal(err) }

Fork A Sandbox#

Fork creates a new paused sandbox from a running or paused source sandbox rootfs. A running source is briefly barriered and checkpointed during the operation, then remains running. The fork receives its own sandbox ID. Writes made after resuming the fork do not modify the source sandbox rootfs.

On the Nomad/gVisor runtime, Sandbox0 persists the fork operation and paused target before contacting the source node. The authenticated node request is bound to the exact live allocation, node incarnation, rootfs writer grant, writer epoch, and source generation. If the API connection or manager restarts after checkpoint publication, background reconciliation recovers the committed target from PostgreSQL without freezing a newer source state again. A never-run fork target starts at runtime generation 0; its first resume claims a fresh slot as generation 1.

POST

/api/v1/sandboxes/{id}/fork

Omit the request body to inherit the source sandbox lifecycle configuration and its existing absolute expiry deadlines. Inheritance does not start a new full TTL window. To set a new lifecycle window for the fork, pass config.ttl and/or config.hard_ttl. Positive values are counted from the fork creation time, and 0 disables that expiration path.

Set config.auto_resume to false to create the child with automatic resume disabled. The same transaction disables resume on its inherited ingress routes; the parent's settings are unchanged. This allows configuring a paused child before explicitly resuming it. A retry with the same idempotency key cannot change an explicit override to a conflicting value. This option does not remove inherited files or credentials.

To bind the capture to a specific source instance, supply expected_runtime_generation and a stable Idempotency-Key. Admission checks the source while holding its lifecycle lock. After an uncertain reply, retain the original generation and key: retries recover the original fork even if the parent has since resumed, and a conflicting generation returns an error. Generation 0 is valid for a never-run paused source. Memory fork conditions must leave room for the parent's successor generation within the safe integer range. Omitting the condition retains the existing unconditional API behavior.

json
{ "config": { "ttl": 300, "hard_ttl": 3600 } }
go
forked, err := client.ForkSandbox(ctx, sandbox.ID, nil) if err != nil { log.Fatal(err) } fmt.Printf("Forked sandbox: %s\n", forked.Sandbox.ID) _, err = client.ResumeSandboxAndWait(ctx, forked.Sandbox.ID, nil) if err != nil { log.Fatal(err) }

Explicit Memory Fork#

Fork defaults to filesystem-only state. Experimental memory fork uses the same endpoint with memory: true and requires a stable Idempotency-Key header. The key and request body must stay unchanged on retries.

http
POST /api/v1/sandboxes/sb_source/fork Content-Type: application/json Idempotency-Key: branch-task-001 { "memory": true, "config": { "ttl": 300, "hard_ttl": 3600 } }

For a paused source, memory fork requires a retained memory checkpoint matching its RootFS head. For a running source, the current implementation captures and retires the source runtime, commits the paused child and resumes the parent into a new carrier. It does not keep the original parent runtime executing during capture. The parent's runtime ID and generation change; its original soft TTL is retained, and deletion or expiry cannot be undone by fork completion.

The operation returns 503 unavailable while capture or parent resume is still pending. Retry with the same key and body. A 201 response identifies the paused child; it does not start the child. Resume that child with memory: true to continue its captured processes. The parent and child use independent writable RootFS branches and resource leases; immutable checkpoint image data is shared.

python
from sandbox0.apispec.models.fork_sandbox_request import ForkSandboxRequest forked = client.sandboxes.fork( sandbox.id, ForkSandboxRequest(memory=True), idempotency_key="branch-task-001", ) client.sandboxes.resume_and_wait(forked.sandbox.id, memory=True)

The SDK call above performs one request. If it reports a pending operation, retry it with the same key and body before attempting child resume. In TypeScript, use client.sandboxes.fork(id, { memory: true }, { idempotencyKey: key }). In Go, use ForkSandboxWithOptions with ForkSandboxRequest.Memory and ForkSandboxOptions.IdempotencyKey.

Fork rebinds the captured runtime and session identity to the child without restarting guest processes. Previously queued parent webhook events are retained as inherited records and are not sent as child events. New child events carry the child's identity. External connections are not guaranteed to survive.

Memory fork has the compatibility and transfer costs described in Pause And Resume. Named snapshots, snapshot claims, restore and rebase remain RootFS operations; they do not create or restore process memory.

Rebase A Paused Sandbox#

ℹ

Rebase is not exposed by the current Sandbox0 Cloud public gateway. The SDK and CLI define helpers for this contract, but they cannot make it available on a server that does not expose the endpoint. The examples below describe the contract for a deployment that supports it, not a working Cloud workflow.

Use rebase when a sandbox must move to a newer immutable Base artifact while preserving file-level changes from its current writable rootfs. The target Base artifact must already be attested and available in the same region. Rebase does not accept an image tag or build an image implicitly.

PUT

/api/v1/sandboxes/{id}/rootfs/rebase

Request Body#

FieldTypeDescription
target_base_artifact_digeststringRequired canonical SHA-256 digest of the target attested Base artifact
rollback_ttlintegerOptional rollback retention in seconds; defaults to 86400; explicit values must be from 1 to 604800
go
rebased, err := client.RebaseSandboxRootFS(ctx, sandbox.ID, apispec.RebaseSandboxRootFSRequest{ TargetBaseArtifactDigest: "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", RollbackTTL: apispec.NewOptInt32(86400), }) if err != nil { log.Fatal(err) } fmt.Printf("Rebased generation: %s\n", rebased.GenerationID)

The sandbox must already be paused, have no live runtime slot or writer grant, and use the block-COW storage format. Recovery of the same internal operation returns its original target generation; a changed target digest or rollback window for that operation is rejected with 409 Conflict. The public SDK/CLI rebase helpers do not expose a stable rebase operation key. Repeating the same payload is therefore not a guarantee of recovering the original operation after a lost response.

Rebase is file-aware rather than a raw block transplant: the worker mounts the old Base, current source, and target Base in isolated branches, computes the filesystem change set, applies it to the target, validates the result, and only then publishes immutable objects. PostgreSQL commits the target generation and rollback pin atomically. Manager reconciliation can therefore recover a committed internal operation after restart or response loss without executing that operation's merge again.

ℹ

Keep the sandbox paused until rebase returns successfully. The previous head is retained only until rollback_expires_at; expiry permits normal RootFS garbage collection to reclaim it.

Delete A Snapshot#

Delete a rootfs snapshot when you no longer need it. This does not modify any sandbox that already restored from that snapshot, and it does not affect forks created from the same rootfs state.

DELETE

/api/v1/sandbox-rootfs-snapshots/{snapshot_id}

go
_, err := client.DeleteSandboxRootFSSnapshot(ctx, snapshot.ID) if err != nil { log.Fatal(err) } fmt.Println("Snapshot deleted")

Typical Pattern#

For coding-agent and test-generation workflows, a common pattern is:

  1. claim a sandbox and initialize the repository or dependency cache
  2. write a marker, lockfile, or workspace state that future tasks should inherit
  3. create a rootfs snapshot for that initialized state; a running source remains running
  4. claim each task sandbox with the same template and snapshot_id
  5. run task-specific work in the newly claimed sandbox

Next Steps#

Snapshot retention quota#

Each sandbox retains at most 10 public RootFS snapshots by default. Creating another snapshot automatically removes the oldest excess snapshots while keeping the new one. This applies to both running and paused sandboxes. Operators can change the regional default or a team's snapshots_per_sandbox quota (minimum 1). Reduced quotas and existing excess snapshots are reconciled by background maintenance. Internal template-build captures are excluded.

Automatically removed snapshots no longer appear in snapshot lists and cannot be used for a new restore or claim. Sandboxes and templates already derived from a snapshot retain their own references; shared blocks remain until no owner needs them. Physical storage reclamation happens asynchronously through RootFS GC.

Snapshot storage billing counts data shared with other snapshots and sandboxes once within a team. Shared base images are excluded. Releasing a snapshot stops its storage charge at the recorded release time for data that no other user owner retains; platform cleanup delays and recovery copies do not extend that charge. See Cloud pricing.

Read the original RootFS fork#

GET /api/v1/sandboxes/{id}/fork takes the original Idempotency-Key header and expected_runtime_generation query parameter (including generation zero). It requires sandbox:read and the same authenticated identity as the original fork. The manager reads retained external authority without contacting the guest, retrying capture or resuming the child. A 404 does not prove cancellation.

A successful receipt binds the original source and child, committed durable head, writer epoch and child wake policy. The child must still be paused, never run, and retain its original configuration and claim. Memory forks are excluded; changed or missing retained evidence conflicts or remains unavailable. A receipt is an observation, not a credential-safety attestation or a reservation for a later mutation. Retain the original operation after uncertainty.

Launch the original fork child#

POST /api/v1/sandboxes/{child_id}/fork-launch starts only the original, never-run RootFS fork at generation zero. It requires sandbox:write, a stable Idempotency-Key, and these conditions from the fork observation:

json
{ "fork_operation_id": "original-fork-operation", "filesystem_id": "child-filesystem", "head_generation_id": "original-child-head", "writer_epoch": 1 }

The child must retain its original configuration with automatic wake disabled. The manager records the first launch before contacting the node and recovers that same operation after a timeout or restart. A pending submission returns 202; completed or logically aborted history returns 200. Memory forks are not eligible for this cold-launch operation.

Read the result with GET /api/v1/sandboxes/{child_id}/fork-launch, the same Idempotency-Key, and the four original conditions as query parameters. The GET requires sandbox:read and never submits or retries work. Keep the original key and conditions after uncertainty, including a 503 response. A 404 does not prove cancellation; do not replace the request with freshly observed coordinates.

The result distinguishes pending, completed and aborted. Completed history retains a digest of the external launch proof and its completion time even after a later lifecycle. current only compares the owner's recorded lifecycle; it does not establish runtime health or grant a lease. An aborted result does not prove physical absence. Credential enrollment and publication require their own admission checks.