# Pi

## Quick start

examples/pi/server.ts:

```ts
import { agentOS, setup } from "@rivet-dev/agentos";
import pi from "@agentos-software/pi";

const vm = agentOS({ software: [pi] });

export const registry = setup({ use: { vm } });
registry.start();
```

examples/pi/client.ts:

```ts
async function quickStart() {
	await agent.sessions.open({
		agent: "pi",
		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
	});

	const result = await agent.sessions.prompt({
		content: [
			{ type: "text", text: "What files are in the current directory?" },
		],
	});
	console.log(result.message?.content ?? []);
}
```

Read [Sessions](/agentos/docs/sessions) first for session options, streaming events, prompts, and lifecycle management.

## Model & 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 [Models & Credentials](/agentos/docs/models-and-credentials), and Pi's [providers docs](https://github.com/badlogic/pi-mono/blob/main/packages/coding-agent/docs/providers.md) 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.

examples/pi/client.ts:

```ts
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.filesystem.mkdir("/home/agentos/.pi/agent/skills/commit-style");
	await agent.filesystem.writeFile(
		"/home/agentos/.pi/agent/skills/commit-style/SKILL.md",
		skill,
	);

	await agent.sessions.open({
		agent: "pi",
		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
	});
}
```

## MCP servers

Expose extra tools to the agent by passing `mcpServers` to `openSession`. Both local child-process servers and remote URLs are supported.

examples/pi/client.ts:

```ts
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.filesystem.mkdir("/home/agentos/.pi/agent");
await agent.filesystem.writeFile("/home/agentos/.pi/agent/.mcp.json", mcpConfig);

await agent.sessions.open({
	agent: "pi",
	env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
});
```

> **NOTE:** **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.process.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](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent/examples/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 |

examples/pi/client.ts:

```ts
	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.filesystem.mkdir("/home/agentos/.pi/agent/extensions");
	await agent.filesystem.writeFile(
		"/home/agentos/.pi/agent/extensions/formal.js",
		extensionCode,
	);

	// Pi discovers the extension automatically
	await agent.sessions.open({
		agent: "pi",
		env: { ANTHROPIC_API_KEY: process.env.ANTHROPIC_API_KEY! },
	});
```

See the [Pi extension documentation](https://github.com/badlogic/pi-mono/tree/main/packages/coding-agent/examples/extensions) 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](/agentos/docs/agents/custom).
