{
  "@context": "https://schema.org",
  "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-05-launch-hn-rivet-yc-w23-scale-and-orchestrate-agents-on-s3/#webpage",
  "@type": [
    "WebPage",
    "ArchiveComponent"
  ],
  "articleBody": "[![Rivet](https://github.com/rivet-dev/rivet/raw/main/.github/media/logo/icon-text-black.svg)](https://www.rivet.dev)\n\n### Fast, high-density, scalable orchestration with Rivet Actors. Built on S3 at SSD speeds.\n\n4.99 ms p99 cold starts, 72 KB RAM per Actor, scales to billions\n\n[Quickstart](https://www.rivet.dev/docs) • [Documentation](https://www.rivet.dev/actors/docs) • [Blog](https://www.rivet.dev/blog) • [Discord](https://www.rivet.dev/discord) • [X](https://x.com/rivet_dev)\n\n## What is Rivet?\n\nRivet Actors are long-lived processes with in-memory state, a SQLite database, WebSockets, and scheduling. You can create one for each agent, user, session, or tenant.\n\n- **72 KB per Actor**: Actors share a node process instead of each booting a sandbox, so one server holds hundreds of thousands.\n- **4.99 ms p99 cold starts**: No image pull and no VM boot.\n- **Built for scale**: All data lives in S3, so a cluster scales to billions of Actors.\n- **Hibernates when idle, wakes on demand**: Idle Actors cost nothing and wake on the next request with nothing lost.\n- **SQLite backed by S3, at SSD speeds**: 1.07 ms durable writes and 1.36 ms reads at p99, for about 10.4× less than replicated SSD storage.\n\n### Use cases\n\n- **[Durable & multiplayer AI agents](https://www.rivet.dev/guides/ai-agent)**: memory that survives restarts, shared live with every client\n- **[Workflows](https://www.rivet.dev/workflows/docs)**: multi-step operations that replay instead of starting over\n- **[AI-generated apps](https://www.rivet.dev/dynamic-apps/docs)**: run the apps and Actors your agent generates\n- **[Collaborative editing](https://www.rivet.dev/guides/collaborative-text-editor)**: one Actor per document, synced to every editor\n\n### Example\n\nA minimal agent written from scratch. For a ready-made agent, use [Pi Durable](https://www.rivet.dev/agents/docs/quickstart/).\n\n```ts\n// server.ts\nimport { actor, setup } from \"rivetkit\";\nimport { db } from \"rivetkit/db\";\nimport { streamText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\n// One Actor per agent, created on first use: agent.getOrCreate([\"agent-123\"])\nexport const agent = actor({\n  // 1. SQLite: every agent has its own database, so history survives restarts\n  db: db({\n    onMigrate: async (db) => {\n      await db.execute(\"CREATE TABLE IF NOT EXISTS messages (role TEXT, content TEXT)\");\n    },\n  }),\n\n  // 2. In-memory state: plain variables that live with the Actor, with no database round trip\n  createVars: () => ({ online: new Map<string, string>() }),\n\n  // 3. WebSockets: each client holds a live connection, and the Actor pushes to all of them\n  onDisconnect: (c, conn) => {\n    c.vars.online.delete(conn.id);\n    c.broadcast(\"online\", [...c.vars.online.values()]);\n  },\n\n  actions: {\n    join: (c, user: string) => {\n      c.vars.online.set(c.conn.id, user);\n      c.broadcast(\"online\", [...c.vars.online.values()]);\n    },\n\n    sendMessage: async (c, text: string) => {\n      // Save the message\n      await c.db.execute(\"INSERT INTO messages VALUES (?, ?)\", \"user\", text);\n      const messages = await c.db.execute(\"SELECT role, content FROM messages\");\n\n      // Stream tokens to every connected client\n      const response = streamText({ model: openai(\"gpt-5\"), messages });\n      for await (const delta of response.textStream) {\n        c.broadcast(\"token\", delta);\n      }\n\n      // Save the response\n      await c.db.execute(\"INSERT INTO messages VALUES (?, ?)\", \"assistant\", await response.text);\n    },\n  },\n});\n\nexport const registry = setup({ use: { agent } });\n```\n\n```ts\n// client.ts (frontend or backend)\nimport { createClient } from \"rivetkit/client\";\nimport type { registry } from \"./server\";\n\nconst client = createClient<typeof registry>();\n\n// Open a WebSocket connection to the agent\nconst agent = client.agent.getOrCreate([\"agent-123\"]).connect();\n\n// Listen for realtime events\nagent.on(\"online\", users => console.log(\"online:\", users));\nagent.on(\"token\", delta => process.stdout.write(delta));\n\n// Call actions on the Actor\nawait agent.join(\"nathan\");\nawait agent.sendMessage(\"how many r's in strawberry?\");\n```\n\n### Why run agents on Rivet Actors?\n\nEach Actor gives the agent a **long-lived process** for long agent turns, **in-memory state** for context, a **WebSocket server** for multiplayer, **durable SQLite storage** for session transcripts and agent artifacts, and **hibernation** when idle.\n\nMost of an agent's time is spent **waiting on inference**. When the agent loop runs inside a sandbox, you pay for a whole VM that sits **mostly idle** with low CPU usage.\n\nRivet Actors run the agent loop outside of the sandbox instead, often called **\"separating the head from the hands.\"** The agent's state, memory, and context live in the Actor, and it reaches the sandbox through tools only when it needs to run code. This uses a fraction of the memory and limits the **blast radius** and **trust boundary** of the code it runs. Read more about [running the harness outside of the sandbox](https://www.rivet.dev/blog/2026-07-27-run-your-harness-outside-the-sandbox/).\n\n### Do I need a sandbox with a Rivet Actor?\n\nOften not. An agent needs a sandbox only to run code it writes. Developers on Rivet use three patterns:\n\n- **Agents with tools**: Many agents only need tool calls, MCP, and APIs, such as customer support or personal agents. No sandbox needed.\n- **Agents with a lightweight sandbox**: [agentOS](https://www.rivet.dev/agentos/docs) provides Linux-compatible sandboxing for JS and Python using V8 and WebAssembly, with full POSIX filesystems, networking stacks, and process trees. It covers most workloads, like data analysis, file processing, evals, and code mode.\n- **Agents with a full sandbox**: Keep your existing sandbox provider and expose its shell and filesystem to the agent as tools, such as a `bash` tool that runs commands in the sandbox. The Actor reattaches to it across sleeps and restarts. See the [sandbox coding agent example](https://github.com/rivet-dev/rivet/blob/main/examples/sandbox-coding-agent).\n\n## Getting Started\n\n### Use with your coding agent\n\nPaste this prompt into Claude Code, Cursor, Codex, or any coding agent:\n\n```\nRun npx skills add rivet-dev/skills, then ask me what to build and run it locally.\n```\n\n### Start from scratch\n\nRivet ships libraries built on top of Actors for common use cases.\n\n- **[Actors](https://www.rivet.dev/actors/docs)**: Long-lived processes with state, realtime, and scheduling built in.\n- **[Agents](https://www.rivet.dev/agents/docs)**: Durable agents built on Actors, with memory that survives restarts.\n- **[Workflows](https://www.rivet.dev/workflows/docs)**: Multi-step operations built on Actors that replay instead of starting over.\n- **[agentOS](https://www.rivet.dev/agentos/docs)**: Run the code your agent writes, securely, with granular control over network access, filesystem access, and resource limits.\n- **[Dynamic Apps](https://www.rivet.dev/dynamic-apps/docs)** (preview): A backend per user, deployed the moment it is generated.\n\n## How Actors compare to sandboxes\n\n| Metric              | Rivet Actor       | Sandbox          |\n| ------------------- | ----------------- | ---------------- |\n| Cold start (p99)    | **4.99 ms**       | 1.70 s           |\n| Memory per instance | **72.4 KB**       | 512 MiB          |\n| Storage             | **SQLite on S3**  | Disk per sandbox |\n| Storage cost        | **10.4× cheaper** | Replicated SSDs  |\n\nBenchmark details & methodology\n\n- **Rivet numbers** come from the published [Rivet Actors vs Cloudflare Durable Objects benchmark](https://github.com/rivet-dev/bench-rivet-actors-vs-durable-objects), run on Rivet 3.0.3. Its repository has the raw samples and the scripts to reproduce them.\n- **Sandbox numbers** are for [E2B](https://e2b.dev): 512 MiB is its default memory allocation from [E2B's billing documentation](https://docs.e2b.dev/billing) as of November 4, 2026, and 1.70 s is the p99 cold start from [ComputeSDK's October 30, 2026 sandbox benchmark](https://www.computesdk.com/benchmarks/sandboxes/burst-tti).\n- **Storage cost** compares S3 Standard with three Amazon EBS gp3 copies at AWS list prices.\n- Sources, dates, and the full method are at [rivet.dev/docs/benchmarking](https://www.rivet.dev/docs/benchmarking/).\n\n## Features\n\n- **Fault tolerance**: If a node goes down, its Actors move elsewhere with their state intact.\n- **HTTP & WebSocket networking**: Call an Actor over HTTP or hold a live WebSocket to it.\n- **End-to-end type safety**: Typed clients for your backend and React hooks for your frontend.\n- **Cron & scheduling**: Wake an Actor on a schedule or at a time it sets for itself.\n- **Actor-to-Actor calls**: Actors call each other by key across the cluster.\n- **Scoped JWTs**: Give each client a [JWT](https://www.rivet.dev/docs/jwt) scoped to the Actors it may reach.\n- **OpenTelemetry**: Traces, metrics, and logs in OTel format.\n\n## Deployment Options\n\n| Option                | Description                                                                                                                        | Get started                                                                      |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |\n| **Local & self-host** | Run Rivet locally while you build. In production, run the control plane on Docker, Kubernetes, or a VM. S3 is the only dependency. | [Self-hosting docs](https://www.rivet.dev/docs/deploy/self-host/control-plane/) |\n| **Rivet Cloud**       | Fully managed, dedicated clusters on AWS or GCP in any region. Run your nodes on Rivet Cloud or bring your own.                    | [Dashboard](https://dashboard.rivet.dev)                                        |\n| **BYOC**              | The control plane runs inside your own VPC on AWS, GCP, or Azure, fully managed by Rivet. Your data never leaves your cloud.       | [BYOC docs](https://www.rivet.dev/docs/deploy/byoc/)                            |\n\nEvery option runs the same control plane, from local dev to production. [Talk to an engineer →](https://www.rivet.dev/talk-to-an-engineer)\n\n## Works with the tools you already use\n\nTyped SDKs for your backend and React hooks for your frontend. Rivet runs on native Node.js and Bun with no custom runtime, so your existing packages, tooling, and tests work unchanged.\n\n**Deploy nodes on**: [Docker Compose](https://www.rivet.dev/docs/deploy/self-host/nodes/docker-compose/) • [Kubernetes](https://www.rivet.dev/docs/deploy/self-host/nodes/kubernetes/) • [VM & bare metal](https://www.rivet.dev/docs/deploy/self-host/nodes/vm/) • [Hetzner](https://www.rivet.dev/docs/deploy/self-host/nodes/hetzner/) • [AWS ECS](https://www.rivet.dev/docs/deploy/self-host/nodes/aws-ecs/) • [Railway](https://www.rivet.dev/docs/deploy/self-host/nodes/railway/) • [Render](https://www.rivet.dev/docs/deploy/self-host/nodes/render/)\n\n**Frameworks**: [React](https://www.rivet.dev/actors/docs/clients/react) • [Effect](https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent-effect)\n\n**Runtimes**: [Node.js](https://www.rivet.dev/actors/docs/quickstart/backend) • [Bun](https://www.rivet.dev/actors/docs/quickstart/backend) • [Rust](https://www.rivet.dev/actors/docs/quickstart/rust)\n\n**Tools**: [Vitest](https://www.rivet.dev/actors/docs/testing) • [OpenTelemetry](https://www.rivet.dev/docs/tracing) • [Pino](https://www.rivet.dev/actors/docs/logging) • [AI SDK](https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent) • [OpenAPI](https://github.com/rivet-dev/rivet/blob/main/rivetkit-openapi) • [AsyncAPI](https://github.com/rivet-dev/rivet/blob/main/rivetkit-asyncapi)\n\n[Request an integration →](https://github.com/rivet-dev/rivet/issues/new)\n\n## FAQ\n\n**Does Rivet have BYOC?**\n\nYes. Rivet deploys into your own cloud account, including air-gapped environments: the control plane and storage run inside your VPC while Rivet operates them. See the [BYOC docs](https://www.rivet.dev/docs/deploy/byoc/).\n\n**Does Rivet have a cloud?**\n\nYes. [Rivet Cloud](https://dashboard.rivet.dev) runs fully managed, dedicated clusters on AWS or GCP in any region. It can run your app's Docker image as [nodes on Rivet Cloud](https://www.rivet.dev/docs/deploy/cloud/compute/), or you can [bring your own nodes](https://www.rivet.dev/docs/deploy/self-host/nodes/).\n\n**Can I self-host Rivet?**\n\nYes. Rivet is fully self-hostable; see the [self-hosting docs](https://www.rivet.dev/docs/deploy/self-host/control-plane/). The control plane runs anywhere a container runs, with guides for Docker Compose, Kubernetes, VMs and bare metal, Hetzner, Railway, Render, and AWS ECS. For enterprise support with a self-hosted deployment, [contact us](https://www.rivet.dev/enterprise/).\n\n**Do I still need Postgres, FoundationDB, or NATS?**\n\nNo. An object storage bucket is the only dependency: there is no database to run and no message bus, and control plane instances find each other through the bucket. Rivet works with Amazon S3, Google Cloud Storage, Azure Blob Storage, and any S3-compatible store such as MinIO, Cloudflare R2, or Hetzner Object Storage. A local filesystem backend is available for trying Rivet on one machine.\n\n**Is Rivet open-source?**\n\nYes. Rivet is open source under the permissive Apache 2.0 license. You're looking at it.\n\n**Are Rivet Actors only for agents?**\n\nNo. Rivet is a general actor platform at its core, with nothing specific to agents. For agents, you can use the optional [agent library](https://www.rivet.dev/agents/docs/quickstart/), which runs Pi Durable on Rivet Actors, or write your own agent from scratch.\n\n**How does Rivet compare to sandboxes?**\n\nA sandbox boots a VM or container per agent, which is slow to start and sits mostly idle. A Rivet Actor runs inside a shared node process: 72 KB and 4.99 ms p99 to start, versus 512 MiB and 1.70 s for a sandbox, and it hibernates when idle. To run untrusted code your agent writes, use [agentOS](https://www.rivet.dev/agentos/docs).\n\n**How does Rivet compare to Cloudflare Durable Objects?**\n\nRivet is often used as an open-source alternative to Cloudflare Durable Objects that is easy to self-host and scales. It also fixes many of the constraints of Durable Objects: no 128 MB memory cap, bottomless storage instead of a 10 GB SQLite limit, Actors are not randomly evicted, and you control the runtime because Actors run on vanilla Node.js or Bun instead of a custom runtime. Rivet also adds built-in connection handling, event broadcasting, durable scheduling and cron, full Vitest support, lifecycle hooks for draining, and control over Actor upgrades. See the [Cloudflare Durable Objects comparison](https://www.rivet.dev/actors/compare/rivet-actors-vs-cloudflare-durable-objects/).\n\n**Does Rivet use a custom V8 runtime?**\n\nNo. Rivet runs on native Node.js and Bun, so your existing packages, tooling, and tests work unchanged.\n\n**Is Rivet like Erlang, Akka, or Orleans?**\n\nRivet implements the virtual actor pattern, which is closest to Orleans, but focuses on what modern workloads need: SQLite persistence instead of simple JSON stores and support for modern runtimes. Erlang and Akka do not provide virtual actors out of the box, though ecosystem packages exist that offer functionality comparable to Rivet Actors.\n\n**Does Rivet require microVMs, gVisor, or nested virtualization?**\n\nNo. Rivet only needs a standard process that connects to the control plane over WebSocket. That process can be Node.js, Bun, Rust, or anything else.\n\n## Projects in This Repository\n\n| Project                                                                                  | Description                                                            |\n| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |\n| [RivetKit TypeScript](https://github.com/rivet-dev/rivet/blob/main/rivetkit-typescript) | Client & server library for building Actors                            |\n| [RivetKit Rust](https://github.com/rivet-dev/rivet/blob/main/rivetkit-rust)             | Rust SDK                                                               |\n| [RivetKit Python](https://github.com/rivet-dev/rivet/blob/main/rivetkit-python)         | Python client (experimental)                                           |\n| [RivetKit Swift](https://github.com/rivet-dev/rivet/blob/main/rivetkit-swift)           | Swift client (experimental)                                            |\n| [Control Plane](https://github.com/rivet-dev/rivet/blob/main/engine)                    | Rust control plane that schedules, routes, and persists Actors         |\n| ↳ [Pegboard](https://github.com/rivet-dev/rivet/blob/main/engine/packages/pegboard)     | Actor scheduling & networking                                          |\n| ↳ [Guard](https://github.com/rivet-dev/rivet/blob/main/engine/packages/guard)           | Traffic routing proxy                                                  |\n| ↳ [Epoxy](https://github.com/rivet-dev/rivet/blob/main/engine/packages/epoxy)           | Multi-region KV store (EPaxos)                                         |\n| [Documentation](https://github.com/rivet-dev/rivet/blob/main/docs)                      | Source for [rivet.dev/actors/docs](https://www.rivet.dev/actors/docs) |\n| [Examples](https://github.com/rivet-dev/rivet/blob/main/examples)                       | Runnable examples                                                      |\n\n## Community\n\n- [Discord](https://www.rivet.dev/discord) - Chat with the community\n- [X/Twitter](https://x.com/rivet_dev) - Follow for updates\n- [GitHub Discussions](https://github.com/rivet-dev/rivet/discussions) - Ask questions\n- [GitHub Issues](https://github.com/rivet-dev/rivet/issues) - Report bugs\n- [Talk to an engineer](https://www.rivet.dev/talk-to-an-engineer) - Discuss your use case\n\n## License\n\n[Apache 2.0](https://github.com/rivet-dev/rivet/blob/main/LICENSE)\n",
  "authors": [
    "NathanFlurry"
  ],
  "captured_at": "2026-11-06T11:27:16.888185679+00:00",
  "category": "news",
  "content_html": "<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev\"><picture class=\"article-picture article-picture-fallback\" style=\"--image-ratio:16 / 9\"><img src=\"https://github.com/rivet-dev/rivet/raw/main/.github/media/logo/icon-text-black.svg\" alt=\"Rivet\" loading=\"eager\" decoding=\"async\" fetchpriority=\"high\" referrerpolicy=\"no-referrer\" class=\"progressive-image\"></picture></a></p>\n<h3>Fast, high-density, scalable orchestration with Rivet Actors. Built on S3 at SSD speeds.</h3>\n<p>4.99 ms p99 cold starts, 72 KB RAM per Actor, scales to billions</p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs\">Quickstart</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs\">Documentation</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/blog\">Blog</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/discord\">Discord</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://x.com/rivet_dev\">X</a></p>\n<h2>What is Rivet?</h2>\n<p>Rivet Actors are long-lived processes with in-memory state, a SQLite database, WebSockets, and scheduling. You can create one for each agent, user, session, or tenant.</p>\n<ul>\n<li><strong>72 KB per Actor</strong>: Actors share a node process instead of each booting a sandbox, so one server holds hundreds of thousands.</li>\n<li><strong>4.99 ms p99 cold starts</strong>: No image pull and no VM boot.</li>\n<li><strong>Built for scale</strong>: All data lives in S3, so a cluster scales to billions of Actors.</li>\n<li><strong>Hibernates when idle, wakes on demand</strong>: Idle Actors cost nothing and wake on the next request with nothing lost.</li>\n<li><strong>SQLite backed by S3, at SSD speeds</strong>: 1.07 ms durable writes and 1.36 ms reads at p99, for about 10.4× less than replicated SSD storage.</li>\n</ul>\n<h3>Use cases</h3>\n<ul>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/guides/ai-agent\">Durable &amp; multiplayer AI agents</a></strong>: memory that survives restarts, shared live with every client</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/workflows/docs\">Workflows</a></strong>: multi-step operations that replay instead of starting over</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/dynamic-apps/docs\">AI-generated apps</a></strong>: run the apps and Actors your agent generates</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/guides/collaborative-text-editor\">Collaborative editing</a></strong>: one Actor per document, synced to every editor</li>\n</ul>\n<h3>Example</h3>\n<p>A minimal agent written from scratch. For a ready-made agent, use <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agents/docs/quickstart/\">Pi Durable</a>.</p>\n<pre><code class=\"language-ts\"><span class=\"code-snippet\" data-language=\"TypeScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> server.ts\n</span><span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">actor</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">setup</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>rivetkit<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">db</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>rivetkit/db<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">streamText</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>ai<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">openai</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>@ai-sdk/openai<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> One Actor per agent, created on first use: agent.getOrCreate([&quot;agent-123&quot;])\n</span><span class=\"syntax-meta syntax-export syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">export</span> <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">agent</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">actor</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n  <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> 1. SQLite: every agent has its own database, so history survives restarts\n</span>  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">db</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">db</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">onMigrate</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">async</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">db</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n      <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">db</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">execute</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>CREATE TABLE IF NOT EXISTS messages (role TEXT, content TEXT)<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n\n  <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> 2. In-memory state: plain variables that live with the Actor, with no database round trip\n</span>  <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">createVars</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">online</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-instance syntax-constructor syntax-js\"><span class=\"syntax-keyword syntax-operator syntax-word syntax-new syntax-js\">new</span><span class=\"syntax-meta syntax-function-call syntax-constructor syntax-js\"> <span class=\"syntax-support syntax-class syntax-builtin syntax-js\">Map</span></span></span><span class=\"syntax-keyword syntax-operator syntax-relational syntax-js\">&lt;</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">string</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> string&gt;() <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n\n  <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> 3. WebSockets: each client holds a live connection, and the Actor pushes to all of them\n</span>  <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">onDisconnect</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">c</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">conn</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">vars</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">online</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">delete</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">conn</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">broadcast</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>online<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-keyword syntax-operator syntax-spread syntax-js\">...</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">vars</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">online</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">values</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n  <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n\n  <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">actions</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">join</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">c</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">user</span>: <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">string</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n      <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">vars</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">online</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">set</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">conn</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">id</span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">user</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n      <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">broadcast</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>online<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-keyword syntax-operator syntax-spread syntax-js\">...</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">vars</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">online</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">values</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n\n    <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\"><span class=\"syntax-entity syntax-name syntax-function syntax-js\">sendMessage</span></span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> </span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-storage syntax-type syntax-js\">async</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-punctuation syntax-section syntax-group syntax-begin syntax-js\">(</span><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">c</span><span class=\"syntax-punctuation syntax-separator syntax-parameter syntax-function syntax-js\">,</span> <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">text</span>: <span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">string</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-end syntax-js\">)</span><span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"> </span><span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n      <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Save the message\n</span>      <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">db</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">execute</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>INSERT INTO messages VALUES (?, ?)<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>user<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">text</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n      <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">messages</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">db</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">execute</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>SELECT role, content FROM messages<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n      <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Stream tokens to every connected client\n</span>      <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">response</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">streamText</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">model</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">openai</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>gpt-5<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">messages</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n      <span class=\"syntax-meta syntax-for syntax-js\"><span class=\"syntax-keyword syntax-control syntax-loop syntax-js\">for</span> </span><span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">delta</span> <span class=\"syntax-keyword syntax-operator syntax-js\">of</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">response</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">textStream</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span>\n        <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">broadcast</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>token<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">delta</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n      <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span>\n\n      <span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Save the response\n</span>      <span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">c</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">db</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">execute</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>INSERT INTO messages VALUES (?, ?)<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>assistant<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">response</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">text</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n    <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n  <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span>\n<span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-meta syntax-export syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">export</span> <span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">registry</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-meta syntax-function-call syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">setup</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-meta syntax-object-literal syntax-key syntax-js\">use</span><span class=\"syntax-punctuation syntax-separator syntax-key-value syntax-js\">:</span> <span class=\"syntax-meta syntax-object-literal syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">agent</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<pre><code class=\"language-ts\"><span class=\"code-snippet\" data-language=\"TypeScript\"><span class=\"syntax-source syntax-js\"><span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> client.ts (frontend or backend)\n</span><span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">createClient</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>rivetkit/client<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-meta syntax-import syntax-js\"><span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">import</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">type</span> </span><span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">{</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">registry</span> <span class=\"syntax-punctuation syntax-section syntax-block syntax-js\">}</span></span> <span class=\"syntax-keyword syntax-control syntax-import-export syntax-js\">from</span> <span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>./server<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">client</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">createClient</span><span class=\"syntax-keyword syntax-operator syntax-relational syntax-js\">&lt;</span><span class=\"syntax-keyword syntax-operator syntax-js\">typeof</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">registry</span><span class=\"syntax-keyword syntax-operator syntax-relational syntax-js\">&gt;</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Open a WebSocket connection to the agent\n</span><span class=\"syntax-storage syntax-type syntax-js\">const</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">agent</span> <span class=\"syntax-keyword syntax-operator syntax-assignment syntax-js\">=</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">client</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-property syntax-object syntax-js\">agent</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">getOrCreate</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-meta syntax-sequence syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">[</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>agent-123<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-section syntax-brackets syntax-js\">]</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">connect</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Listen for realtime events\n</span><span class=\"syntax-variable syntax-other syntax-object syntax-js\">agent</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">on</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>online<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">users</span> <span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-type syntax-object syntax-console syntax-js\">console</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-support syntax-function syntax-console syntax-js\">log</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>online:<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">users</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-variable syntax-other syntax-object syntax-js\">agent</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">on</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>token<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span><span class=\"syntax-punctuation syntax-separator syntax-comma syntax-js\">,</span> <span class=\"syntax-meta syntax-function syntax-declaration syntax-js\"><span class=\"syntax-variable syntax-parameter syntax-function syntax-js\">delta</span> <span class=\"syntax-storage syntax-type syntax-function syntax-arrow syntax-js\">=&gt;</span></span> <span class=\"syntax-meta syntax-block syntax-js\"><span class=\"syntax-support syntax-type syntax-object syntax-process syntax-js\">process</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-support syntax-type syntax-object syntax-process syntax-js\">stdout</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-support syntax-function syntax-dom syntax-js\">write</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-variable syntax-other syntax-readwrite syntax-js\">delta</span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n\n<span class=\"syntax-comment syntax-line syntax-double-slash syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-comment syntax-js\">//</span> Call actions on the Actor\n</span><span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">agent</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">join</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>nathan<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n<span class=\"syntax-keyword syntax-control syntax-flow syntax-js\">await</span> <span class=\"syntax-variable syntax-other syntax-object syntax-js\">agent</span><span class=\"syntax-punctuation syntax-accessor syntax-js\">.</span><span class=\"syntax-meta syntax-function-call syntax-method syntax-js\"><span class=\"syntax-variable syntax-function syntax-js\">sendMessage</span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">(</span><span class=\"syntax-string syntax-quoted syntax-double syntax-js\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-js\">&quot;</span>how many r&#39;s in strawberry?<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-js\">&quot;</span></span></span><span class=\"syntax-meta syntax-group syntax-js\"><span class=\"syntax-punctuation syntax-section syntax-group syntax-js\">)</span></span></span><span class=\"syntax-punctuation syntax-terminator syntax-statement syntax-js\">;</span>\n</span></span></code></pre>\n<h3>Why run agents on Rivet Actors?</h3>\n<p>Each Actor gives the agent a <strong>long-lived process</strong> for long agent turns, <strong>in-memory state</strong> for context, a <strong>WebSocket server</strong> for multiplayer, <strong>durable SQLite storage</strong> for session transcripts and agent artifacts, and <strong>hibernation</strong> when idle.</p>\n<p>Most of an agent's time is spent <strong>waiting on inference</strong>. When the agent loop runs inside a sandbox, you pay for a whole VM that sits <strong>mostly idle</strong> with low CPU usage.</p>\n<p>Rivet Actors run the agent loop outside of the sandbox instead, often called <strong>&quot;separating the head from the hands.&quot;</strong> The agent's state, memory, and context live in the Actor, and it reaches the sandbox through tools only when it needs to run code. This uses a fraction of the memory and limits the <strong>blast radius</strong> and <strong>trust boundary</strong> of the code it runs. Read more about <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/blog/2026-07-27-run-your-harness-outside-the-sandbox/\">running the harness outside of the sandbox</a>.</p>\n<h3>Do I need a sandbox with a Rivet Actor?</h3>\n<p>Often not. An agent needs a sandbox only to run code it writes. Developers on Rivet use three patterns:</p>\n<ul>\n<li><strong>Agents with tools</strong>: Many agents only need tool calls, MCP, and APIs, such as customer support or personal agents. No sandbox needed.</li>\n<li><strong>Agents with a lightweight sandbox</strong>: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agentos/docs\">agentOS</a> provides Linux-compatible sandboxing for JS and Python using V8 and WebAssembly, with full POSIX filesystems, networking stacks, and process trees. It covers most workloads, like data analysis, file processing, evals, and code mode.</li>\n<li><strong>Agents with a full sandbox</strong>: Keep your existing sandbox provider and expose its shell and filesystem to the agent as tools, such as a <code>bash</code> tool that runs commands in the sandbox. The Actor reattaches to it across sleeps and restarts. See the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/examples/sandbox-coding-agent\">sandbox coding agent example</a>.</li>\n</ul>\n<h2>Getting Started</h2>\n<h3>Use with your coding agent</h3>\n<p>Paste this prompt into Claude Code, Cursor, Codex, or any coding agent:</p>\n<pre><code><span class=\"code-snippet\">Run npx skills add rivet-dev/skills, then ask me what to build and run it locally.\n</span></code></pre>\n<h3>Start from scratch</h3>\n<p>Rivet ships libraries built on top of Actors for common use cases.</p>\n<ul>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs\">Actors</a></strong>: Long-lived processes with state, realtime, and scheduling built in.</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agents/docs\">Agents</a></strong>: Durable agents built on Actors, with memory that survives restarts.</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/workflows/docs\">Workflows</a></strong>: Multi-step operations built on Actors that replay instead of starting over.</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agentos/docs\">agentOS</a></strong>: Run the code your agent writes, securely, with granular control over network access, filesystem access, and resource limits.</li>\n<li><strong><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/dynamic-apps/docs\">Dynamic Apps</a></strong> (preview): A backend per user, deployed the moment it is generated.</li>\n</ul>\n<h2>How Actors compare to sandboxes</h2>\n<table>\n<thead>\n<tr>\n<th>Metric</th>\n<th>Rivet Actor</th>\n<th>Sandbox</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Cold start (p99)</td>\n<td><strong>4.99 ms</strong></td>\n<td>1.70 s</td>\n</tr>\n<tr>\n<td>Memory per instance</td>\n<td><strong>72.4 KB</strong></td>\n<td>512 MiB</td>\n</tr>\n<tr>\n<td>Storage</td>\n<td><strong>SQLite on S3</strong></td>\n<td>Disk per sandbox</td>\n</tr>\n<tr>\n<td>Storage cost</td>\n<td><strong>10.4× cheaper</strong></td>\n<td>Replicated SSDs</td>\n</tr>\n</tbody>\n</table>\n<p>Benchmark details &amp; methodology</p>\n<ul>\n<li><strong>Rivet numbers</strong> come from the published <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/bench-rivet-actors-vs-durable-objects\">Rivet Actors vs Cloudflare Durable Objects benchmark</a>, run on Rivet 3.0.3. Its repository has the raw samples and the scripts to reproduce them.</li>\n<li><strong>Sandbox numbers</strong> are for <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://e2b.dev\">E2B</a>: 512 MiB is its default memory allocation from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://docs.e2b.dev/billing\">E2B's billing documentation</a> as of November 4, 2026, and 1.70 s is the p99 cold start from <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.computesdk.com/benchmarks/sandboxes/burst-tti\">ComputeSDK's October 30, 2026 sandbox benchmark</a>.</li>\n<li><strong>Storage cost</strong> compares S3 Standard with three Amazon EBS gp3 copies at AWS list prices.</li>\n<li>Sources, dates, and the full method are at <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/benchmarking/\">rivet.dev/docs/benchmarking</a>.</li>\n</ul>\n<h2>Features</h2>\n<ul>\n<li><strong>Fault tolerance</strong>: If a node goes down, its Actors move elsewhere with their state intact.</li>\n<li><strong>HTTP &amp; WebSocket networking</strong>: Call an Actor over HTTP or hold a live WebSocket to it.</li>\n<li><strong>End-to-end type safety</strong>: Typed clients for your backend and React hooks for your frontend.</li>\n<li><strong>Cron &amp; scheduling</strong>: Wake an Actor on a schedule or at a time it sets for itself.</li>\n<li><strong>Actor-to-Actor calls</strong>: Actors call each other by key across the cluster.</li>\n<li><strong>Scoped JWTs</strong>: Give each client a <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/jwt\">JWT</a> scoped to the Actors it may reach.</li>\n<li><strong>OpenTelemetry</strong>: Traces, metrics, and logs in OTel format.</li>\n</ul>\n<h2>Deployment Options</h2>\n<table>\n<thead>\n<tr>\n<th>Option</th>\n<th>Description</th>\n<th>Get started</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Local &amp; self-host</strong></td>\n<td>Run Rivet locally while you build. In production, run the control plane on Docker, Kubernetes, or a VM. S3 is the only dependency.</td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/control-plane/\">Self-hosting docs</a></td>\n</tr>\n<tr>\n<td><strong>Rivet Cloud</strong></td>\n<td>Fully managed, dedicated clusters on AWS or GCP in any region. Run your nodes on Rivet Cloud or bring your own.</td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://dashboard.rivet.dev\">Dashboard</a></td>\n</tr>\n<tr>\n<td><strong>BYOC</strong></td>\n<td>The control plane runs inside your own VPC on AWS, GCP, or Azure, fully managed by Rivet. Your data never leaves your cloud.</td>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/byoc/\">BYOC docs</a></td>\n</tr>\n</tbody>\n</table>\n<p>Every option runs the same control plane, from local dev to production. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/talk-to-an-engineer\">Talk to an engineer →</a></p>\n<h2>Works with the tools you already use</h2>\n<p>Typed SDKs for your backend and React hooks for your frontend. Rivet runs on native Node.js and Bun with no custom runtime, so your existing packages, tooling, and tests work unchanged.</p>\n<p><strong>Deploy nodes on</strong>: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/docker-compose/\">Docker Compose</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/kubernetes/\">Kubernetes</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/vm/\">VM &amp; bare metal</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/hetzner/\">Hetzner</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/aws-ecs/\">AWS ECS</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/railway/\">Railway</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/render/\">Render</a></p>\n<p><strong>Frameworks</strong>: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/clients/react\">React</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent-effect\">Effect</a></p>\n<p><strong>Runtimes</strong>: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/quickstart/backend\">Node.js</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/quickstart/backend\">Bun</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/quickstart/rust\">Rust</a></p>\n<p><strong>Tools</strong>: <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/testing\">Vitest</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/tracing\">OpenTelemetry</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs/logging\">Pino</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent\">AI SDK</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-openapi\">OpenAPI</a> • <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-asyncapi\">AsyncAPI</a></p>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/issues/new\">Request an integration →</a></p>\n<h2>FAQ</h2>\n<p><strong>Does Rivet have BYOC?</strong></p>\n<p>Yes. Rivet deploys into your own cloud account, including air-gapped environments: the control plane and storage run inside your VPC while Rivet operates them. See the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/byoc/\">BYOC docs</a>.</p>\n<p><strong>Does Rivet have a cloud?</strong></p>\n<p>Yes. <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://dashboard.rivet.dev\">Rivet Cloud</a> runs fully managed, dedicated clusters on AWS or GCP in any region. It can run your app's Docker image as <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/cloud/compute/\">nodes on Rivet Cloud</a>, or you can <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/nodes/\">bring your own nodes</a>.</p>\n<p><strong>Can I self-host Rivet?</strong></p>\n<p>Yes. Rivet is fully self-hostable; see the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/docs/deploy/self-host/control-plane/\">self-hosting docs</a>. The control plane runs anywhere a container runs, with guides for Docker Compose, Kubernetes, VMs and bare metal, Hetzner, Railway, Render, and AWS ECS. For enterprise support with a self-hosted deployment, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/enterprise/\">contact us</a>.</p>\n<p><strong>Do I still need Postgres, FoundationDB, or NATS?</strong></p>\n<p>No. An object storage bucket is the only dependency: there is no database to run and no message bus, and control plane instances find each other through the bucket. Rivet works with Amazon S3, Google Cloud Storage, Azure Blob Storage, and any S3-compatible store such as MinIO, Cloudflare R2, or Hetzner Object Storage. A local filesystem backend is available for trying Rivet on one machine.</p>\n<p><strong>Is Rivet open-source?</strong></p>\n<p>Yes. Rivet is open source under the permissive Apache 2.0 license. You're looking at it.</p>\n<p><strong>Are Rivet Actors only for agents?</strong></p>\n<p>No. Rivet is a general actor platform at its core, with nothing specific to agents. For agents, you can use the optional <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agents/docs/quickstart/\">agent library</a>, which runs Pi Durable on Rivet Actors, or write your own agent from scratch.</p>\n<p><strong>How does Rivet compare to sandboxes?</strong></p>\n<p>A sandbox boots a VM or container per agent, which is slow to start and sits mostly idle. A Rivet Actor runs inside a shared node process: 72 KB and 4.99 ms p99 to start, versus 512 MiB and 1.70 s for a sandbox, and it hibernates when idle. To run untrusted code your agent writes, use <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/agentos/docs\">agentOS</a>.</p>\n<p><strong>How does Rivet compare to Cloudflare Durable Objects?</strong></p>\n<p>Rivet is often used as an open-source alternative to Cloudflare Durable Objects that is easy to self-host and scales. It also fixes many of the constraints of Durable Objects: no 128 MB memory cap, bottomless storage instead of a 10 GB SQLite limit, Actors are not randomly evicted, and you control the runtime because Actors run on vanilla Node.js or Bun instead of a custom runtime. Rivet also adds built-in connection handling, event broadcasting, durable scheduling and cron, full Vitest support, lifecycle hooks for draining, and control over Actor upgrades. See the <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/compare/rivet-actors-vs-cloudflare-durable-objects/\">Cloudflare Durable Objects comparison</a>.</p>\n<p><strong>Does Rivet use a custom V8 runtime?</strong></p>\n<p>No. Rivet runs on native Node.js and Bun, so your existing packages, tooling, and tests work unchanged.</p>\n<p><strong>Is Rivet like Erlang, Akka, or Orleans?</strong></p>\n<p>Rivet implements the virtual actor pattern, which is closest to Orleans, but focuses on what modern workloads need: SQLite persistence instead of simple JSON stores and support for modern runtimes. Erlang and Akka do not provide virtual actors out of the box, though ecosystem packages exist that offer functionality comparable to Rivet Actors.</p>\n<p><strong>Does Rivet require microVMs, gVisor, or nested virtualization?</strong></p>\n<p>No. Rivet only needs a standard process that connects to the control plane over WebSocket. That process can be Node.js, Bun, Rust, or anything else.</p>\n<h2>Projects in This Repository</h2>\n<table>\n<thead>\n<tr>\n<th>Project</th>\n<th>Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-typescript\">RivetKit TypeScript</a></td>\n<td>Client &amp; server library for building Actors</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-rust\">RivetKit Rust</a></td>\n<td>Rust SDK</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-python\">RivetKit Python</a></td>\n<td>Python client (experimental)</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/rivetkit-swift\">RivetKit Swift</a></td>\n<td>Swift client (experimental)</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/engine\">Control Plane</a></td>\n<td>Rust control plane that schedules, routes, and persists Actors</td>\n</tr>\n<tr>\n<td>↳ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/engine/packages/pegboard\">Pegboard</a></td>\n<td>Actor scheduling &amp; networking</td>\n</tr>\n<tr>\n<td>↳ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/engine/packages/guard\">Guard</a></td>\n<td>Traffic routing proxy</td>\n</tr>\n<tr>\n<td>↳ <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/engine/packages/epoxy\">Epoxy</a></td>\n<td>Multi-region KV store (EPaxos)</td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/docs\">Documentation</a></td>\n<td>Source for <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/actors/docs\">rivet.dev/actors/docs</a></td>\n</tr>\n<tr>\n<td><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/examples\">Examples</a></td>\n<td>Runnable examples</td>\n</tr>\n</tbody>\n</table>\n<h2>Community</h2>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/discord\">Discord</a> - Chat with the community</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://x.com/rivet_dev\">X/Twitter</a> - Follow for updates</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/discussions\">GitHub Discussions</a> - Ask questions</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/issues\">GitHub Issues</a> - Report bugs</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://www.rivet.dev/talk-to-an-engineer\">Talk to an engineer</a> - Discuss your use case</li>\n</ul>\n<h2>License</h2>\n<p><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://github.com/rivet-dev/rivet/blob/main/LICENSE\">Apache 2.0</a></p>\n",
  "content_markdown": "[![Rivet](https://github.com/rivet-dev/rivet/raw/main/.github/media/logo/icon-text-black.svg)](https://www.rivet.dev)\n\n### Fast, high-density, scalable orchestration with Rivet Actors. Built on S3 at SSD speeds.\n\n4.99 ms p99 cold starts, 72 KB RAM per Actor, scales to billions\n\n[Quickstart](https://www.rivet.dev/docs) • [Documentation](https://www.rivet.dev/actors/docs) • [Blog](https://www.rivet.dev/blog) • [Discord](https://www.rivet.dev/discord) • [X](https://x.com/rivet_dev)\n\n## What is Rivet?\n\nRivet Actors are long-lived processes with in-memory state, a SQLite database, WebSockets, and scheduling. You can create one for each agent, user, session, or tenant.\n\n- **72 KB per Actor**: Actors share a node process instead of each booting a sandbox, so one server holds hundreds of thousands.\n- **4.99 ms p99 cold starts**: No image pull and no VM boot.\n- **Built for scale**: All data lives in S3, so a cluster scales to billions of Actors.\n- **Hibernates when idle, wakes on demand**: Idle Actors cost nothing and wake on the next request with nothing lost.\n- **SQLite backed by S3, at SSD speeds**: 1.07 ms durable writes and 1.36 ms reads at p99, for about 10.4× less than replicated SSD storage.\n\n### Use cases\n\n- **[Durable & multiplayer AI agents](https://www.rivet.dev/guides/ai-agent)**: memory that survives restarts, shared live with every client\n- **[Workflows](https://www.rivet.dev/workflows/docs)**: multi-step operations that replay instead of starting over\n- **[AI-generated apps](https://www.rivet.dev/dynamic-apps/docs)**: run the apps and Actors your agent generates\n- **[Collaborative editing](https://www.rivet.dev/guides/collaborative-text-editor)**: one Actor per document, synced to every editor\n\n### Example\n\nA minimal agent written from scratch. For a ready-made agent, use [Pi Durable](https://www.rivet.dev/agents/docs/quickstart/).\n\n```ts\n// server.ts\nimport { actor, setup } from \"rivetkit\";\nimport { db } from \"rivetkit/db\";\nimport { streamText } from \"ai\";\nimport { openai } from \"@ai-sdk/openai\";\n\n// One Actor per agent, created on first use: agent.getOrCreate([\"agent-123\"])\nexport const agent = actor({\n  // 1. SQLite: every agent has its own database, so history survives restarts\n  db: db({\n    onMigrate: async (db) => {\n      await db.execute(\"CREATE TABLE IF NOT EXISTS messages (role TEXT, content TEXT)\");\n    },\n  }),\n\n  // 2. In-memory state: plain variables that live with the Actor, with no database round trip\n  createVars: () => ({ online: new Map<string, string>() }),\n\n  // 3. WebSockets: each client holds a live connection, and the Actor pushes to all of them\n  onDisconnect: (c, conn) => {\n    c.vars.online.delete(conn.id);\n    c.broadcast(\"online\", [...c.vars.online.values()]);\n  },\n\n  actions: {\n    join: (c, user: string) => {\n      c.vars.online.set(c.conn.id, user);\n      c.broadcast(\"online\", [...c.vars.online.values()]);\n    },\n\n    sendMessage: async (c, text: string) => {\n      // Save the message\n      await c.db.execute(\"INSERT INTO messages VALUES (?, ?)\", \"user\", text);\n      const messages = await c.db.execute(\"SELECT role, content FROM messages\");\n\n      // Stream tokens to every connected client\n      const response = streamText({ model: openai(\"gpt-5\"), messages });\n      for await (const delta of response.textStream) {\n        c.broadcast(\"token\", delta);\n      }\n\n      // Save the response\n      await c.db.execute(\"INSERT INTO messages VALUES (?, ?)\", \"assistant\", await response.text);\n    },\n  },\n});\n\nexport const registry = setup({ use: { agent } });\n```\n\n```ts\n// client.ts (frontend or backend)\nimport { createClient } from \"rivetkit/client\";\nimport type { registry } from \"./server\";\n\nconst client = createClient<typeof registry>();\n\n// Open a WebSocket connection to the agent\nconst agent = client.agent.getOrCreate([\"agent-123\"]).connect();\n\n// Listen for realtime events\nagent.on(\"online\", users => console.log(\"online:\", users));\nagent.on(\"token\", delta => process.stdout.write(delta));\n\n// Call actions on the Actor\nawait agent.join(\"nathan\");\nawait agent.sendMessage(\"how many r's in strawberry?\");\n```\n\n### Why run agents on Rivet Actors?\n\nEach Actor gives the agent a **long-lived process** for long agent turns, **in-memory state** for context, a **WebSocket server** for multiplayer, **durable SQLite storage** for session transcripts and agent artifacts, and **hibernation** when idle.\n\nMost of an agent's time is spent **waiting on inference**. When the agent loop runs inside a sandbox, you pay for a whole VM that sits **mostly idle** with low CPU usage.\n\nRivet Actors run the agent loop outside of the sandbox instead, often called **\"separating the head from the hands.\"** The agent's state, memory, and context live in the Actor, and it reaches the sandbox through tools only when it needs to run code. This uses a fraction of the memory and limits the **blast radius** and **trust boundary** of the code it runs. Read more about [running the harness outside of the sandbox](https://www.rivet.dev/blog/2026-07-27-run-your-harness-outside-the-sandbox/).\n\n### Do I need a sandbox with a Rivet Actor?\n\nOften not. An agent needs a sandbox only to run code it writes. Developers on Rivet use three patterns:\n\n- **Agents with tools**: Many agents only need tool calls, MCP, and APIs, such as customer support or personal agents. No sandbox needed.\n- **Agents with a lightweight sandbox**: [agentOS](https://www.rivet.dev/agentos/docs) provides Linux-compatible sandboxing for JS and Python using V8 and WebAssembly, with full POSIX filesystems, networking stacks, and process trees. It covers most workloads, like data analysis, file processing, evals, and code mode.\n- **Agents with a full sandbox**: Keep your existing sandbox provider and expose its shell and filesystem to the agent as tools, such as a `bash` tool that runs commands in the sandbox. The Actor reattaches to it across sleeps and restarts. See the [sandbox coding agent example](https://github.com/rivet-dev/rivet/blob/main/examples/sandbox-coding-agent).\n\n## Getting Started\n\n### Use with your coding agent\n\nPaste this prompt into Claude Code, Cursor, Codex, or any coding agent:\n\n```\nRun npx skills add rivet-dev/skills, then ask me what to build and run it locally.\n```\n\n### Start from scratch\n\nRivet ships libraries built on top of Actors for common use cases.\n\n- **[Actors](https://www.rivet.dev/actors/docs)**: Long-lived processes with state, realtime, and scheduling built in.\n- **[Agents](https://www.rivet.dev/agents/docs)**: Durable agents built on Actors, with memory that survives restarts.\n- **[Workflows](https://www.rivet.dev/workflows/docs)**: Multi-step operations built on Actors that replay instead of starting over.\n- **[agentOS](https://www.rivet.dev/agentos/docs)**: Run the code your agent writes, securely, with granular control over network access, filesystem access, and resource limits.\n- **[Dynamic Apps](https://www.rivet.dev/dynamic-apps/docs)** (preview): A backend per user, deployed the moment it is generated.\n\n## How Actors compare to sandboxes\n\n| Metric              | Rivet Actor       | Sandbox          |\n| ------------------- | ----------------- | ---------------- |\n| Cold start (p99)    | **4.99 ms**       | 1.70 s           |\n| Memory per instance | **72.4 KB**       | 512 MiB          |\n| Storage             | **SQLite on S3**  | Disk per sandbox |\n| Storage cost        | **10.4× cheaper** | Replicated SSDs  |\n\nBenchmark details & methodology\n\n- **Rivet numbers** come from the published [Rivet Actors vs Cloudflare Durable Objects benchmark](https://github.com/rivet-dev/bench-rivet-actors-vs-durable-objects), run on Rivet 3.0.3. Its repository has the raw samples and the scripts to reproduce them.\n- **Sandbox numbers** are for [E2B](https://e2b.dev): 512 MiB is its default memory allocation from [E2B's billing documentation](https://docs.e2b.dev/billing) as of November 4, 2026, and 1.70 s is the p99 cold start from [ComputeSDK's October 30, 2026 sandbox benchmark](https://www.computesdk.com/benchmarks/sandboxes/burst-tti).\n- **Storage cost** compares S3 Standard with three Amazon EBS gp3 copies at AWS list prices.\n- Sources, dates, and the full method are at [rivet.dev/docs/benchmarking](https://www.rivet.dev/docs/benchmarking/).\n\n## Features\n\n- **Fault tolerance**: If a node goes down, its Actors move elsewhere with their state intact.\n- **HTTP & WebSocket networking**: Call an Actor over HTTP or hold a live WebSocket to it.\n- **End-to-end type safety**: Typed clients for your backend and React hooks for your frontend.\n- **Cron & scheduling**: Wake an Actor on a schedule or at a time it sets for itself.\n- **Actor-to-Actor calls**: Actors call each other by key across the cluster.\n- **Scoped JWTs**: Give each client a [JWT](https://www.rivet.dev/docs/jwt) scoped to the Actors it may reach.\n- **OpenTelemetry**: Traces, metrics, and logs in OTel format.\n\n## Deployment Options\n\n| Option                | Description                                                                                                                        | Get started                                                                      |\n| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------- |\n| **Local & self-host** | Run Rivet locally while you build. In production, run the control plane on Docker, Kubernetes, or a VM. S3 is the only dependency. | [Self-hosting docs](https://www.rivet.dev/docs/deploy/self-host/control-plane/) |\n| **Rivet Cloud**       | Fully managed, dedicated clusters on AWS or GCP in any region. Run your nodes on Rivet Cloud or bring your own.                    | [Dashboard](https://dashboard.rivet.dev)                                        |\n| **BYOC**              | The control plane runs inside your own VPC on AWS, GCP, or Azure, fully managed by Rivet. Your data never leaves your cloud.       | [BYOC docs](https://www.rivet.dev/docs/deploy/byoc/)                            |\n\nEvery option runs the same control plane, from local dev to production. [Talk to an engineer →](https://www.rivet.dev/talk-to-an-engineer)\n\n## Works with the tools you already use\n\nTyped SDKs for your backend and React hooks for your frontend. Rivet runs on native Node.js and Bun with no custom runtime, so your existing packages, tooling, and tests work unchanged.\n\n**Deploy nodes on**: [Docker Compose](https://www.rivet.dev/docs/deploy/self-host/nodes/docker-compose/) • [Kubernetes](https://www.rivet.dev/docs/deploy/self-host/nodes/kubernetes/) • [VM & bare metal](https://www.rivet.dev/docs/deploy/self-host/nodes/vm/) • [Hetzner](https://www.rivet.dev/docs/deploy/self-host/nodes/hetzner/) • [AWS ECS](https://www.rivet.dev/docs/deploy/self-host/nodes/aws-ecs/) • [Railway](https://www.rivet.dev/docs/deploy/self-host/nodes/railway/) • [Render](https://www.rivet.dev/docs/deploy/self-host/nodes/render/)\n\n**Frameworks**: [React](https://www.rivet.dev/actors/docs/clients/react) • [Effect](https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent-effect)\n\n**Runtimes**: [Node.js](https://www.rivet.dev/actors/docs/quickstart/backend) • [Bun](https://www.rivet.dev/actors/docs/quickstart/backend) • [Rust](https://www.rivet.dev/actors/docs/quickstart/rust)\n\n**Tools**: [Vitest](https://www.rivet.dev/actors/docs/testing) • [OpenTelemetry](https://www.rivet.dev/docs/tracing) • [Pino](https://www.rivet.dev/actors/docs/logging) • [AI SDK](https://github.com/rivet-dev/rivet/blob/main/examples/ai-agent) • [OpenAPI](https://github.com/rivet-dev/rivet/blob/main/rivetkit-openapi) • [AsyncAPI](https://github.com/rivet-dev/rivet/blob/main/rivetkit-asyncapi)\n\n[Request an integration →](https://github.com/rivet-dev/rivet/issues/new)\n\n## FAQ\n\n**Does Rivet have BYOC?**\n\nYes. Rivet deploys into your own cloud account, including air-gapped environments: the control plane and storage run inside your VPC while Rivet operates them. See the [BYOC docs](https://www.rivet.dev/docs/deploy/byoc/).\n\n**Does Rivet have a cloud?**\n\nYes. [Rivet Cloud](https://dashboard.rivet.dev) runs fully managed, dedicated clusters on AWS or GCP in any region. It can run your app's Docker image as [nodes on Rivet Cloud](https://www.rivet.dev/docs/deploy/cloud/compute/), or you can [bring your own nodes](https://www.rivet.dev/docs/deploy/self-host/nodes/).\n\n**Can I self-host Rivet?**\n\nYes. Rivet is fully self-hostable; see the [self-hosting docs](https://www.rivet.dev/docs/deploy/self-host/control-plane/). The control plane runs anywhere a container runs, with guides for Docker Compose, Kubernetes, VMs and bare metal, Hetzner, Railway, Render, and AWS ECS. For enterprise support with a self-hosted deployment, [contact us](https://www.rivet.dev/enterprise/).\n\n**Do I still need Postgres, FoundationDB, or NATS?**\n\nNo. An object storage bucket is the only dependency: there is no database to run and no message bus, and control plane instances find each other through the bucket. Rivet works with Amazon S3, Google Cloud Storage, Azure Blob Storage, and any S3-compatible store such as MinIO, Cloudflare R2, or Hetzner Object Storage. A local filesystem backend is available for trying Rivet on one machine.\n\n**Is Rivet open-source?**\n\nYes. Rivet is open source under the permissive Apache 2.0 license. You're looking at it.\n\n**Are Rivet Actors only for agents?**\n\nNo. Rivet is a general actor platform at its core, with nothing specific to agents. For agents, you can use the optional [agent library](https://www.rivet.dev/agents/docs/quickstart/), which runs Pi Durable on Rivet Actors, or write your own agent from scratch.\n\n**How does Rivet compare to sandboxes?**\n\nA sandbox boots a VM or container per agent, which is slow to start and sits mostly idle. A Rivet Actor runs inside a shared node process: 72 KB and 4.99 ms p99 to start, versus 512 MiB and 1.70 s for a sandbox, and it hibernates when idle. To run untrusted code your agent writes, use [agentOS](https://www.rivet.dev/agentos/docs).\n\n**How does Rivet compare to Cloudflare Durable Objects?**\n\nRivet is often used as an open-source alternative to Cloudflare Durable Objects that is easy to self-host and scales. It also fixes many of the constraints of Durable Objects: no 128 MB memory cap, bottomless storage instead of a 10 GB SQLite limit, Actors are not randomly evicted, and you control the runtime because Actors run on vanilla Node.js or Bun instead of a custom runtime. Rivet also adds built-in connection handling, event broadcasting, durable scheduling and cron, full Vitest support, lifecycle hooks for draining, and control over Actor upgrades. See the [Cloudflare Durable Objects comparison](https://www.rivet.dev/actors/compare/rivet-actors-vs-cloudflare-durable-objects/).\n\n**Does Rivet use a custom V8 runtime?**\n\nNo. Rivet runs on native Node.js and Bun, so your existing packages, tooling, and tests work unchanged.\n\n**Is Rivet like Erlang, Akka, or Orleans?**\n\nRivet implements the virtual actor pattern, which is closest to Orleans, but focuses on what modern workloads need: SQLite persistence instead of simple JSON stores and support for modern runtimes. Erlang and Akka do not provide virtual actors out of the box, though ecosystem packages exist that offer functionality comparable to Rivet Actors.\n\n**Does Rivet require microVMs, gVisor, or nested virtualization?**\n\nNo. Rivet only needs a standard process that connects to the control plane over WebSocket. That process can be Node.js, Bun, Rust, or anything else.\n\n## Projects in This Repository\n\n| Project                                                                                  | Description                                                            |\n| ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |\n| [RivetKit TypeScript](https://github.com/rivet-dev/rivet/blob/main/rivetkit-typescript) | Client & server library for building Actors                            |\n| [RivetKit Rust](https://github.com/rivet-dev/rivet/blob/main/rivetkit-rust)             | Rust SDK                                                               |\n| [RivetKit Python](https://github.com/rivet-dev/rivet/blob/main/rivetkit-python)         | Python client (experimental)                                           |\n| [RivetKit Swift](https://github.com/rivet-dev/rivet/blob/main/rivetkit-swift)           | Swift client (experimental)                                            |\n| [Control Plane](https://github.com/rivet-dev/rivet/blob/main/engine)                    | Rust control plane that schedules, routes, and persists Actors         |\n| ↳ [Pegboard](https://github.com/rivet-dev/rivet/blob/main/engine/packages/pegboard)     | Actor scheduling & networking                                          |\n| ↳ [Guard](https://github.com/rivet-dev/rivet/blob/main/engine/packages/guard)           | Traffic routing proxy                                                  |\n| ↳ [Epoxy](https://github.com/rivet-dev/rivet/blob/main/engine/packages/epoxy)           | Multi-region KV store (EPaxos)                                         |\n| [Documentation](https://github.com/rivet-dev/rivet/blob/main/docs)                      | Source for [rivet.dev/actors/docs](https://www.rivet.dev/actors/docs) |\n| [Examples](https://github.com/rivet-dev/rivet/blob/main/examples)                       | Runnable examples                                                      |\n\n## Community\n\n- [Discord](https://www.rivet.dev/discord) - Chat with the community\n- [X/Twitter](https://x.com/rivet_dev) - Follow for updates\n- [GitHub Discussions](https://github.com/rivet-dev/rivet/discussions) - Ask questions\n- [GitHub Issues](https://github.com/rivet-dev/rivet/issues) - Report bugs\n- [Talk to an engineer](https://www.rivet.dev/talk-to-an-engineer) - Discuss your use case\n\n## License\n\n[Apache 2.0](https://github.com/rivet-dev/rivet/blob/main/LICENSE)\n",
  "dateCreated": "2026-11-06T11:27:16.888185679+00:00",
  "date_created": "2026-11-05T17:17:42+00:00",
  "date_modified": "2026-11-05T17:17:42+00:00",
  "date_published": "2026-11-05T17:17:42+00:00",
  "description": "Hey HN, this is Nathan and Nicholas from Rivet (https://rivet.dev) – a fast, high-density, and scalable orchestrator for agentic workloads using the actor model. Rather than running a heavyweight sandbox per agent, each agent gets a…",
  "external_url": "https://github.com/rivet-dev/rivet",
  "git": {
    "commit": "20068632b65d2830a2d54f25ca1d90d697bea2c0",
    "path": "items/hnrss-org/2026/11/2026-11-05-launch-hn-rivet-yc-w23-scale-and-orchestrate-agents-on-s3.md",
    "permalink": "https://github.com/aymericbeaumet/aggr-instance/blob/20068632b65d2830a2d54f25ca1d90d697bea2c0/items/hnrss-org/2026/11/2026-11-05-launch-hn-rivet-yc-w23-scale-and-orchestrate-agents-on-s3.md"
  },
  "id": "urn:aggr:item:08276578bee1b65a587160b196109b08f769cf13",
  "isBasedOn": {
    "@id": "https://github.com/rivet-dev/rivet"
  },
  "mainEntity": {
    "@id": "https://github.com/rivet-dev/rivet",
    "@type": "CreativeWork",
    "archivedAt": {
      "@id": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-05-launch-hn-rivet-yc-w23-scale-and-orchestrate-agents-on-s3/#webpage"
    },
    "author": [
      {
        "@type": "Person",
        "name": "NathanFlurry"
      }
    ],
    "dateModified": "2026-11-05T17:17:42+00:00",
    "datePublished": "2026-11-05T17:17:42+00:00",
    "headline": "Launch HN: Rivet (YC W23) – Scale and Orchestrate Agents on S3",
    "image": {
      "@type": "ImageObject",
      "caption": "The orchestrator for agentic workloads. A fast, high-density and scalable orchestrator for every workload an agent needs. - rivet-dev/rivet",
      "height": 90,
      "url": "https://repository-images.githubusercontent.com/654560183/d4b2fdae-1a15-4420-a2a3-17256a51ae24",
      "width": 160
    },
    "timeRequired": "PT9M",
    "url": "https://github.com/rivet-dev/rivet",
    "wordCount": 1908
  },
  "name": "Archived snapshot: Launch HN: Rivet (YC W23) – Scale and Orchestrate Agents on S3",
  "preview": {
    "alt": "The orchestrator for agentic workloads. A fast, high-density and scalable orchestrator for every workload an agent needs. - rivet-dev/rivet",
    "color": null,
    "height": 90,
    "placeholder": {
      "data_url": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+A8AAQUBAScY42YAAAAASUVORK5CYII=",
      "hash": ""
    },
    "url": "https://repository-images.githubusercontent.com/654560183/d4b2fdae-1a15-4420-a2a3-17256a51ae24",
    "width": 160
  },
  "reading_minutes": 9,
  "replicated_at": null,
  "source": "hnrss-org",
  "source_name": "Hacker News: Front Page",
  "summary": "Hey HN, this is Nathan and Nicholas from Rivet (https://rivet.dev) – a fast, high-density, and scalable orchestrator for agentic workloads using the actor model. Rather than running a heavyweight sandbox per agent, each agent gets a lightweight actor backed by S3. Actors provide a long-lived process for long agent turns, in-memory state for context, a WebSocket server for multiplayer, durable SQLite storage backed by S3, and hibernation when idle. It's a similar model to Cloudflare Durable Objects, but it’s open source and self-hostable. Here’s a video walkthrough: https://www.youtube.com/watch?v=3Ev6I7DOV9c When we went through YC in 2023, we were building infrastructure for multiplayer games like Diep and Krunker. This involved heavily optimizing high-throughput matchmaking, real-time player messages, and blitz scaling. Through that process, we spent a lot of time on workloads where Postgres couldn't keep up with our throughput. We started out by hacking together Lua scripts on top of Redis, but this became too cumbersome to maintain and upgrade. This led us to extend our game server orchestrator to support what we call Rivet Actors today: many lightweight workers with in-memory state and durable storage. By using actors, we were able to serve tens of millions of monthly active users. As agents grew in popularity, it became clear that running agents in sandboxes is inefficient. Sandboxes are expensive, mostly idle, and slow to start. Developers started using actors because they are far more memory efficient (72 KB baseline for actors vs 512 MB for a minimal sandbox) and fast to start (4.9 ms p99 for actors vs 1.7 s p99 for sandboxes). For example, Amp is using Rivet to orchestrate multiplayer agents. They originally tried to build on Cloudflare Durable Objects, but couldn’t launch because of the platform’s limitations and unresponsive support. They migrated to Rivet Actors in a weekend and deploy on-prem. Rivet’s flexible architecture lets them adapt it to their own use cases without being constrained by a framework or the memory, storage, and runtime limits of Cloudflare Durable Objects. Under the hood, Rivet is backed by S3 while maintaining SSD speeds. Why S3? Previously, Rivet ran on FoundationDB. However, we were surprised to find that companies are storing orders of magnitude more data on Rivet Actors than in Postgres, such as large session transcripts, agent artifacts, and full POSIX filesystems. As their data grew, they had to start paying for SSDs that sat mostly idle with old transcripts. This led us to double down on S3 as our primary storage medium without sacrificing performance. This choice means that data stored on Rivet is 10× cheaper than on EBS gp3 while maintaining SSD speeds. It’s not as simple as writing data straight to S3. Lots of PUTs for tiny blobs of data are slow and expensive. Instead, we use an SSD tier to optimize speed and cost: When you write data to an actor’s SQLite database, the write is acknowledged once SSDs in 2 of 3 availability zones have it. Then, the data is batched to S3 in the background. This means that S3 is never on the write path, which lowers latency and cost. When reading data or waking an actor, Rivet reads from SSDs if already cached and falls back to S3 if not. SSD caches can be tuned to meet your needs, giving you configurable tiered storage for your actors. This architecture lets Rivet provide 1.07 ms durable writes (3 AZ, p99), 1.36 ms reads (p99), and 138 ms reads from object storage (p99). We’ve spent a lot of time making sure that Rivet can run wherever you need it. Self-hosting requires deploying a single Rust binary with S3 as the only dependency, Rivet Cloud lets you deploy dedicated clusters on AWS or GCP in any region, and BYOC lets us deploy Rivet to your VPC without having to operate it yourself. Rivet also runs identically in local dev as in production, since Rivet is a lightweight binary that runs anywhere Rivet Actors can be written in TypeScript or Rust. Out of the box, they support agents (Pi Durable), workflows, real-time, multiplayer, running AI-generated code, Durable Streams, and integrations with tools like Vercel’s Eve and Turso. See all of our available guides, or point your agent at them: https://rivet.dev/docs/#guides Try it out now, by reading our quickstart guides (https://rivet.dev/docs/) or ask your agent: “Run npx skills add rivet-dev/skills, then build a multiplayer chat agent and run it locally.” We’d love to get feedback on your experience with Rivet! We’re deeply invested in making Rivet an easy-to-self-host, flexible, and efficient way to run agentic workloads. GitHub: https://github.com/rivet-dev/rivet Architecture: https://rivet.dev/docs/architecture/ Benchmarks: https://rivet.dev/docs/benchmarking/ Self-hosting: https://rivet.dev/docs/deploy/self-host/ Comments URL: https://news.ycombinator.com/item?id=50381687 Points: 100 # Comments: 52",
  "tags": [],
  "temporalCoverage": "2026-11-06T11:27:16.888185679+00:00",
  "title": "Launch HN: Rivet (YC W23) – Scale and Orchestrate Agents on S3",
  "url": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-11-05-launch-hn-rivet-yc-w23-scale-and-orchestrate-agents-on-s3/",
  "word_count": 1908
}