Built-in Tools
Pi's file and shell tools, where they run with and without a sandbox, and how to choose them.
Built-in tools are Pi’s own file and shell tools. The CodingTools extension from @earendil-works/pi-durable/tools installs all four:
| Tool | What it does |
|---|---|
read | Reads a text file. The model reads a long file in parts. |
write | Creates or replaces a file. |
edit | Changes part of a file. |
bash | Runs a shell command. |
Where they run
The sandbox option decides where the tools run. They never touch your worker’s file system or shell.
| Tool | Without a sandbox | With a sandbox |
|---|---|---|
read, write, edit | Files in the Actor’s own SQLite database. | Files in the sandbox. |
bash | Returns an error. There is no shell. | Runs in the sandbox. |
Without a sandbox, there is nothing to set up. The files are saved with the conversation and survive sleep and crashes. This agent has no sandbox, so it installs the file tools without bash:
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";
// This agent has no sandbox, so its files live in the Actor's own database.
// There is no shell, so it gets read, write, and edit without bash.
const extensions = createRegistry();
extensions.install(defineExtension({ name: "files", tools: [createReadTool(), createWriteTool(), createEditTool()] }));
const writer = pi({
model: "anthropic/claude-opus-5-5",
registry: extensions,
});
export const registry = setup({ use: { writer } });
registry.start();
import { createClient } from "rivetkit/client";
import type { registry } from "./server";
const client = createClient<typeof registry>();
const writer = client.writer.getOrCreate(["docs-123"]);
await writer.prompt("Write a README.md for a command-line todo app.");
const result = await writer.prompt("Add an Install section to README.md.");
console.log(result.status === "done" ? result.text : `Unanswered: ${result.reason}`);
The second prompt edits the file that the first prompt wrote. To run commands, give the agent a sandbox.
Choose tools
Each tool also has its own factory: createReadTool, createWriteTool, createEditTool, and createBashTool. Install only the tools you want in your own extension. This reviewer can read files and run tests, but it has no write or edit tool:
import { createRegistry, defineExtension } from "@earendil-works/pi-durable";
import { createBashTool, createReadTool } 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 and bash, without the write and edit tools
const extensions = createRegistry();
extensions.install(defineExtension({ name: "review-tools", tools: [createReadTool(), createBashTool()] }));
const reviewer = pi({
model: "anthropic/claude-opus-5-5",
registry: extensions,
sandbox: e2bProvider(),
});
export const registry = setup({ use: { reviewer } });
registry.start();
- The
bashtool can still change files in the sandbox. For an agent that must not change anything, leavebashout too. - A client can narrow the tools of one conversation with
conversation.configure(id, { tools: ["read"] }). - In a sandbox, the file tools reject paths outside the sandbox’s working directory.
- The
bashtool accepts a timeout, and long output is truncated before it reaches the model. - Images aren’t supported yet. The
readtool returns an error for an image file.
To give an agent your own tools, see Custom Tools.