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

# Lifecycle

> Checkpoint, start from checkpoint, pause, sleep, resume, schedule wakes, upgrade, and terminate Sailboxes

Sailboxes preserve their writable disk, in-memory state, and in-flight network
requests across checkpoints and resumes.

The examples below assume a running Sailbox `sb`.

<CodeGroup>
  ```python Python theme={null}
  checkpoint = sb.checkpoint()  # Create a durable checkpoint handle
  child = sail.Sailbox.from_checkpoint(checkpoint.checkpoint_id, name="rollout-1")
  sb.pause()                    # Checkpoint and pause until explicit resume
  sb.sleep()                    # Checkpoint and sleep until network ingress, exec, or resume
  sb.resume()                   # Resume a paused or sleeping Sailbox
  sb.upgrade()                  # Update the Sailbox runtime by rebooting on the same disk
  sb.terminate()                # Permanently destroy the Sailbox
  ```

  ```typescript TypeScript theme={null}
  const checkpoint = await sb.checkpoint(); // Create a durable checkpoint handle
  const child = await Sailbox.fromCheckpoint({
    checkpointId: checkpoint.checkpointId,
    name: "rollout-1",
  });
  await sb.pause(); // Checkpoint and pause until explicit resume
  await sb.sleep(); // Checkpoint and sleep until network ingress, exec, or resume
  await sb.resume(); // Resume a paused or sleeping Sailbox
  await sb.upgrade(); // Update the Sailbox runtime by rebooting on the same disk
  await sb.terminate(); // Permanently destroy the Sailbox
  ```

  ```rust Rust theme={null}
  use sail::CheckpointOptions;

  // Create a durable checkpoint handle
  let checkpoint = sb.checkpoint(CheckpointOptions::default()).await?;
  let child = client
      .create_from_checkpoint(&checkpoint.checkpoint_id, Some("rollout-1"), /* timeout */ None)
      .await?;
  sb.pause().await?; // Checkpoint and pause until explicit resume
  sb.sleep(/* wake_at */ None).await?; // Checkpoint and sleep until ingress, exec, or resume
  sb.resume().await?; // Resume a paused or sleeping Sailbox
  sb.upgrade().await?; // Update the Sailbox runtime
  sb.terminate().await?; // Permanently destroy the Sailbox
  ```
</CodeGroup>

Sail may also sleep a Sailbox on its own, but only when nothing would notice:
no CPU or network activity, no process waiting on a timer, and no open
connections a sleep would break. A slept Sailbox wakes transparently on
traffic or the next operation.

## Checkpoint

`checkpoint()` creates a durable checkpoint handle. Running Sailboxes are
snapshotted first. Paused and sleeping Sailboxes return a handle to their
existing checkpoint without waking.

<CodeGroup>
  ```python Python theme={null}
  sb.exec("python3 setup.py").wait()
  checkpoint = sb.checkpoint(name="after-setup", ttl_seconds=30 * 86400)
  print(checkpoint.expires_at)
  ```

  ```typescript TypeScript theme={null}
  await (await sb.exec("python3 setup.py")).wait();
  const checkpoint = await sb.checkpoint({
    name: "after-setup",
    ttlSeconds: 30 * 86400,
  });
  console.log(checkpoint.expiresAt);
  ```

  ```rust Rust theme={null}
  use sail::CheckpointOptions;
  use std::time::Duration;

  use sail::ExecOptions;

  let setup = sb
      .exec(
          vec!["python3".to_string(), "setup.py".to_string()],
          ExecOptions::default(),
      )
      .await?;
  setup.wait().await?;
  let checkpoint = sb
      .checkpoint(CheckpointOptions {
          name: Some("after-setup".to_string()),
          ttl: Some(Duration::from_secs(30 * 86400)),
      })
      .await?;
  println!("{:?}", checkpoint.expires_at);
  ```
</CodeGroup>

Call `checkpoint()` after important setup, such as installing packages,
fetching remote data, or writing files. On host failure, Sail restores from the
most recent completed checkpoint and does not replay commands that ran before
that checkpoint.

