Pi
Run the Pi coding agent as a durable Rivet Actor.
This integration is in beta. APIs may change between releases.
@rivet-dev/pi runs the Pi coding agent in a Rivet Actor. The agent loop runs in the actor. Pi’s file and shell tools run in a separate sandbox.
Each actor holds one Pi session and saves it in its SQLite database, so a conversation survives sleep and restarts.
Quickstart
Install
npm add @rivet-dev/pi rivetkit
Define the actor
import { pi } from "@rivet-dev/pi";
import { setup } from "rivetkit";
const agent = pi({ model: "anthropic/claude-opus-5-5" });
export const registry = setup({
use: { agent },
});
registry.start();
Set the key for your model provider, such as ANTHROPIC_API_KEY.
Send a prompt
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>("http://localhost:6420");
const agent = client.agent.getOrCreate(["support", "customer-123"]);
const conn = agent.connect();
await conn.prompt("Inspect the project and summarize its test failures.");
console.log(await conn.getLastAssistantText());
await conn.dispose();
The client waits for Pi to finish, then reads the full reply with getLastAssistantText().
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:
Configuration
pi() accepts the same config as actor() and Pi’s session options, plus:
| Option | Description |
|---|---|
model | Model for a new session. |
scopedModels | Models a client may switch to with setModel. |
apiKeys | API keys by provider. Otherwise keys come from the environment. |
providers | Custom providers, in the shape of Pi’s models.json. |
credentials | Logins your application stores, such as subscriptions. See Bring your subscription. |
sandbox | Where Pi’s file and shell tools run. Without it they are disabled. |
import { agentOS } from "@rivet-dev/agentos";
import { pi } from "@rivet-dev/pi";
import { agentOSProvider } from "@rivet-dev/sandbox-adapter/agentos";
import { setup } from "rivetkit";
const agent = pi({
model: "anthropic/claude-opus-5-5",
sandbox: agentOSProvider({ actor: "vm" }),
});
export const registry = setup({ use: { agent, vm: agentOS() } });
For E2B, Daytona, or Modal, use sandboxAgentProvider() from @rivet-dev/sandbox-adapter/sandbox-agent. Provider credentials never enter the sandbox.
Tracing
Each run is an invoke_agent pi span under the prompt action span, with OpenTelemetry GenAI attributes. Prompts, tool arguments, and tool results are not recorded. See OpenTelemetry to export actor traces.
Bring your subscription
Your users can run Pi on their own Claude or ChatGPT subscription instead of your API key. Pi supports headless OAuth login for these subscriptions.
Pass the logins you store to Pi with credentials:
import { pi } from "@rivet-dev/pi";
const agent = pi({
model: "openai-codex/gpt-6-sol",
credentials: (c) => ({
list: () => logins.list(c.key[0]),
read: (provider) => logins.read(c.key[0], provider),
refresh: (provider) => logins.refresh(c.key[0], provider),
}),
});
logins is your own storage. See PiCredentialSource for what each method returns. Pi never receives the refresh token.
The credentials example stores logins in a credentials actor and runs the login in a terminal.