Skip to main content
General

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.

Clientclient.tsAgent Actorserver.tsSandboxoptionalModel providerprompttool callsmodel calls

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

agentOS needs no provider account. For E2B, install e2b and set E2B_API_KEY. For Daytona, install @daytonaio/sdk and set DAYTONA_API_KEY. 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:

If you are running your own workers, follow the guide for your hosting provider:

Next: Pi, for how a run survives crashes and upgrades, and its known limitations.