`name` labels the handle. The TTL, when set, overrides the server's default
retention window. Set it when you keep a checkpoint to reuse as a template, so
the handle does not expire while you still need it. The returned handle carries
the expiry time (`expires_at`), when it becomes eligible for garbage
collection.

## Start From Checkpoint

Create a separate running Sailbox from a durable checkpoint handle:

<CodeGroup>
  ```python Python theme={null}
  checkpoint = sb.checkpoint()
  child = sail.Sailbox.from_checkpoint(
      checkpoint.checkpoint_id,
      name="experiment-1",
  )
  ```

  ```typescript TypeScript theme={null}
  const checkpoint = await sb.checkpoint();
  const child = await Sailbox.fromCheckpoint({
    checkpointId: checkpoint.checkpointId,
    name: "experiment-1",
  });
  ```

  ```rust Rust theme={null}
  use sail::CheckpointOptions;

  let checkpoint = sb.checkpoint(CheckpointOptions::default()).await?;
  let child = client
      .create_from_checkpoint(&checkpoint.checkpoint_id, Some("experiment-1"), /* timeout */ None)
      .await?;
  ```
</CodeGroup>

The child gets new Sail identity and networking. Active TCP connections are
reset in the child. A child starts with no inherited ingress, so add the ports
the child should publish with
[`expose`](/sailboxes-networking#add-or-remove-ports-at-runtime).

Sleeping and paused Sailboxes can be cloned too: `checkpoint()` returns the
existing checkpoint handle without waking the parent. Starting multiple
children from the same checkpoint reuses the same checkpoint artifacts, so the
second and later children avoid re-checkpointing the parent.

## Fork

`fork()` clones a Sailbox in one call, without creating a durable checkpoint
first:

<CodeGroup>
  ```python Python theme={null}
  child = sb.fork(name="experiment-1")
  ```

  ```typescript TypeScript theme={null}
  const child = await sb.fork({ name: "experiment-1" });
  ```

  ```rust Rust theme={null}
  use sail::ForkOptions;

  let child = sb
      .fork(ForkOptions {
          name: Some("experiment-1".into()),
          ..Default::default()
      })
      .await?;
  ```
</CodeGroup>

The child is a point-in-time copy of the parent's memory and writable disk,
and the parent keeps running unchanged. A sleeping or paused parent forks
without waking. The child is a new Sailbox with
its own identity: open TCP connections are reset in the child, and it starts
with no inherited ingress ports. Add the ports it should publish with
[`expose`](/sailboxes-networking#add-or-remove-ports-at-runtime).

The two clone paths differ in what you keep. `fork` is one call and keeps
nothing: the child starts running, and there is no artifact to manage or
reuse. `checkpoint` returns a durable handle you can start any number of
Sailboxes from later with `from_checkpoint`, even after the parent is
terminated. So for fan-out, set up one Sailbox (install dependencies, load
your data), then `fork` it once per task. Take a `checkpoint` when you want
to keep that state around to boot from later.

## Pause

`pause()` checkpoints the Sailbox and powers it down until you explicitly resume
it:

<CodeGroup>
  ```python Python theme={null}
  sb.pause()
  sb.resume()
  ```

  ```typescript TypeScript theme={null}
  await sb.pause();
  await sb.resume();
  ```

  ```rust Rust theme={null}
  sb.pause().await?;
  sb.resume().await?;
  ```
</CodeGroup>

Use pause when you want to preserve state but do not want the Sailbox to wake on
network traffic.

## Sleep

`sleep()` checkpoints the Sailbox and powers it down until network ingress,
exec, or an explicit resume wakes it:

<CodeGroup>
  ```python Python theme={null}
  sb.sleep()
  ```

  ```typescript TypeScript theme={null}
  await sb.sleep();
  ```

  ```rust Rust theme={null}
  sb.sleep(/* wake_at */ None).await?;
  ```
</CodeGroup>

Use sleep for idle services that should wake when they receive traffic.

## Resume

`resume()` restores a paused or sleeping Sailbox:

<CodeGroup>
  ```python Python theme={null}
  sb = sb.resume()
  ```

  ```typescript TypeScript theme={null}
  await sb.resume();
  ```

  ```rust Rust theme={null}
  sb.resume().await?;
  ```
</CodeGroup>

`exec` and file operations wake a sleeping Sailbox automatically, so binding
an existing box by id needs no explicit resume in any language.

## Sleep Until a Wake

Pass a wake time to `sleep()` to schedule a wall-clock wake as the Sailbox
goes down. When the moment arrives and the Sailbox is still sleeping, Sail
restores it:

<CodeGroup>
  ```python Python theme={null}
  from datetime import datetime, timedelta, timezone

  effective = sb.sleep(wake_at=datetime.now(timezone.utc) + timedelta(hours=2))
  ```

  ```typescript TypeScript theme={null}
  const effective = await sb.sleep(new Date(Date.now() + 2 * 60 * 60 * 1000));
  ```

  ```rust Rust theme={null}
  use sail::time::{Duration, OffsetDateTime};

  let effective = sb
      .sleep(Some(OffsetDateTime::now_utc() + Duration::hours(2)))
      .await?;
  ```

  ```bash CLI theme={null}
  sail box sleep <id> --wake-at 2h
  ```
</CodeGroup>

Each Sailbox holds one scheduled wake. A request earlier than the current
scheduled wake replaces it. A later request leaves the sooner wake in place.
The call returns the effective wake time (the sooner of the two). Schedule
the next wake after the current one fires if you need a series.

Calling `sleep` with a wake time on a Sailbox that is already sleeping just
updates the scheduled wake. The CLI accepts a delay like `30m` or `2h`, or
an absolute RFC 3339 timestamp. The wake can fire a little after the time
you set, so treat it as approximate. Schedule a minute or two of headroom
rather than an exact deadline. Paused Sailboxes only wake on an explicit
resume and reject scheduled wakes.

Use scheduled wakes for agents and services that sleep between runs and need
to be running again at a known time, such as a daily job or a follow-up an
agent set for itself.

## Upgrade

`upgrade()` reboots the Sailbox on its same disk onto the latest in-guest Sail
agent, picking up new features, fixes, and performance improvements without
recreating the Sailbox:

<CodeGroup>
  ```python Python theme={null}
  result = sb.upgrade()
  print(result.applied)
  ```

  ```typescript TypeScript theme={null}
  const { applied } = await sb.upgrade();
  ```

  ```rust Rust theme={null}
  let outcome = sb.upgrade().await?;
  println!("applied now: {}", outcome.applied);
  ```
</CodeGroup>

```bash theme={null}
sail box upgrade <id>
```

The filesystem is fully preserved; running processes stop and the Sailbox boots
fresh, like a machine reboot. Restart any long-running services afterwards.

On a running Sailbox the upgrade applies immediately and `applied` is true. On
a paused or sleeping Sailbox the upgrade is recorded without waking it and
`applied` is false; it applies automatically the next time the Sailbox wakes. A
Sailbox that is already on the current runtime version reports true without
rebooting.

A Sailbox whose runtime is too old for Sail to resume safely is
upgraded automatically the next time it wakes, as if `upgrade()` had been
called on it first.

Before a runtime version reaches that automatic-upgrade cutoff, `get` and
`list` return a `deprecation` notice with a deadline and upgrade instructions.
The CLI and Python/TypeScript SDKs also surface the first such notice as a
warning once per process (Python emits `SailDeprecationWarning` through the
`warnings` module); Rust callers
can install a callback with `sail::set_notice_handler`. Treat it as advance
notice to schedule `upgrade()` on your own terms before the deadline; it is not
an immediate failure.

## Terminate

`terminate()` permanently destroys the Sailbox:

<CodeGroup>
  ```python Python theme={null}
  sb.terminate()
  ```

  ```typescript TypeScript theme={null}
  await sb.terminate();
  ```

  ```rust Rust theme={null}
  sb.terminate().await?;
  ```
</CodeGroup>

Termination is not reversible. Use `pause()` or `sleep()` when you want to keep
the VM state for later.
