# Lifecycle, pausing, and hibernation
URL: https://metorial.com/docs/build/sandboxes/lifecycle

Control when sandbox machines pause or hibernate, and run hooks on every transition.

---

Machines don't need to run all the time. Pause a machine to freeze it exactly as it is, or hibernate it to stop using compute while its files stay on disk. Idle policies do this for you, and lifecycle hooks let your code react to each transition.

<PageIntro>
  <Learn>
    * The states a machine moves through
    * How pausing and hibernation differ
    * How to pause and hibernate idle machines automatically
    * How to run code on start, pause, resume, and terminate
  </Learn>

  <Reading title="Before you start">
    * [Run your first machine](/docs/build/sandboxes/quickstart)
  </Reading>
</PageIntro>

## Machine states [#machine-states]

<Mermaid
  chart="flowchart LR
  starting --> running
  running -->|pause| paused
  paused -->|start| running
  running -->|hibernate| hibernated
  paused -->|hibernate| hibernated
  hibernated -->|start| starting
  running -->|restart| starting
  running -->|delete| terminated
  paused -->|delete| terminated
  hibernated -->|delete| terminated"
/>

Transitions pass through short in-between states: `pausing`, `resuming`, `hibernating`, `restarting`, and `terminating`. A machine that can't boot ends up `failed`; its `failure` field says why (see [Monitoring](/docs/build/sandboxes/monitoring#failures)).

| Command     | Effect                                           |
| ----------- | ------------------------------------------------ |
| `start`     | Starts a paused or hibernated machine            |
| `pause`     | Freezes a running machine, memory included       |
| `hibernate` | Stops the machine; files on disk stay            |
| `restart`   | Boots the machine again on a fresh instance      |
| `touch`     | Records activity so idle policies wait longer    |
| `delete`    | Terminates the machine and deletes its root disk |

```bash
metorial-admin sandbox machines pause $MACHINE
metorial-admin sandbox machines start $MACHINE
```

Call `start` before you connect to a paused or hibernated machine.

## Pause or hibernate? [#pause-or-hibernate]

Pausing keeps everything: memory, running processes, open files. When you start the machine again, it continues exactly where it stopped, and it does so faster than a cold boot. A paused machine still holds its memory, so keep pauses short.

Hibernation stops the machine. The root disk and attached disks keep every file, but processes are gone. Starting a hibernated machine boots it fresh, runs your `setup` commands and entrypoint, and fires `start` hooks.

<Tip>
  For most agents, hibernation plus a good startup routine is the better choice. Write state to
  disk as you go, and let the entrypoint or a `start` hook bring services back up. An idle
  machine then uses no compute, and it comes back in a clean, known state. Use pausing for
  short breaks where an in-memory process can't be rebuilt quickly.
</Tip>

A machine that stays paused for a long time (8 hours or more) may be restarted by the platform. Set a hibernation policy so that happens on your terms.

## Pause and hibernate idle machines automatically [#pause-and-hibernate-idle-machines-automatically]

A lifecycle policy moves idle machines along for you:

| Field                            | What it does                                                                      |
| -------------------------------- | --------------------------------------------------------------------------------- |
| `pause_after_idle_seconds`       | Pause the machine after it's been idle this long                                  |
| `hibernate_after_paused_seconds` | Hibernate the machine after it's been paused this long                            |
| `connection_idle_seconds`        | How long a connection can go without traffic before it stops counting as activity |

Set a field to `null` to turn it off. If pausing is off and hibernation is on, the machine hibernates directly once it has been idle for the hibernation time.

Activity is anything that uses the machine: an open shell, file, or port connection with traffic, or a `touch` call. A connection that's silent for `connection_idle_seconds` no longer keeps the machine awake.

This policy hibernates a machine after 10 minutes without activity, which suits most agent workloads:

```bash
metorial-admin sandbox machines update $MACHINE --lifecycle-policy '{
  "pause_after_idle_seconds": null,
  "hibernate_after_paused_seconds": 600,
  "connection_idle_seconds": 300
}'
```

