# Persistence & Sleep

> Source: `src/content/docs/agent-os/persistence.mdx`
> Canonical URL: https://rivet.dev/docs/agent-os/persistence
> Description: How agentOS persists data and manages sleep/wake cycles.

---
- **Persistent filesystem** backs `/home/user` automatically
- **Session transcripts** persisted with sequence numbers for replay
- **Configurable sleep** with a 15-minute grace period by default
- **Automatic wake** when a client connects or a cron job triggers

## What persists across sleep

| Data | Storage | Persists? |
|------|---------|-----------|
| Files in `/home/user` | Persistent filesystem | Yes |
| Session records | SQLite (`agent_os_sessions`) | Yes |
| Session event history | SQLite (`agent_os_session_events`) | Yes |
| Preview URL tokens | SQLite (`agent_os_preview_tokens`) | Yes |
| Cron job definitions | Actor state | Yes |
| Running processes | VM kernel | No |
| Active shells | VM kernel | No |
| In-memory mounts | VM memory | No |
| VM kernel state | VM memory | No |

## What prevents sleep

The actor stays awake as long as any of these are active:

- **Active sessions** (created but not closed/destroyed)
- **Running processes** (spawned but not exited)
- **Active shells** (opened but not closed)
- **Pending hooks** (server-side callbacks still executing)

When all activity stops, the sleep grace period begins.

## Sleep grace period

After all activity stops, the actor waits 15 minutes before sleeping. This allows for brief pauses between interactions without restarting the VM.

```
Activity stops ──> 15 min grace period ──> Actor sleeps
                                           (VM shutdown, processes killed)

New client connects ──> Actor wakes ──> VM boots ──> Filesystem restored
```

## Sleep vs destroy

| | Sleep | Destroy |
|-|-------|---------|
| Filesystem | Preserved | Deleted |
| Session records | Preserved | Deleted |
| Event history | Preserved | Deleted |
| Preview tokens | Preserved | Deleted |
| VM state | Lost | Lost |
| Processes | Killed | Killed |

## VM boot and shutdown events

Subscribe to `vmBooted` and `vmShutdown` events to track VM lifecycle.

```ts @nocheck client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";

const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);

agent.on("vmBooted", () => {
  console.log("VM is ready");
});

agent.on("vmShutdown", (data) => {
  console.log("VM shutdown reason:", data.reason);
  // reason: "sleep" | "destroy" | "error"
});
```

```ts @nocheck server.ts
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";

const vm = agentOs({
  options: { software: [common, pi] },
});

export const registry = setup({ use: { vm } });
registry.start();
```

## Resuming after sleep

When the actor wakes up:

1. The VM boots and the filesystem is restored from SQLite
2. Session records and event history are available immediately
3. Processes and shells from the previous session are gone
4. Clients can reconnect and resume sessions using `resumeSession`
5. Use `getSessionEvents` to replay missed events

```ts @nocheck client.ts
import { createClient } from "rivetkit/client";
import type { registry } from "./server";

const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.vm.getOrCreate(["my-agent"]);

// List sessions from before sleep
const sessions = await agent.listPersistedSessions();
console.log("Previous sessions:", sessions.length);

// Resume the most recent session
if (sessions.length > 0) {
  const last = sessions[0];
  await agent.resumeSession(last.sessionId);

  // Replay events for transcript
  const events = await agent.getSessionEvents(last.sessionId);
  for (const e of events) {
    console.log(e.seq, e.event.method);
  }
}
```

```ts @nocheck server.ts
import { agentOs } from "rivetkit/agent-os";
import { setup } from "rivetkit";
import common from "@rivet-dev/agent-os-common";
import pi from "@rivet-dev/agent-os-pi";

const vm = agentOs({
  options: { software: [common, pi] },
});

export const registry = setup({ use: { vm } });
registry.start();
```

## Persisted tables schema

### `agent_os_fs_entries`

Stores the virtual filesystem.

| Column | Type | Description |
|--------|------|-------------|
| `path` | TEXT PRIMARY KEY | File or directory path |
| `is_directory` | INTEGER | 1 for directory, 0 for file |
| `content` | BLOB | File content |
| `mode` | INTEGER | POSIX mode bits |
| `size` | INTEGER | File size in bytes |
| `atime_ms` | INTEGER | Access time (ms) |
| `mtime_ms` | INTEGER | Modification time (ms) |
| `ctime_ms` | INTEGER | Change time (ms) |
| `birthtime_ms` | INTEGER | Birth time (ms) |

### `agent_os_sessions`

Stores session metadata.

| Column | Type | Description |
|--------|------|-------------|
| `session_id` | TEXT PRIMARY KEY | Unique session identifier |
| `agent_type` | TEXT | Agent type (e.g. "pi") |
| `capabilities` | TEXT (JSON) | Agent capabilities |
| `agent_info` | TEXT (JSON) | Agent metadata |
| `created_at` | INTEGER | Creation timestamp (ms) |

### `agent_os_session_events`

Stores session event history.

| Column | Type | Description |
|--------|------|-------------|
| `id` | INTEGER PRIMARY KEY | Auto-incrementing ID |
| `session_id` | TEXT | Session reference |
| `seq` | INTEGER | Sequence number within session |
| `event` | TEXT (JSON) | JSON-RPC notification |
| `created_at` | INTEGER | Timestamp (ms) |

_Source doc path: /docs/agent-os/persistence_
