Quickstart
Run your first Pi agent in a Rivet Actor. Its files live in the Actor's database, so there is nothing else to set up.
An agent is a Rivet Actor in your backend. Clients prompt it like any other Actor. Each step of a run is saved to the Actor’s SQLite database, so a run survives sleep, crashes, and upgrades.
Install
npm add @rivet-dev/pi @earendil-works/pi-durable rivetkit
Define the agent
import { createRegistry, defineExtension } from "@earendil-works/pi-durable";
import { createEditTool, createReadTool, createWriteTool } from "@earendil-works/pi-durable/tools";
import { pi } from "@rivet-dev/pi";
import { setup } from "rivetkit";
// read, write, and edit. With no sandbox, the files live in the Actor's own database.
const extensions = createRegistry();
extensions.install(defineExtension({ name: "files", tools: [createReadTool(), createWriteTool(), createEditTool()] }));
const agent = pi({
model: "anthropic/claude-opus-5-5",
registry: extensions,
});
export const registry = setup({ use: { agent } });
registry.start();
Set ANTHROPIC_API_KEY. For another model provider, change model and set that provider’s key, such as OPENAI_API_KEY. See LLM API Keys.
The agent needs no sandbox. Its read, write, and edit tools work on files stored in the Actor’s own database.
Send a prompt
TypeScript
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>();
const agent = client.agent.getOrCreate(["user-123"]);
const result = await agent.prompt(
"Write a hello-world Rivet Actor to counter.ts, then read the file back to me.",
{ requestId: crypto.randomUUID() },
);
console.log(result.status === "done" ? result.text : `Unanswered: ${result.reason}`);
curl
URL="http://localhost:6420/gateway/agent/action"
AGENT="rvt-namespace=default&rvt-method=getOrCreate&rvt-key=user-123&rvt-pool=default"
curl -X POST "$URL/prompt?$AGENT" \
-H "Content-Type: application/json" \
-d '{"args": ["Write a hello-world Rivet Actor to counter.ts, then read the file back to me.", {"requestId": "counter-1"}]}'
Each action is a POST to the gateway with its arguments in args. See Call Action.
The prompt action waits for the run to finish and returns { status, text }. A model error doesn’t reject it: status is unanswered, with Pi’s reason. Sending the same requestId again returns the first answer instead of running twice.
Add a sandbox (optional)
To let the agent run commands, give it a sandbox and Pi’s CodingTools, which add bash:
npm add @rivet-dev/sandbox-adapter e2b
import { createRegistry } from "@earendil-works/pi-durable";
import { CodingTools } from "@earendil-works/pi-durable/tools";
import { pi } from "@rivet-dev/pi";
import { e2bProvider } from "@rivet-dev/sandbox-adapter/e2b";
import { setup } from "rivetkit";
// read, write, edit, and bash, running in the sandbox
const extensions = createRegistry();
extensions.install(CodingTools);
const agent = pi({
model: "anthropic/claude-opus-5-5",
registry: extensions,
sandbox: e2bProvider(),
});
export const registry = setup({ use: { agent } });
registry.start();
import { createRegistry } from "@earendil-works/pi-durable";
import { CodingTools } from "@earendil-works/pi-durable/tools";
import { pi } from "@rivet-dev/pi";
import { daytonaProvider } from "@rivet-dev/sandbox-adapter/daytona";
import { setup } from "rivetkit";
// read, write, edit, and bash, running in the sandbox
const extensions = createRegistry();
extensions.install(CodingTools);
const agent = pi({
model: "anthropic/claude-opus-5-5",
registry: extensions,
sandbox: daytonaProvider(),
});
export const registry = setup({ use: { agent } });
registry.start();
Set E2B_API_KEY for E2B, or install @daytonaio/sdk and set DAYTONA_API_KEY for Daytona. See Sandboxes.
Deploy
By default, Rivet stores Actor state on the local file system.
To scale Rivet in production, pick how much of it you want to run yourself:
Fully managed
Bring your own compute
Full self-hosting
If you are running your own workers, follow the guide for your hosting provider:
Docker Compose
Kubernetes
Virtual Machine
AWS ECS
Railway
Render
Custom Platform
Vercel
Google Cloud Run
AWS Lambda
Next: Pi, for how a run survives crashes and upgrades, and its known limitations.