Pi is a minimal terminal coding harness. Adapt pi to your workflows, not the other way around, without having to fork and modify pi internals. Extend it with TypeScript [Extensions](#extensions), [Skills](#skills), [Prompt Templates](#prompt-templates), and [Themes](#themes). Put your extensions, skills, prompt templates, and themes in [Pi Packages](#pi-packages) and share them with others via npm or git.
Pi ships with powerful defaults but skips features like sub agents and plan mode. Instead, you can ask pi to build what you want or install a third party pi package that matches your workflow.
Pi runs in four modes: interactive, print or JSON, RPC for process integration, and an SDK for embedding in your own apps. See [clawdbot/clawdbot](https://github.com/clawdbot/clawdbot) for a real-world SDK integration.
## Table of Contents
- [Getting Started](#getting-started)
- [Installation](#installation)
- [Windows Setup](#windows-setup)
- [Shell Aliases](#shell-aliases)
- [Terminal Setup](#terminal-setup)
- [Authentication](#authentication)
- [Quick Start](#quick-start)
- [Usage](#usage)
- [Slash Commands](#slash-commands)
- [Editor Features](#editor-features)
- [Keyboard Shortcuts](#keyboard-shortcuts)
- [Custom Keybindings](#custom-keybindings)
- [Bash Mode](#bash-mode)
- [Image Support](#image-support)
- [Sessions](#sessions)
- [Session Management](#session-management)
- [Context Compaction](#context-compaction)
- [Branching](#branching)
- [Configuration](#configuration)
- [Project Context Files](#project-context-files)
- [Custom System Prompt](#custom-system-prompt)
- [Custom Models and Providers](#custom-models-and-providers)
- [Settings File](#settings-file)
- [Customization](#customization)
- [Themes](#themes)
- [Prompt Templates](#prompt-templates)
- [Skills](#skills)
- [Extensions](#extensions)
- [Pi Packages](#pi-packages)
- [CLI Reference](#cli-reference)
- [Tools](#tools)
- [Programmatic Usage](#programmatic-usage)
- [SDK](#sdk)
- [RPC Mode](#rpc-mode)
- [HTML Export](#html-export)
- [Philosophy](#philosophy)
- [Development](#development)
- [License](#license)
---
## Getting Started
### Installation
```bash
npm install -g @mariozechner/pi-coding-agent
pi
```
### Windows Setup
Pi requires a bash shell on Windows. Checked locations (in order):
1. Custom path from `~/.pi/agent/settings.json`
2. Git Bash (`C:\Program Files\Git\bin\bash.exe`)
3. `bash.exe` on PATH (Cygwin, MSYS2, WSL)
For most users, [Git for Windows](https://git-scm.com/download/win) is sufficient.
**Custom shell path:**
```json
// ~/.pi/agent/settings.json
{
"shellPath": "C:\\cygwin64\\bin\\bash.exe"
}
```
### Shell Aliases
Pi runs bash in non-interactive mode (`bash -c`), which doesn't expand aliases by default. To enable your shell aliases:
```json
// ~/.pi/agent/settings.json
{
"shellCommandPrefix": "shopt -s expand_aliases\neval \"$(grep '^alias ' ~/.zshrc)\""
}
```
Adjust the path (`~/.zshrc`, `~/.bashrc`, etc.) to match your shell config.
### Terminal Setup
Pi uses the [Kitty keyboard protocol](https://sw.kovidgoyal.net/kitty/keyboard-protocol/) for reliable modifier key detection. Kitty and iTerm2 work out of the box. Other terminals may need configuration. See [docs/terminal-setup.md](docs/terminal-setup.md).
### Authentication
**Subscriptions:** Use `/login` to authenticate with Claude Pro/Max, ChatGPT Plus/Pro, GitHub Copilot, or Google Gemini (free).
**API keys:** Set via environment variable:
```bash
export ANTHROPIC_API_KEY=sk-ant-...
pi
```
Supported: `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, `GEMINI_API_KEY`, `MISTRAL_API_KEY`, `GROQ_API_KEY`, `CEREBRAS_API_KEY`, `XAI_API_KEY`, `OPENROUTER_API_KEY`, `AWS_PROFILE`, and [more](docs/providers.md).
See [docs/providers.md](docs/providers.md) for auth file format, Azure, Bedrock, and Vertex setup.
### Quick Start
```bash
export ANTHROPIC_API_KEY=sk-ant-...
pi
```
Then chat:
```
You: Create a simple Express server in src/server.ts
```
The agent reads, writes, and edits files, and executes commands via bash.
---
## Usage
### Slash Commands
| Command | Description |
|---------|-------------|
| `/settings` | Open settings menu (thinking, theme, message delivery modes, toggles) |
| `/model` | Switch models mid-session. Use `/model ` or `provider/model` to prefilter/disambiguate. |
| `/scoped-models` | Enable/disable models for Ctrl+P cycling |
| `/export [file]` | Export session to self-contained HTML |
| `/share` | Upload session as secret GitHub gist, get shareable URL (requires `gh` CLI) |
| `/session` | Show session info: path, message counts, token usage, cost |
| `/name ` | Set session display name (shown in session selector) |
| `/hotkeys` | Show all keyboard shortcuts |
| `/changelog` | Display full version history |
| `/tree` | Navigate session tree in-place (search, filter, label entries) |
| `/fork` | Create new conversation fork from a previous message |
| `/resume` | Switch to a different session (interactive selector) |
| `/login` | OAuth login for subscription-based models |
| `/logout` | Clear OAuth tokens |
| `/new` | Start a new session |
| `/copy` | Copy last agent message to clipboard |
| `/compact [instructions]` | Manually compact conversation context |
| `/reload` | Reload extensions, skills, prompts, and themes |
### Editor Features
**File reference (`@`):** Type `@` to fuzzy-search project files. Respects `.gitignore`.
**Path completion (Tab):** Complete relative paths, `../`, `~/`, etc.
**Drag & drop:** Drag files from your file manager into the terminal.
**Multi-line paste:** Pasted content is collapsed to `[paste #N lines]` but sent in full.
**Message queuing:** Submit messages while the agent is working:
- **Enter** queues a *steering* message, delivered after current tool execution (interrupts remaining tools)
- **Alt+Enter** queues a *follow-up* message, delivered only after the agent finishes all work
Both modes are configurable via `/settings`: "one-at-a-time" delivers messages one by one waiting for responses, "all" delivers all queued messages at once. Press Escape to abort and restore queued messages to editor.
### Keyboard Shortcuts
**Navigation:**
| Key | Action |
|-----|--------|
| Arrow keys | Move cursor / browse history (Up when empty) |
| Alt+Left/Right | Move by word |
| Ctrl+A / Home / Cmd+Left | Start of line |
| Ctrl+E / End / Cmd+Right | End of line |
| PageUp / PageDown | Scroll by page |
**Editing:**
| Key | Action |
|-----|--------|
| Enter | Send message |
| Shift+Enter | New line (Ctrl+Enter on Windows Terminal) |
| Ctrl+W / Alt+Backspace | Delete word backwards |
| Alt+D / Alt+Delete | Delete word forwards |
| Ctrl+U | Delete to start of line |
| Ctrl+K | Delete to end of line |
| Ctrl+Y | Paste most recently deleted text |
| Alt+Y | Cycle through deleted text after pasting |
| Ctrl+- | Undo |
**Other:**
| Key | Action |
|-----|--------|
| Tab | Path completion / accept autocomplete |
| Escape | Cancel autocomplete / abort streaming |
| Ctrl+C | Clear editor (first) / exit (second) |
| Ctrl+D | Exit (when editor is empty) |
| Ctrl+Z | Suspend to background (use `fg` in shell to resume) |
| Shift+Tab | Cycle thinking level |
| Ctrl+P / Shift+Ctrl+P | Cycle models forward/backward (scoped by `--models`) |
| Ctrl+L | Open model selector |
| Ctrl+O | Toggle tool output expansion |
| Ctrl+T | Toggle thinking block visibility |
| Ctrl+G | Edit message in external editor (`$VISUAL` or `$EDITOR`) |
| Ctrl+V | Paste image from clipboard |
| Alt+Enter | Queue follow-up message |
| Alt+Up | Restore queued messages to editor |
### Custom Keybindings
All keyboard shortcuts can be customized via `~/.pi/agent/keybindings.json`. Each action can be bound to one or more keys.
**Key format:** `modifier+key` where modifiers are `ctrl`, `shift`, `alt` and keys are:
- Letters: `a-z`
- Numbers: `0-9`
- Special keys: `escape`, `tab`, `enter`, `space`, `backspace`, `delete`, `home`, `end`, `up`, `down`, `left`, `right`
- Symbol keys: `` ` ``, `-`, `=`, `[`, `]`, `\`, `;`, `'`, `,`, `.`, `/`, `!`, `@`, `#`, `$`, `%`, `^`, `&`, `*`, `(`, `)`, `_`, `+`, `|`, `~`, `{`, `}`, `:`, `<`, `>`, `?`
**Configurable actions:**
| Action | Default | Description |
|--------|---------|-------------|
| `cursorUp` | `up` | Move cursor up |
| `cursorDown` | `down` | Move cursor down |
| `cursorLeft` | `left` | Move cursor left |
| `cursorRight` | `right` | Move cursor right |
| `cursorWordLeft` | `alt+left`, `ctrl+left` | Move cursor word left |
| `cursorWordRight` | `alt+right`, `ctrl+right` | Move cursor word right |
| `cursorLineStart` | `home`, `ctrl+a` | Move to line start |
| `cursorLineEnd` | `end`, `ctrl+e` | Move to line end |
| `pageUp` | `pageUp` | Scroll up by page |
| `pageDown` | `pageDown` | Scroll down by page |
| `deleteCharBackward` | `backspace` | Delete char backward |
| `deleteCharForward` | `delete` | Delete char forward |
| `deleteWordBackward` | `ctrl+w`, `alt+backspace` | Delete word backward |
| `deleteWordForward` | `alt+d`, `alt+delete` | Delete word forward |
| `deleteToLineStart` | `ctrl+u` | Delete to line start |
| `deleteToLineEnd` | `ctrl+k` | Delete to line end |
| `yank` | `ctrl+y` | Paste most recently deleted text |
| `yankPop` | `alt+y` | Cycle through deleted text after pasting |
| `undo` | `ctrl+-` | Undo last edit |
| `newLine` | `shift+enter` | Insert new line |
| `submit` | `enter` | Submit input |
| `tab` | `tab` | Tab/autocomplete |
| `interrupt` | `escape` | Interrupt operation |
| `clear` | `ctrl+c` | Clear editor |
| `exit` | `ctrl+d` | Exit (when empty) |
| `suspend` | `ctrl+z` | Suspend process |
| `cycleThinkingLevel` | `shift+tab` | Cycle thinking level |
| `cycleModelForward` | `ctrl+p` | Next model |
| `cycleModelBackward` | `shift+ctrl+p` | Previous model |
| `selectModel` | `ctrl+l` | Open model selector |
| `expandTools` | `ctrl+o` | Expand tool output |
| `toggleThinking` | `ctrl+t` | Toggle thinking |
| `externalEditor` | `ctrl+g` | Open external editor |
| `followUp` | `alt+enter` | Queue follow-up message |
| `dequeue` | `alt+up` | Restore queued messages to editor |
| `selectUp` | `up` | Move selection up in lists (session picker, model selector) |
| `selectDown` | `down` | Move selection down in lists |
| `selectConfirm` | `enter` | Confirm selection |
| `selectCancel` | `escape`, `ctrl+c` | Cancel selection |
| `toggleSessionPath` | `ctrl+p` | Toggle path display in session picker |
| `toggleSessionSort` | `ctrl+s` | Toggle sort mode in session picker |
| `renameSession` | `ctrl+r` | Rename selected session |
| `deleteSession` | `ctrl+d` | Delete selected session |
| `deleteSessionNoninvasive` | `ctrl+backspace` | Delete session (when query empty) |
**Example (Emacs-style):**
```json
{
"cursorUp": ["up", "ctrl+p"],
"cursorDown": ["down", "ctrl+n"],
"cursorLeft": ["left", "ctrl+b"],
"cursorRight": ["right", "ctrl+f"],
"cursorWordLeft": ["alt+left", "alt+b"],
"cursorWordRight": ["alt+right", "alt+f"],
"deleteCharForward": ["delete", "ctrl+d"],
"deleteCharBackward": ["backspace", "ctrl+h"],
"newLine": ["shift+enter", "ctrl+j"]
}
```
**Example (Vim-style):**
```json
{
"cursorUp": ["up", "alt+k"],
"cursorDown": ["down", "alt+j"],
"cursorLeft": ["left", "alt+h"],
"cursorRight": ["right", "alt+l"],
"cursorWordLeft": ["alt+left", "alt+b"],
"cursorWordRight": ["alt+right", "alt+w"],
"deleteCharBackward": ["backspace", "ctrl+h"],
"deleteWordBackward": ["ctrl+w", "alt+backspace"]
}
```
**Example (symbol keys):**
```json
{
"submit": ["enter", "ctrl+j"],
"newLine": ["shift+enter", "ctrl+;"],
"toggleThinking": "ctrl+/",
"cycleModelForward": "ctrl+.",
"cycleModelBackward": "ctrl+,",
"interrupt": ["escape", "ctrl+`"]
}
```
> **Note:** Some `ctrl+symbol` combinations overlap with ASCII control characters due to terminal legacy behavior (e.g., `ctrl+[` is the same as Escape, `ctrl+M` is the same as Enter). These can still be used with `ctrl+shift+key` (e.g., `ctrl+shift+]`). See [Kitty keyboard protocol: legacy ctrl mapping of ASCII keys](https://sw.kovidgoyal.net/kitty/keyboard-protocol/#legacy-ctrl-mapping-of-ascii-keys) for all unsupported keys.
### Bash Mode
Prefix commands with `!` to execute them and add output to context:
```
!ls -la
!git status
!cat package.json | jq '.dependencies'
```
Output streams in real-time. Press Escape to cancel. Large outputs truncate at 2000 lines / 50KB.
The output becomes part of your next prompt, formatted as:
```
Ran `ls -la`