Pi
Run the Pi coding agent inside a VM with extensions and custom configuration.
Quick start
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "./software/pi";
const vm = agentOS({ software: [pi] });
export const registry = setup({ use: { vm } });
registry.start();
Read Sessions first for session options, streaming events, prompts, and lifecycle management.
LLM Credentials
Set the relevant variable on the session’s env, sourced from your server’s environment:
ANTHROPIC_API_KEY— Anthropic (Claude), the default.- Other providers — use the provider-named key (e.g.
OPENAI_API_KEY,GEMINI_API_KEY,OPENROUTER_API_KEY).
See LLM Credentials, and Pi’s providers docs for the full list.
Skills
Pi discovers SKILL.md files from its skills directory. Write the skill into the VM before creating a session and Pi loads it automatically.
async function withSkill() {
const skill = `---
name: commit-style
description: How to write commit messages in this project.
---
Write commit messages in the imperative mood and keep the subject under 50 characters.
`;
await agent.mkdir("/home/agentos/.pi/agent/skills/commit-style");
await agent.writeFile("/home/agentos/.pi/agent/skills/commit-style/SKILL.md", skill);
const sessionId = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
console.log(sessionId);
}
MCP servers
Expose extra tools to the agent by passing mcpServers to createSession. Both local child-process servers and remote URLs are supported.
const mcpConfig = JSON.stringify({
mcpServers: {
filesystem: {
command: "npx",
args: ["-y", "@modelcontextprotocol/server-filesystem", "/home/agentos"],
},
remote: {
url: "https://mcp.example.com/sse",
headers: { Authorization: "Bearer my-token" },
},
},
});
await agent.mkdir("/home/agentos/.pi/agent");
await agent.writeFile("/home/agentos/.pi/agent/.mcp.json", mcpConfig);
const sessionId = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
Pre-install npx-launched servers. A local server started with npx -y … writes install progress to stdout on its first run, which corrupts the MCP stdio handshake (you’ll see Connection closed). Pre-install it in the VM so npx is silent — await agent.exec("npm install -g @modelcontextprotocol/server-filesystem") before the session — or pin the package and point command at the installed binary.
Extensions
Pi supports extensions that let you register custom tools, modify the system prompt, and hook into agent lifecycle events. Write a .js file into the VM’s extensions directory before creating a session and Pi discovers it automatically.
Pi scans two directories for .js extension files:
| Directory | Scope |
|---|---|
~/.pi/agent/extensions/ | Global — applies to all Pi sessions |
<cwd>/.pi/extensions/ | Project — applies only when cwd matches |
const extensionCode = `
export default function(pi) {
// Modify the system prompt before each agent turn
pi.on("before_agent_start", async (event) => {
return {
systemPrompt: event.systemPrompt +
"\\n\\nAlways respond in formal English."
};
});
}
`;
// Write the extension before creating the session
await agent.mkdir("/home/agentos/.pi/agent/extensions");
await agent.writeFile("/home/agentos/.pi/agent/extensions/formal.js", extensionCode);
// Pi discovers the extension automatically
const sessionId = await agent.createSession("pi", {
env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
See the Pi extension documentation for the full extension API.
Customizing the agent
Pi is a built-in agent, but it’s just a software package under the hood. To ship your own ACP adapter, swap the underlying agent SDK, or register a tweaked Pi build as a new agent, see Custom Agents.