Pi Coding Agent

https://github.com/badlogic/pi-mono 9e22d39
MIT TypeScript linuxmacoswindows
Confidence levels high Confirmed in source · medium Inferred from patterns · low Best guess

Core Metadata

License high

MIT

Primary Language high

TypeScript

Extensions are TypeScript modules
"dev": "tsgo -p tsconfig.build.json --watch --preserveWatchOutput"
Platforms high

linux, macos, windows

`~/Library/Application Support/Code/User/keybindings.json`
`~/.config/Code/User/keybindings.json`

Edit

Mechanism high

str_replace

const editSchema = Type.Object({
Edit a file by replacing exact text.
Anchoring high

Anchored by matching oldText in file content: exact match first, then fuzzy-normalized fallback; replacement must be unique.

Find the old text using fuzzy matching (tries exact match first, then fuzzy)
Find oldText in content, trying exact match first, then fuzzy match.
Verification high

Rejects on missing match, non-unique match, or no-op replacement; applies single replacement and writes full file (no partial merge).

if (baseContent === newContent)
await ops.writeFile(absolutePath, finalContent);
Retry Loop medium

No edit-specific auto-retry loop in harness code; edit errors are surfaced to the agent as tool failures.

Failure Modes high
  • file_not_found
  • old_text_not_found
  • non_unique_old_text
  • no_effect_change
  • aborted
Could not find the exact text in ${path}.
Found ${occurrences} occurrences of the text
No changes made to ${path}.
reject(new Error("Operation aborted"));

Tools

Available high

read, write, edit, bash, grep, find, ls, extension_tools

Available built-in tools: `read`, `bash`, `edit`, `write`, `grep`, `find`, `ls`
**Custom tools** - Register tools the LLM can call via `pi.registerTool()`
Schema Style high

TypeBox JSON-schema-like parameter objects, validated before tool execution.

export interface Tool<TParameters extends TSchema = TSchema>
const editSchema = Type.Object({
const validatedArgs = validateToolArguments(tool, toolCall);
Sandbox medium

No built-in permission popup/approval sandbox; bash runs in configured cwd, and file tools resolve relative-to-cwd or absolute paths.

Config

Locations high
  • path: ~/.pi/agent/settings.json scope: global precedence: lower
  • path: .pi/settings.json scope: project precedence: higher
  • path: ~/.pi/agent (base dir, overridable via env) scope: global precedence: base
`~/.pi/agent/settings.json` | Global (all projects)
`.pi/settings.json` | Project (current directory)
project/overrides take precedence
const envDir = process.env[ENV_AGENT_DIR];
Env Vars high
  • name: PI_CODING_AGENT_DIR meaning: Override agent config directory (default ~/.pi/agent)
  • name: PI_PACKAGE_DIR meaning: Override package asset directory
  • name: PI_SKIP_VERSION_CHECK meaning: Skip startup version check
  • name: PI_CACHE_RETENTION meaning: Configure prompt cache retention policy
  • name: VISUAL meaning: External editor selection
  • name: EDITOR meaning: External editor selection fallback
  • name: Provider API key vars meaning: Provider-specific env vars (e.g., OPENAI_API_KEY, ANTHROPIC_API_KEY, GEMINI_API_KEY)
`PI_CODING_AGENT_DIR` | Override config directory
`PI_PACKAGE_DIR` | Override package directory
`PI_CACHE_RETENTION`
`VISUAL`, `EDITOR`
const envMap: Record<string, string> = {

Extensions

Supported high

true

Skills are self-contained capability packages
Locations high

~/.pi/agent/skills/, .pi/skills/, package skills/ or pi.skills in package.json, settings skills[] paths, --skill <path>

Pi loads skills from:
CLI: `--skill <path>`
Format high

Markdown SKILL.md with frontmatter (Agent Skills spec).

A skill is a directory with a `SKILL.md` file.
Plugins high

TypeScript extension API plus pi package ecosystem; extensions can register tools/commands/flags/providers and intercept tool calls/results.

Extensions are TypeScript modules that extend pi's behavior.
registerTool(tool: ToolDefinition): void
Pi packages bundle extensions, skills, prompt templates, and themes
Mcp medium

No built-in MCP in core harness; MCP integration is expected via extensions.

Providers

Supported high

amazon-bedrock, anthropic, google, google-gemini-cli, google-antigravity, google-vertex, openai, azure-openai-responses, openai-codex, github-copilot, xai, groq, cerebras, openrouter, vercel-ai-gateway, zai, mistral, minimax, minimax-cn, huggingface, opencode, kimi-coding

export type KnownProvider =
Auth high

Supports OAuth login and API keys. Resolution order: --api-key runtime override, auth.json entry, environment variable, then models.json fallback resolver.

Model Selection high

Interactive `/model` command and CLI flags (`--provider`, `--model`); defaults and cycling are configurable in settings.

select any model from that provider via `/model`
`--provider <name>`
`--model <pattern>`

Ux

Interface high

CLI/TUI interactive interface, plus non-interactive print, JSON stream, RPC, and SDK embeddings.

Pi runs in four modes: interactive, print or JSON, RPC for process integration, and an SDK for embedding in your own apps.
(default) | Interactive mode
Streaming high

Yes. Assistant/token/tool events stream; JSON mode emits event stream lines.

Outputs all session events as JSON lines to stdout.
session.subscribe((event) => {
Review Controls medium

No built-in permission popup approvals in core; confirmation gates can be added by extensions.

No permission popups.
pi.on("tool_call", async (event, ctx) => {
Sessions high

Sessions persist as JSONL trees under ~/.pi/agent/sessions (unless --no-session/in-memory mode).

Sessions are stored as JSONL files with a tree structure.
Sessions auto-save to `~/.pi/agent/sessions/`
Compute the default session directory for a cwd.

Context

Compaction high

Auto-compaction summarizes old context when threshold exceeded; manual /compact is also supported; settings control reserve/keep token budgets.

Compaction | Context exceeds threshold, or `/compact`
contextTokens > contextWindow - reserveTokens
return this.settings.compaction?.reserveTokens ?? 16384;
Overflow Handling high

On context overflow, pi removes the overflow error message from active context, auto-compacts, then retries the agent run.

if (sameModel && !errorIsFromBeforeCompaction && isContextOverflow(assistantMessage, contextWindow)) {
await this._runAutoCompaction("overflow", true);
this.agent.continue().catch(() => {});

Reliability

Auto Retry high

Built-in transient-error retry with exponential backoff; configurable (`retry.enabled`, `maxRetries`, delays) and disable-able.

Match: overloaded_error, rate limit, 429, 500, 502, 503, 504
const delayMs = settings.baseDelayMs * 2 ** (this._retryAttempt - 1);
`retry.enabled` | boolean | `true`
Recovery Loops high

Two recovery loops: (1) overflow-triggered auto-compaction + continue; (2) transient-error auto-retry loop. Both emit start/end events.

Check auto-retry and auto-compaction after agent completes
this._emit({ type: "auto_compaction_start", reason });

Integration

Sdk high

Supported TypeScript/Node SDK in @mariozechner/pi-coding-agent (createAgentSession/AgentSession API).

import { AuthStorage, createAgentSession, ModelRegistry, SessionManager }
npm install @mariozechner/pi-coding-agent
Modes high

interactive, print, json_event_stream, rpc, sdk_embedding

Pi runs in four modes: interactive, print or JSON, RPC for process integration, and an SDK for embedding in your own apps.
`--mode json` | Output all events as JSON lines
`--mode rpc` | RPC mode for process integration
Protocol high

JSON lines protocol over stdio. RPC commands on stdin, responses/events on stdout; JSON mode streams AgentSession events as JSONL.

**Commands**: JSON objects sent to stdin, one per line
**Events**: Agent events streamed to stdout as JSON lines
Each line is a JSON object.

Customization

System Prompt high

System prompt can be replaced by SYSTEM.md (project over global), appended via APPEND_SYSTEM.md, and overridden/appended by CLI flags.

Replace the default system prompt with `.pi/SYSTEM.md` (project) or `~/.pi/agent/SYSTEM.md` (global).
const projectPath = join(this.cwd, CONFIG_DIR_NAME, "SYSTEM.md")
`--system-prompt <text>` | Replace default prompt
Prompt Templates high

Markdown prompt files loaded from global/project/package/settings/CLI paths, invoked as slash commands with argument substitution.

Global: `~/.pi/agent/prompts/*.md`
export function substituteArgs(content: string, args: string[]): string
Keybindings high

Customizable via JSON at ~/.pi/agent/keybindings.json; user config overrides defaults.

customized via `~/.pi/agent/keybindings.json`
User config overrides defaults.
const configPath = join(agentDir, "keybindings.json")
Themes high

Themes are JSON files loaded from built-ins, global/project dirs, packages, settings, or CLI paths; active custom theme hot-reloads.

Themes are JSON files
Pi loads themes from:
pi reloads it automatically

Distribution

Artifacts high

npm package: @mariozechner/pi-coding-agent, [object Object], optional compiled binary via bun build --compile

npm install -g @mariozechner/pi-coding-agent
"build:binary": "npm run build && bun build --compile ./dist/cli.js --outfile dist/pi && npm run copy-binary-assets",

Packages

Install Locations high

global npm install root and ~/.pi/agent/git/<host>/<path>, project-local .pi/npm/node_modules and .pi/git/<host>/<path>, temporary extension installs under tmpdir for one-off -e/--extension

Use `-l` to write to project settings (`.pi/settings.json`) instead.
- Cloned to `~/.pi/agent/git/<host>/<path>` (global) or `.pi/git/<host>/<path>` (project).
return join(this.cwd, CONFIG_DIR_NAME, "npm", "node_modules", source.name);
return join(this.agentDir, "git", source.host, source.path);

Extras

messaging.queue_controls high

Pi has explicit steering vs follow-up queue semantics and modes.

- **Enter** queues a *steering* message, delivered after current tool execution (interrupts remaining tools)
async steer(text: string, images?: ImageContent[]): Promise<void> {
async followUp(text: string, images?: ImageContent[]): Promise<void> {
extensions.ui_bridge_modes high

RPC mode maps extension UI calls into protocol messages; some UI capabilities are unavailable in RPC.

* Create an extension UI context that uses the RPC protocol.
// Working message not supported in RPC mode - requires TUI loader access
// Custom UI not supported in RPC mode
packages.filtering_controls high

Pi supports include/exclude and exact force include/exclude patterns (`!`, `+`, `-`) for package resources.

`+path` and `-path` are exact paths relative to the package root.
* Apply patterns to paths and return a Set of enabled paths.
function applyPatterns(allPaths: string[], patterns: string[], baseDir: string): Set<string> {