<CodeBlockTabs defaultValue="TypeScript" groupId="language" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    await metorial.sandbox.machines.update(machine.id, {
      lifecyclePolicy: {
        pauseAfterIdleSeconds: null,
        hibernateAfterPausedSeconds: 600,
        connectionIdleSeconds: 300
      }
    });

    // Keep the machine awake during long work that doesn't use a connection
    await metorial.sandbox.machines.touch(machine.id);
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    metorial.sandbox.machines.update(
        machine.id,
        lifecycle_policy={
            "pause_after_idle_seconds": None,
            "hibernate_after_paused_seconds": 600,
            "connection_idle_seconds": 300,
        },
    )

    # Keep the machine awake during long work that doesn't use a connection
    metorial.sandbox.machines.touch(machine.id)
    ```
  </CodeBlockTab>
</CodeBlockTabs>

The machine object tells you what comes next: `last_activity_at`, `pause_at`, `hibernates_at`, and `upcoming_events` (pauses, hibernations, and restarts scheduled within the next hour).

## Lifecycle hooks [#lifecycle-hooks]

Hooks run your code when a machine changes state. Each hook runs on one transition:

| `on`        | Runs when                                                                            |
| ----------- | ------------------------------------------------------------------------------------ |
| `start`     | The machine boots: after create, when starting from hibernation, and after a restart |
| `pause`     | The machine is about to pause                                                        |
| `resume`    | The machine continues after a pause                                                  |
| `terminate` | The machine is about to be deleted                                                   |

A hook is either a script inside the machine or an HTTP request to a port inside the machine:

* `wait`: the transition waits for the hook to finish. Use it for hooks that must complete first, such as flushing state before a pause.
* `timeout_seconds`: how long the hook may run before it counts as failed.

```bash
metorial-admin sandbox machines update $MACHINE --lifecycle-hooks-file hooks.json
```

<CodeBlockTabs defaultValue="TypeScript" groupId="language" mode="code">
  <CodeBlockTabsList>
    <CodeBlockTabsTrigger value="TypeScript">
      TypeScript
    </CodeBlockTabsTrigger>

    <CodeBlockTabsTrigger value="Python">
      Python
    </CodeBlockTabsTrigger>
  </CodeBlockTabsList>

  <CodeBlockTab value="TypeScript">
    ```typescript
    await metorial.sandbox.machines.update(machine.id, {
      lifecycleHooks: [
        {
          type: 'script',
          on: 'start',
          path: '/app/bin/restore.sh',
          arguments: ['--from', '/data'],
          wait: true,
          timeoutSeconds: 60
        },
        {
          type: 'http',
          on: 'pause',
          port: 3000,
          path: '/hooks/flush',
          wait: true,
          timeoutSeconds: 30
        }
      ]
    });
    ```
  </CodeBlockTab>

  <CodeBlockTab value="Python">
    ```python
    metorial.sandbox.machines.update(
        machine.id,
        lifecycle_hooks=[
            {"type": "script", "on": "start", "path": "/app/bin/restore.sh", "arguments": ["--from", "/data"], "wait": True, "timeout_seconds": 60},
            {"type": "http", "on": "pause", "port": 3000, "path": "/hooks/flush", "wait": True, "timeout_seconds": 30},
        ],
    )
    ```
  </CodeBlockTab>
</CodeBlockTabs>

Images can ship their own hooks. Set `ignore_image_hooks` to `true` to skip them.

## A good startup routine [#a-good-startup-routine]

Combine the runtime and hooks so a machine recovers on its own after every boot:

* Bake dependencies into a [custom image](/docs/build/sandboxes/custom-images) so boots stay fast.
* Use `runtime.setup` for quick preparation, such as creating directories or writing config from environment variables.
* Use the `entrypoint` for the long-running service your agent talks to.
* Use a `start` hook for work that depends on saved state, such as restoring a checkout from an attached [disk](/docs/build/sandboxes/disks).
* Keep anything you need after a hibernation on disk, never only in memory.