# pi-config

> Supercharge your pi coding agent with specialist agents, automated code review, persistent memory, and multi-agent workflows

---

Source: quickstart.md

# Installing and Starting Your First Session

Get pi-config installed and launch your first orchestrator session so you can start delegating tasks to specialist agents. You can install via a pre-built Docker container (recommended for isolation and consistency) or natively on your machine.

## Prerequisites

- **Node.js 22+** — required for pi itself ([nodejs.org](https://nodejs.org))
- **Git** — version control ([git-scm.com](https://git-scm.com))
- **A GitHub account** with a personal access token — needed for PR and issue workflows
- **An LLM provider** — pi needs a model to run (e.g., Claude via Vertex AI, or another supported provider)

## Quick Start (Docker)

```bash
docker pull ghcr.io/myk-org/pi-config:latest

docker run --rm -it \
  --name "pi-session" \
  --network host \
  -v "$PWD":"$PWD":rw \
  -v "$HOME/.pi":"$HOME/.pi":rw \
  -v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
  -v "$HOME/.ssh":"$HOME/.ssh":ro \
  -v "$HOME/.config/gh":"$HOME/.config/gh":ro \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

That's it — pi starts automatically with the orchestrator, all 24 specialist agents, and every tool pre-installed. Navigate to a project directory first, then run the command.

## Quick Start (Native)

```bash
npm install -g @earendil-works/pi-coding-agent
curl -LsSf https://astral.sh/uv/install.sh | sh
uv run https://raw.githubusercontent.com/myk-org/pi-config/main/scripts/install.py
```

After the installer finishes, start a session:

```bash
pi
```

## Step-by-Step: Docker Installation

### 1. Pull the image

```bash
docker pull ghcr.io/myk-org/pi-config:latest
```

The image includes everything pre-installed: `gh`, `uv`, `go`, `kubectl`, `bun`, Playwright + Chromium, CodeRabbit CLI, Cursor CLI, Claude Code, and more.

### 2. Create an environment file

Create a file at `~/.pi/.env` with your credentials and settings:

```env
# Timezone (match your host for correct timestamps)
TZ=America/New_York

# Host username (maps container paths to match your host home directory)
PI_HOST_USER=yourusername

# GitHub token (required for PR/issue workflows)
GITHUB_TOKEN=ghp_xxx
GH_CONFIG_DIR=/home/yourusername/.config/gh

# Google Cloud / Vertex AI (if using Claude via Vertex)
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-east5
GOOGLE_APPLICATION_CREDENTIALS=/home/yourusername/.config/gcloud/application_default_credentials.json
```

> **Note:** Replace `yourusername` with your actual system username. The `PI_HOST_USER` variable creates a symlink inside the container so that host-mounted paths resolve correctly.

### 3. Run pi in a container

Navigate to your project directory and start a session:

```bash
docker run --rm -it \
  --name "pi-config-$(basename $PWD)-$(date +%s)" \
  --network host \
  --env-file "$HOME/.pi/.env" \
  -v "$PWD":"$PWD":rw \
  -v "$HOME/.pi":"$HOME/.pi":rw \
  -v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
  -v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
  -v "$HOME/.ssh":"$HOME/.ssh":ro \
  -v "$HOME/.config/gh":"$HOME/.config/gh":ro \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

On each start, the container automatically installs the latest version of pi and updates all packages.

> **Tip:** A startup `WARNING` about already-cached packages is normal and can be ignored.

### 4. Create a shell alias

Add this to your `~/.bashrc` or `~/.zshrc` so you can launch pi with a single command:

```bash
alias pi-docker='docker pull ghcr.io/myk-org/pi-config:latest && \
  docker run --rm -it \
  --name "pi-config-$(basename $PWD)-$(date +%s)" \
  --network host \
  --env-file "$HOME/.pi/.env" \
  -v "$PWD":"$PWD":rw \
  -v "$HOME/.pi":"$HOME/.pi":rw \
  -v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
  -v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
  -v "$HOME/.ssh":"$HOME/.ssh":ro \
  -v "$HOME/.config/gh":"$HOME/.config/gh":ro \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest'
```

Then from any project directory:

```bash
pi-docker
```

## Step-by-Step: Native Installation

### 1. Install prerequisites

Install pi, uv, and the GitHub CLI:

```bash
# Pi coding agent
npm install -g @earendil-works/pi-coding-agent

# uv (Python package manager — enforced by pi-config instead of pip)
curl -LsSf https://astral.sh/uv/install.sh | sh

# GitHub CLI (for PR and issue workflows)
# macOS:
brew install gh
# Debian/Ubuntu:
# See https://cli.github.com/ for installation instructions
```

### 2. Run the interactive installer

The installer walks you through each component with multi-select checkboxes:

```bash
uv run https://raw.githubusercontent.com/myk-org/pi-config/main/scripts/install.py
```

It installs in 5 steps:

1. **Pi Packages** — pi-config, pi-vertex-claude, pi-web-access, pi-tasks, myk-pi-tools, bun
2. **Python Tools** — mcp-launchpad (mcpl), prek
3. **npm Packages** — acpx, agent-browser
4. **Browser Automation** — Playwright + Chromium
5. **Environment Setup** — adds `.pi/` and `.worktrees/` to your global gitignore

Deselect anything you don't need. The installer shows which items are already installed.

### 3. Authenticate GitHub CLI

```bash
gh auth login
```

Follow the prompts to authenticate. This enables PR creation, issue management, and release workflows.

### 4. Start a session

Navigate to a project directory and launch pi:

```bash
cd ~/my-project
pi
```

The orchestrator loads automatically and validates your environment. You'll see notifications about any missing optional tools.

## Verifying Your Installation

When pi starts, it runs environment checks and notifies you about missing tools. A healthy session shows:

- **No critical warnings** — `uv` is detected
- **Git status** in the status line — shows your current branch and working tree status
- **Container indicator** (Docker only) — a container icon confirms you're running inside the sandbox

Try a simple delegation to confirm the orchestrator is working:

```text
What files are in this project?
```

The orchestrator should route this to a specialist agent (typically `worker`) that reads and reports the directory contents.

## What the Container Protects

When running via Docker, pi-config enforces filesystem isolation:

| Access | Scope |
|--------|-------|
| ✅ Read/write | Your mounted project directory |
| ✅ Read/write | `~/.pi` (sessions, memory, settings) |
| ✅ Read-only | Git, SSH, and GitHub CLI config |
| ❌ Blocked | Everything else on your host |

> **Warning:** The `--network host` flag shares your host network stack. This is required for local MCP servers, the web dashboard, and file preview. If you only use cloud-based LLM providers and don't need these features, you can omit it.

## Updating

### Docker

```bash
docker pull ghcr.io/myk-org/pi-config:latest
```

The container runs `pi update` automatically on each start, so packages stay current.

### Native

```bash
pi update
uv tool upgrade myk-pi-tools
```

After updating, run `/reload` inside an active session or restart pi to pick up changes. Pi-config shows a changelog notification on the first session after an upgrade.

## Advanced Usage

### Non-Interactive Installation (CI)

Skip all prompts and install everything:

```bash
uv run https://raw.githubusercontent.com/myk-org/pi-config/main/scripts/install.py --all
```

### Building the Docker Image from Source

> **Note:** The image is built for **linux/amd64** only. On ARM hosts, build with `--platform linux/amd64`.

```bash
git clone https://github.com/myk-org/pi-config.git
cd pi-config
docker build -t ghcr.io/myk-org/pi-config:latest .
```

### Additional Docker Volume Mounts

These optional mounts unlock extra capabilities:

| Mount | Purpose |
|-------|---------|
| `-v "$HOME/.config/gcloud/application_default_credentials.json":"$HOME/.config/gcloud/application_default_credentials.json":ro` | Google Cloud credentials (Claude via Vertex AI) |
| `-v "$HOME/.config/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json":ro` | MCP server configuration |
| `-v "$HOME/.agents":"$HOME/.agents":rw` | User-level skills |
| `-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro` | Cursor CLI auth (for ACPX models) |
| `-v "$HOME/.config/glab-cli":"$HOME/.config/glab-cli":ro` | GitLab CLI config |
| `-v "$HOME/.coderabbit":"$HOME/.coderabbit":rw` | CodeRabbit CLI auth and data |
| `-v "$HOME/screenshots":"$HOME/screenshots":ro` | Share images with the agent |
| `-v /var/run/docker.sock:/var/run/docker.sock:ro` | Docker container inspection |

When mounting the Docker socket, also add `--group-add $(stat -c '%g' /var/run/docker.sock)` for proper permissions.

### Environment Variables for Additional Features

Add these to your `.env` file as needed:

| Variable | Purpose |
|----------|---------|
| `GEMINI_API_KEY` | Gemini API access (image generation, external AI) |
| `PI_IMAGE_MODEL` | Gemini model for image generation (e.g., `gemini-3-pro-image`) |
| `ACPX_AGENTS` | Comma-separated list of ACPX agents to register as providers (e.g., `cursor`) |
| `MCPL_CONFIG_FILES` | Path to MCP Launchpad config inside the container |
| `VERTEX_PROJECT_ID` | Google Cloud project for Vertex AI |
| `VERTEX_REGION` | Google Cloud region for Vertex AI |
| `PI_PIDASH_PORT` | Custom port for the web dashboard (default: `19190`) |
| `PI_PIDIFF_PORT` | Custom port for the diff viewer (default: `19290`) |

See [Configuration and Environment Variables Reference](configuration-reference.html) for the complete list.

### Project-Level Settings

Create `.pi/pi-config-settings.json` in any project to override global defaults:

```json
{
  "co_author": true,
  "use_worktrees": false,
  "dream_interval_hours": 3
}
```

See [Customization and Extension Recipes](customization-recipes.html) for details on project settings and custom agents.

## Troubleshooting

**"Cannot find pi" after native install**
Make sure `~/.npm-global/bin` (or your npm prefix) is in your `PATH`. Run `npm config get prefix` to check.

**Container exits immediately**
Ensure you're running with `-it` (interactive + TTY). Without these flags, the container has no terminal to attach to.

**"uv: command not found" warning on session start**
Install uv: `curl -LsSf https://astral.sh/uv/install.sh | sh`. Pi-config enforces `uv` instead of `pip` for all Python operations.

**GitHub CLI not authenticated**
Run `gh auth login` on the host (native) or ensure `~/.config/gh` is mounted (Docker). Without it, PR and issue workflows won't work.

**Host file paths don't resolve inside the container**
Set `PI_HOST_USER=yourusername` in your `.env` file. This creates a symlink from `/home/yourusername` inside the container to the container's home directory, so mounted paths match.

**Startup is slow**
The container runs `npm install -g` and `pi update` on every start to stay current. This takes a few seconds with a warm cache. Subsequent starts in the same network environment are faster.

## Related Pages

- [Your First Coding Workflow](first-workflow.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)

---

Source: first-workflow.md

# Your First Coding Workflow

You want to go from a feature idea to a merged pull request using pi's orchestrator. This guide walks you through the full cycle — asking pi to implement a change, watching it delegate to specialist agents, iterating through code review, and creating a PR.

## Prerequisites

- A running pi session in a Git repository (see [Installing and Starting Your First Session](quickstart.html))
- GitHub CLI (`gh`) authenticated — pi uses it for issues and PRs
- A remote `origin` configured for your repository

## Quick Example

Type a request in plain language. Pi handles the rest:

```
Add a --verbose flag to the export command that prints each file as it's processed
```

Pi will:

1. Investigate the codebase to understand the current export command
2. Create a GitHub issue describing the feature
3. Create a feature branch (`feat/issue-12-verbose-flag`)
4. Delegate code changes to the right specialist agent (e.g., `python-expert`)
5. Run three parallel code reviewers
6. Fix any findings and re-review until all pass
7. Run tests
8. Commit, push, and open a PR

You stay in control at each checkpoint — pi asks before proceeding.

## Step-by-Step Walkthrough

### Step 1: Describe What You Want

Just tell pi what you need. Be specific about the behavior you want, not how to implement it:

```
The /stats endpoint should return results sorted by date descending instead of ascending
```

Pi reads the relevant source code first to understand the current behavior before doing anything else.

### Step 2: Issue Creation and Branch Setup

Pi creates a GitHub issue with a root cause analysis, requirements, and a checklist of deliverables. It then asks for confirmation:

```
Issue #24 created: fix: /stats endpoint returns results in ascending order

URL: https://github.com/yourorg/yourrepo/issues/24

Do you want to work on it now?
```

Answer **yes** and pi fetches `main`, creates an issue branch (`fix/issue-24-stats-sort-order`), and starts working.

> **Tip:** If you want to skip the issue-first workflow for a trivial change, say "just do it" or "quick fix" — pi will go straight to implementation.

### Step 3: Watch the Orchestrator Delegate

The orchestrator never writes code directly. It routes work to specialist agents based on what the task involves:

| What's happening | Agent pi delegates to |
|---|---|
| Editing Python files | `python-expert` |
| Editing TypeScript/React files | `ts-expert` |
| Editing Go files | `go-expert` |
| Editing shell scripts | `bash-expert` |
| Git operations (branch, commit) | `git-expert` |
| GitHub operations (PR, issue) | `github-expert` |
| Writing or updating tests | `test-automator` |
| Exploring a codebase for context | `scout` |
| No specialist matches | `worker` |

Pi picks the right agent automatically — you don't need to specify. See [Understanding Agent Routing and Delegation](agent-routing.html) for the full routing table.

### Step 4: Code Review Loop

After the code changes are made, pi sends the diff to **three review agents in parallel**:

| Reviewer | Focus |
|---|---|
| `code-reviewer-quality` | Readability, abstractions, DRY, error handling |
| `code-reviewer-guidelines` | Project conventions (AGENTS.md compliance), documentation updates |
| `code-reviewer-security` | Bugs, logic errors, security vulnerabilities, edge cases |

These reviewers run as background agents — pi doesn't block while waiting. When all three return, pi merges and deduplicates their findings, then categorizes them by severity:

- **Critical** — must fix before proceeding
- **Warning** — should fix
- **Suggestion** — nice to have

If there are findings, pi sends them to the appropriate specialist to fix, then re-runs all three reviewers on the updated code. This loop repeats until all reviewers approve.

> **Note:** You don't need to trigger reviews manually during implementation — they run automatically after every code change. See [Running the Automated Code Review Loop](code-review-loop.html) for details on the review system.

### Step 5: Tests

Once all reviewers approve, pi delegates to the `test-automator` to run the project's test suite. Only **new** test failures block the workflow — pre-existing failures are noted but don't stop progress.

If tests fail:

- **Minor fix** (test config, import path): pi fixes and re-runs tests
- **Code change needed**: pi fixes the code and goes back through the full review loop

### Step 6: Commit, Push, and PR

When reviews pass and tests are green, pi:

1. Delegates to `git-expert` to stage specific files and commit with a clear message
2. Pushes the branch to origin
3. Delegates to `github-expert` to create a pull request with a description linking back to the issue

Pi checks off deliverables on the GitHub issue as they're completed, and closes the issue when everything is done.

## Using the /implement Shortcut

For a streamlined experience, use the `/implement` command. It chains three agents together automatically — scout, planner, then worker:

```
/implement Add a --verbose flag to the export command
```

This runs:

1. **Scout** — rapidly explores your codebase to find the relevant files, functions, and dependencies
2. **Planner** — creates a detailed implementation plan with files to change, edge cases, and testing approach
3. **Worker** — executes the plan, making all the code changes

The code review loop runs automatically after the worker finishes.

> **Tip:** Want a plan without implementation? Use `/scout-and-plan` instead — it runs only the scout and planner steps so you can review the approach before committing to it.

## Using /review-local to Review Before Committing

You can trigger a review at any time on your uncommitted changes:

```
/review-local
```

Or compare against a specific branch:

```
/review-local main
```

This spawns the same three parallel reviewers and presents findings grouped by severity, without modifying any code. See [Using Slash Commands and Prompt Templates](slash-commands.html) for all available commands.

## Task Tracking During the Workflow

For multi-step workflows, pi creates a visible task list and tracks progress through each step. If you ask a side question mid-workflow, pi answers it and then **resumes from exactly where it left off** — the task list ensures nothing gets forgotten.

You can check the current session state at any time:

```
/status
```

## Advanced Usage

### Reviewing an Existing Pull Request

Use `/pr-review` to review a PR that's already on GitHub:

```
/pr-review 42
/pr-review https://github.com/owner/repo/pull/42
```

Pi clones the PR branch, runs the three reviewers against the full repo context, lets you select which findings to post, and submits them as inline review comments on the PR. See [Common Workflow Recipes](workflow-recipes.html) for more review patterns.

### Skipping the Issue-First Workflow

The issue-first workflow is skipped automatically for:

- Typos and single-line fixes
- Questions or explorations (no code changes)
- Urgent hotfixes when you indicate time pressure
- When you say "just do it" or "quick fix"

### Multiple PRs in Parallel

When working on more than one PR or branch at the same time, pi uses `git worktree` to keep each branch isolated:

```bash
# Pi creates separate worktrees automatically
.worktrees/pr-42/   # One branch
.worktrees/pr-43/   # Another branch
```

This prevents branch switching from corrupting parallel agent work.

### Teaching Pi Your Preferences

Pi remembers your conventions across sessions. When you correct it or state a preference, it's saved automatically:

```
Always use conventional commits. Never put issue numbers in commit titles.
```

These preferences influence future sessions — including how code is written, reviewed, and committed. See [Working with Project Memory](memory-system.html) for more on the memory system.

## Troubleshooting

- **Pi tries to write code directly instead of delegating** — This shouldn't happen, but if it does, say "delegate this to the appropriate specialist agent."
- **Review loop seems stuck** — Reviewers run as background agents. Use `/async-status` to check their progress. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).
- **Pi skipped the issue/branch step** — It may have classified your request as trivial. Say "use the issue-first workflow" to force it.
- **Tests fail that were already failing** — Pi compares against a baseline. Only new failures caused by your changes block the workflow. Pre-existing failures are noted but don't stop progress.
- **Wrong specialist agent picked** — Pi routes by task intent, not file extension. If routing seems wrong, you can say "use the python-expert for this" to override.

## Related Pages

- [Installing and Starting Your First Session](quickstart.html)
- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Working with Project Memory](memory-system.html)

---

Source: agent-routing.md

## Prerequisites

- A working pi session with the orchestrator loaded (see [Installing and Starting Your First Session](quickstart.html))
- Familiarity with basic pi interactions (see [Your First Coding Workflow](first-workflow.html))

## Quick Example

Just tell pi what you need — the orchestrator routes it to the right agent automatically:

```
Fix the bug in src/auth/login.py where expired tokens aren't rejected
```

The orchestrator reads your request, identifies it involves Python code, and delegates to `python-expert`. You don't need to name the agent — routing happens based on the task's intent.

## How Routing Works

The orchestrator follows a routing table that maps task domains to specialist agents. When you make a request, it analyzes the **intent** of your task — not just the tools or file types involved — and picks the best agent.

### The Routing Table

| Domain | Agent | When It's Used |
|--------|-------|----------------|
| Python (.py) | `python-expert` | Writing, modifying, refactoring, or debugging Python code |
| Go (.go) | `go-expert` | Go development tasks |
| JS/TS/React/Vue/Angular | `ts-expert` | Frontend and TypeScript/JavaScript work |
| Java (.java) | `java-expert` | Java development tasks |
| Shell scripts (.sh) | `bash-expert` | Creating or editing shell scripts |
| Markdown (.md) | `technical-documentation-writer` | Writing documentation |
| Docker | `docker-expert` | Dockerfiles, container orchestration, image builds |
| Kubernetes/OpenShift | `kubernetes-expert` | Cluster configs, deployments, pods |
| Jenkins/CI/Groovy | `jenkins-expert` | CI pipeline configuration |
| Git (local) | `git-expert` | Commits, branching, rebasing, stash |
| GitHub (platform) | `github-expert` | PRs, issues, releases, workflows |
| Tests | `test-automator` | Creating test suites and CI pipelines |
| Debugging | `debugger` | Root cause analysis of errors and failures |
| API documentation | `api-documenter` | Generating API docs |
| External docs | `docs-fetcher` | Fetching library/framework documentation |
| Security audits | `security-auditor` | Auditing external code before adoption |
| No specialist match | `worker` | General-purpose fallback for anything else |

### Intent-Based Routing

The orchestrator routes by what you're **trying to accomplish**, not just the tools being used:

| Your Request | Routed To | Why |
|---|---|---|
| "Run the Python tests" | `python-expert` | The intent is testing Python code |
| "Edit `auth.py` using sed" | `python-expert` | The target is a Python file, regardless of the tool |
| "Create a PR for this branch" | `github-expert` | PR creation is a GitHub platform operation |
| "Commit these changes" | `git-expert` | Committing is a local git operation |
| "How do I use React hooks?" | `docs-fetcher` | Fetching external documentation |
| "Write a deploy script" | `bash-expert` | Creating a shell script |

> **Tip:** If the orchestrator ever routes to the wrong agent, just tell it: "Use python-expert for this" — it'll correct course immediately.

## Delegation Modes

The orchestrator can delegate work in three modes depending on your task's structure.

### Single Agent

One agent handles one task. This is the most common mode:

```
Refactor the database connection pool in src/db/pool.py
```

The orchestrator sends this to `python-expert`, waits for the result, and presents it to you.

### Parallel Agents

Multiple independent tasks run simultaneously:

```
Review these changes for quality, guidelines compliance, and security issues
```

The orchestrator spawns all three review agents (`code-reviewer-quality`, `code-reviewer-guidelines`, `code-reviewer-security`) at the same time and merges their findings. See [Running the Automated Code Review Loop](code-review-loop.html) for details.

### Chain Mode

Sequential agents where each step feeds into the next. The `/implement` slash command uses this pattern:

```
/implement Add rate limiting to the API endpoints
```

This runs a three-step chain:

1. **`scout`** — Explores the codebase to find relevant files and dependencies
2. **`planner`** — Creates a detailed implementation plan from the scout's findings
3. **`worker`** — Implements the plan, making all code changes

Each step receives the previous step's output via the `{previous}` placeholder. The `/scout-and-plan` command works the same way but stops after step 2 (no implementation).

## Sync vs Async Delegation

Agents run in one of two modes depending on how long the task takes and whether the orchestrator needs the result immediately.

### Sync Agents (Default)

The orchestrator waits for the result before continuing. Used when the next step depends on this agent's output. Sync agents must complete in under 30 seconds.

### Async Agents (Background)

The agent runs in the background while you keep working. Results surface automatically when complete. Use `/async-status` to check progress.

> **Note:** Three agents are **always** forced to run async, even if requested as sync: `code-reviewer-quality`, `code-reviewer-guidelines`, and `code-reviewer-security`. This prevents long code reviews from blocking your session.

See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for the full async workflow.

## Agent Discovery and Scope

Agents are loaded from three locations, with later sources overriding earlier ones by name:

| Priority | Source | Location |
|----------|--------|----------|
| 1 (base) | Package agents | Bundled with pi-config (24 built-in agents) |
| 2 | User agents | `~/.pi/agent/agents/` |
| 3 (highest) | Project agents | `.pi/agents/` in your project directory |

This means you can override any built-in agent by placing a file with the same `name` in your user or project agents directory.

### Agent Scope Control

When the orchestrator delegates, it can control which agent directories are searched:

| Scope | Package | User | Project |
|-------|---------|------|---------|
| `user` (default) | ✅ | ✅ | ❌ |
| `project` | ✅ | ❌ | ✅ |
| `both` | ✅ | ✅ | ✅ |

> **Note:** When project agents are used (`project` or `both` scope), pi prompts for confirmation before running them. This protects against unexpected code in project-local agent definitions.

## Advanced Usage

### Creating Project-Local Agents

You can define agents specific to your project by placing markdown files in `.pi/agents/`:

```markdown
---
name: my-api-agent
description: Handles API endpoint creation following our internal conventions.
tools: read, write, edit, bash
---

You are an API specialist for this project. Follow these conventions:

- Use FastAPI with Pydantic v2 models
- All endpoints go in src/api/routes/
- Every endpoint needs OpenAPI documentation
- Use dependency injection for database sessions
```

Each agent file needs YAML frontmatter with at least `name` and `description`. The optional `tools` field controls which tools the agent can use (comma-separated). You can also set `model` and `provider` to override the default LLM.

> **Tip:** Project agents are great for encoding project-specific conventions that don't apply globally. See [Customization and Extension Recipes](customization-recipes.html) for step-by-step instructions.

### Overriding a Built-In Agent

To customize a built-in agent's behavior for your project, create a file in `.pi/agents/` with the same `name` frontmatter value:

```markdown
---
name: python-expert
description: Python expert with project-specific conventions.
tools: read, write, edit, bash
---

You are a Python Expert. In addition to standard Python best practices:

- Always use SQLAlchemy 2.0 style (not legacy)
- Use pydantic-settings for all configuration
- Run `make lint` after every change
```

This project-level `python-expert` completely replaces the built-in one when working in this project.

### Overriding Routing with Model Pinning

Individual agents can be pinned to specific models using the `model` and `provider` fields in the frontmatter:

```markdown
---
name: scout
description: Fast codebase reconnaissance.
tools: read, bash
model: claude-haiku-4-5
---
```

The `scout` agent uses a faster, cheaper model by default because its job is quick reconnaissance, not deep analysis. You can apply this pattern to any agent — use a powerful model for complex tasks and a lightweight one for simple ones.

### The Fallback Agent

When no specialist matches your request, the orchestrator delegates to `worker` — a general-purpose agent with full capabilities (read, write, edit, bash). The worker handles any task that doesn't fit a specialist's domain.

If the worker identifies during execution that a task would be better handled by a specialist, it reports back and the orchestrator re-routes.

### Documentation Routing

When you ask about external libraries or frameworks, the orchestrator **must** delegate to `docs-fetcher` rather than fetching documentation directly. The `docs-fetcher` agent:

1. Checks for `llms.txt` first (documentation optimized for LLMs)
2. Falls back to web parsing if no `llms.txt` is available
3. Extracts only the relevant sections, saving tokens

```
How do I configure Oh My Posh themes?
```

This goes to `docs-fetcher`, which fetches the official docs efficiently. The orchestrator never uses `fetch_content` for external documentation directly.

**Skip `docs-fetcher` when:**

- You're working with standard library features only
- You explicitly say "skip docs" or "I know the API"
- The pattern is simple and obvious

### The Code Review Pipeline

After any code change, the orchestrator automatically triggers the review loop with three parallel async reviewers. This is a mandatory part of the workflow — you can't skip it.

The three reviewers have intentionally overlapping scopes to ensure nothing is missed:

| Reviewer | Focus |
|----------|-------|
| `code-reviewer-quality` | Clean code, abstractions, readability |
| `code-reviewer-guidelines` | Project conventions and AGENTS.md compliance |
| `code-reviewer-security` | Bugs, logic errors, security vulnerabilities |

Findings from all three are merged and deduplicated before being presented to you. See [Running the Automated Code Review Loop](code-review-loop.html) for the complete flow.

### The Scout → Plan → Implement Chain

For complex tasks, the `/implement` command chains three agents:

1. **`scout`** (pinned to `claude-haiku-4-5`) — Fast reconnaissance to map the relevant codebase
2. **`planner`** — Detailed implementation plan with files to change, steps, and edge cases
3. **`worker`** — Executes the plan, making all code changes

Use `/scout-and-plan` to get just the plan without implementation — useful when you want to review the approach before committing to it. See [Using Slash Commands and Prompt Templates](slash-commands.html) for all available commands.

## Troubleshooting

**The orchestrator picked the wrong agent**
Tell it directly: "Use `bash-expert` for this" or "Route this to `docker-expert`". The orchestrator corrects immediately.

**A project agent isn't being picked up**
Check that your file is in `.pi/agents/`, has valid YAML frontmatter with `name` and `description`, and ends in `.md`. The orchestrator searches upward from your working directory, so the `.pi/agents/` directory must be at or above your current location.

**An agent seems to be using the wrong model**
Agents inherit the session's model unless they have a `model` field in their frontmatter. Check the agent definition to see if a model override is set. User-level agents (`~/.pi/agent/agents/`) override package agents, and project-level agents (`.pi/agents/`) override both.

**Sync agent call was rejected as too slow**
Sync agents must complete in under 30 seconds. If the orchestrator estimates a task will take longer, it either auto-promotes to async or rejects the call. This is by design — long tasks should run in the background so they don't block your session. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

## Related Pages

- [Specialist Agents Reference](agents-reference.html)
- [Your First Coding Workflow](first-workflow.html)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Customization and Extension Recipes](customization-recipes.html)

---

Source: code-review-loop.md

# Running the Automated Code Review Loop

Get your code changes reviewed by three parallel reviewers — quality, guidelines, and security — and iterate on findings until all reviewers approve and tests pass.

## Prerequisites

- A working pi session with the orchestrator (see [Installing and Starting Your First Session](quickstart.html))
- Code changes on a working branch (uncommitted or committed)
- Familiarity with basic agent delegation (see [Understanding Agent Routing and Delegation](agent-routing.html))

## Quick Example

Make a code change and ask pi to review it:

```text
I've updated the authentication module. Please review my changes.
```

The orchestrator automatically triggers the code review loop — it spawns all three reviewers in parallel, collects their findings, and presents a merged summary. If there are issues, fix them and the loop runs again.

For an even faster workflow, use the built-in slash command:

```text
/review-local
```

This reviews all uncommitted changes (staged + unstaged) against `HEAD`. To review changes compared to a specific branch:

```text
/review-local main
```

## How the Review Loop Works

The code review loop runs automatically after any code change. Here's the flow:

1. **Specialist writes or fixes code** — a language expert (e.g., `python-expert`, `ts-expert`) makes the changes
2. **Three reviewers run in parallel** — all launched simultaneously as background agents
3. **Findings are merged** — duplicates across reviewers are removed
4. **Findings require fixes?** — if yes, the code is fixed and reviewers run again (step 2)
5. **All reviewers approve** — the `test-automator` agent runs tests
6. **Tests pass?** — if yes, the loop is complete. If not, the code is fixed and either re-reviewed (for substantive changes) or re-tested (for test/config-only fixes)

> **Note:** You don't need to manage this loop manually. The orchestrator handles the full cycle — spawning reviewers, collecting results, requesting fixes, and re-running reviews. You only interact when asked to make a decision.

## The Three Reviewers

Each reviewer focuses on a different aspect of your code:

| Reviewer | Focus Area | Example Findings |
|----------|-----------|------------------|
| `code-reviewer-quality` | Code quality and maintainability | DRY violations, poor naming, missing error logging, dead code |
| `code-reviewer-guidelines` | Project guidelines compliance | AGENTS.md violations, missing documentation updates, import ordering |
| `code-reviewer-security` | Bugs, logic errors, and security | SQL injection, race conditions, null references, resource leaks |

The overlapping scope is intentional — multiple reviewers examining similar areas reduces the chance of missed issues.

### Finding Severity Levels

Reviewers categorize their findings into three severity levels:

- **`[CRITICAL]`** — Must fix before merging. Security vulnerabilities, data loss risks, logic errors.
- **`[WARNING]`** — Should fix. Quality issues, missing error handling, guideline violations.
- **`[SUGGESTION]`** — Nice to have. Style improvements, minor readability enhancements.

### How Findings Are Deduplicated

When reviewers flag the same issue, the orchestrator merges findings using these rules:

- **Same file/line range + same root cause** → kept as one finding (the most actionable version)
- **Conflicting suggestions** → priority order: security > correctness > performance > style
- **Different issue types on the same code** → both findings are kept

## Reviewing Uncommitted Changes

The `/review-local` command runs a full three-reviewer analysis on your local changes without creating a PR.

```text
/review-local
```

This reviews all uncommitted changes (staged + unstaged) against `HEAD`.

To compare against a specific branch:

```text
/review-local main
/review-local develop
```

The workflow creates a structured task plan:

1. Get the diff
2. Launch all three reviewers in parallel (async)
3. Merge and deduplicate findings
4. Present findings grouped by severity

> **Tip:** Use `/review-local` before pushing to catch issues early. It's faster than a full PR review since it works on local changes.

## Implementing with Automatic Review

To implement a feature and run the review loop in one step:

```text
/implement-and-review Add rate limiting to the API endpoints
```

This chains three stages:

1. A `worker` agent implements the task
2. All three reviewers run in parallel on the changes
3. A `worker` agent fixes all issues found by the reviewers

## Reviewing a GitHub PR

The `/pr-review` command runs the three-reviewer system against a GitHub PR and posts inline comments:

```text
/pr-review
/pr-review 123
/pr-review https://github.com/owner/repo/pull/123
```

The PR review workflow:

1. **Detects the PR** — from the current branch or from the argument you provide
2. **Clones the repo** — checks out the PR branch so reviewers have full repo access
3. **Checks past review comments** — fetches previous review threads to track unresolved issues
4. **Runs all three reviewers in parallel** — each reviewer examines the diff and full source
5. **Presents merged findings** — you choose which to post as inline PR comments
6. **Posts comments and stores them** — comments are tracked in a local database for future review cycles

> **Note:** Past review comments are categorized during the review. Unresolved threads appear as `[PREV-UNRESOLVED]`, while threads marked resolved but with incorrect fixes show as `[PREV-BAD-FIX]`. This prevents issues from slipping through across review cycles.

See [Using Slash Commands and Prompt Templates](slash-commands.html) for the full list of available commands.

## Understanding Async Reviewers

All three review agents are enforced to run asynchronously — they always run as background agents. This means:

- The orchestrator spawns all three reviewers in a single action
- Your session remains interactive while reviewers work
- Results surface automatically when each reviewer finishes
- You can continue other work while waiting

Check reviewer status at any time:

```text
/async-status
```

See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for more on async agents.

## Baseline Test Comparison

When the review loop runs tests (step 5), it compares test results against a baseline to avoid blocking on pre-existing failures:

- The orchestrator saves your changes, resets to a clean state, and runs tests to establish a baseline failure count
- Then it restores your changes and runs tests again
- **Only new failures** (current minus baseline) block the review
- Pre-existing failures are noted but don't prevent approval

This prevents the review loop from blocking on test failures that existed before your changes.

## Advanced Usage

### Handling Review Comments from External Reviewers

The `/review-handler` command processes review comments from multiple sources — human reviewers, CodeRabbit, and Qodo — on a GitHub PR:

```text
/review-handler
```

For each comment, you choose whether to address it, skip it, or address all at once. The agent then delegates fixes to the appropriate specialist.

To automatically fix comments from CodeRabbit or Qodo in a polling loop:

```text
/review-handler --autorabbit
/review-handler --autoqodo
/review-handler --autorabbit --autoqodo
```

In auto mode, the handler processes comments, pushes fixes, and polls for new comments until the reviewer approves the PR.

See [Common Workflow Recipes](workflow-recipes.html) for more patterns.

### Refining Your Own Review Comments

Before submitting a pending GitHub review, polish your comments with AI:

```text
/refine-review https://github.com/owner/repo/pull/123
```

This fetches your pending review comments, suggests refinements for clarity and actionability, and lets you accept, reject, or customize each suggestion before submitting.

### Staged Review Mode for Automated Workflows

When using automated review flows (`--autorabbit`, `--autoqodo`), the system uses a two-stage review order instead of launching all three reviewers in parallel:

- **Stage 1 — Spec Compliance:** Does the code meet requirements? Are all deliverables implemented? No scope creep?
- **Stage 2 — Code Quality:** Quality, security, and guidelines checks (the normal three reviewers)

Stage 1 must pass before Stage 2 begins. This avoids polishing code that doesn't meet the specification — saving time and review cycles.

### Multi-PR Review Handling

When handling reviews for multiple PRs simultaneously, the system uses git worktrees to isolate each PR:

```text
/review-handler
```

> **Warning:** Never switch branches manually when multiple review agents are running. The orchestrator uses worktrees automatically to prevent branch switching from corrupting parallel agent work.

### The Implement → Review → Fix Cycle

For a complete implementation workflow that includes scouting, planning, implementation, and review:

```text
/implement Add caching layer to the database queries
```

This chains three agents:

1. `scout` — explores the codebase to find relevant code
2. `planner` — creates a detailed implementation plan
3. `worker` — implements the plan

After implementation, the orchestrator automatically triggers the code review loop. Any findings lead to fixes and re-review until all three reviewers approve.

## Troubleshooting

**Reviewers seem stuck or unresponsive:**
Check `/async-status` to see if reviewers are still running. If a reviewer fails, the orchestrator reports the error and can retry.

**Too many false positives from reviewers:**
The overlapping reviewer scope is intentional, but if findings are consistently unhelpful, check that your project has an `AGENTS.md` or `CLAUDE.md` file. Reviewers read these files to understand project-specific conventions and reduce noise.

**Tests fail on pre-existing issues:**
The baseline comparison should handle this automatically. If baseline comparison is unavailable (e.g., `git apply` fails), the review notes "baseline comparison unavailable" and does not block on all failures.

**Review loop keeps cycling:**
The loop exits when all three reviewers approve AND tests pass. If fixes introduce new issues, the loop continues. For complex changes, consider breaking the work into smaller commits.

## Related Pages

- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Specialist Agents Reference](agents-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Common Workflow Recipes](workflow-recipes.html)

---

Source: slash-commands.md

# Using Slash Commands and Prompt Templates

Slash commands let you trigger multi-step workflows in a single line — from implementing features to creating GitHub releases. This guide shows you how to use every built-in command and how prompt templates work under the hood.

## Prerequisites

- A running pi session (see [Installing and Starting Your First Session](quickstart.html))
- `myk-pi-tools` installed (`uv tool install myk-pi-tools`) — required by most commands
- GitHub CLI (`gh`) authenticated — needed for PR and release commands

## Quick Example

Type a slash command directly in your pi session:

```
/implement add a retry mechanism to the HTTP client
```

Pi scouts the codebase, creates a plan, and implements the change — all in one step.

## Prompt Template Commands

Prompt templates are markdown files that define multi-step workflows. When you type a `/command`, pi loads the matching template and follows its instructions. Arguments you pass replace the `$ARGUMENTS` placeholder in the template.

### /implement — Scout, Plan, and Build

Chains three specialist agents in sequence: scout → planner → worker.

```
/implement <task description>
```

**Examples:**

```
/implement add pagination to the users API endpoint
/implement refactor the auth middleware to support JWT
```

The scout explores relevant code, the planner creates a step-by-step plan, and the worker implements it.

### /scout-and-plan — Explore Without Changing Code

Like `/implement` but stops after planning — no code changes are made.

```
/scout-and-plan <task description>
```

**Examples:**

```
/scout-and-plan migrate the database layer to async
/scout-and-plan what would it take to add WebSocket support
```

Use this when you want to understand the scope of a change before committing to it.

### /implement-and-review — Build With Automated Review

Implements a task, then runs all three code reviewers in parallel, and fixes any issues found.

```
/implement-and-review <task description>
```

The workflow:
1. Worker implements the task
2. Three reviewers run in parallel: quality, guidelines, and security
3. Worker fixes all review findings

### /pr-review — Review a GitHub PR

Reviews a GitHub PR using three parallel reviewers and posts inline comments.

```
/pr-review                       # Review PR from current branch
/pr-review 123                   # Review PR #123
/pr-review https://github.com/owner/repo/pull/123
```

**Workflow:**
1. Clones the PR's repo and checks out the PR branch (reviewers get full repo access)
2. Checks past review comments — verifies whether previously posted comments were addressed, resolved correctly, or still unresolved
3. Runs three reviewers in parallel (quality, guidelines, security) — each reviewer reads project guidelines (AGENTS.md/CLAUDE.md) independently
4. Merges and deduplicates findings from all reviewers and past comment analysis
5. Presents findings grouped by severity (CRITICAL → WARNING → SUGGESTION), including past unresolved and incorrectly resolved comments
6. Lets you choose which findings to post as inline comments
7. Stores posted comments in a local database for tracking across review cycles

> **Tip:** Tab-completion is available — press Tab after `/pr-review` to see open PRs.

### /review-local — Review Uncommitted Changes

Reviews your local changes without touching GitHub.

```
/review-local                    # Review uncommitted changes (staged + unstaged)
/review-local main               # Review changes compared to main branch
/review-local feature/auth       # Review changes compared to a specific branch
```

All three reviewers run in parallel and findings are grouped by severity. No comments are posted anywhere — this is purely local feedback.

> **Tip:** Press Tab after `/review-local` to autocomplete branch names.

### /release — Create a GitHub Release

Creates a GitHub release with automatic changelog generation and optional version bumping.

```
/release                         # Auto-detect version bump from commits
/release 2.1.0                   # Release with explicit version (skips approval)
/release --dry-run               # Preview without creating
/release --prerelease            # Create a prerelease
/release --draft                 # Create a draft release
/release --target v2.10          # Target a specific branch
```

**Workflow:**
1. Validates the branch (must be default or target branch, clean, synced)
2. Detects version files (pyproject.toml, package.json, Cargo.toml, etc.)
3. Categorizes commits by conventional commit type and generates a changelog
4. Asks for approval (unless an explicit version was given)
5. Bumps version files, creates a PR, merges it
6. Creates the GitHub release with the changelog

> **Tip:** Tab-completion shows recent git tags and flags like `--dry-run`, `--prerelease`, `--draft`, and `--target`.

### /review-handler — Process All PR Review Comments

Fetches and processes review comments from all sources — human reviewers, Qodo, and CodeRabbit.

```
/review-handler                              # Process current PR's reviews
/review-handler --autorabbit                 # Auto-fix CodeRabbit comments in a loop
/review-handler --autoqodo                   # Auto-fix Qodo comments in a loop
/review-handler --autorabbit --autoqodo      # Auto-fix both in a loop
```

In manual mode, each review comment is presented with its severity and you decide which to address. In auto mode (`--autorabbit`/`--autoqodo`), the command enters a polling loop that automatically fixes comments, pushes changes, and waits for the reviewer to re-evaluate — fully unattended.

> **Note:** The `--autorabbit` and `--autoqodo` flags are command-level flags for pi, not CLI arguments. They control the behavior of the polling loop.

For multi-PR scenarios, the command uses `git worktree` to isolate each PR rather than switching branches, which prevents interference with other running agents.

### /external-ai — Run Prompts via External AI CLIs

Sends prompts to external AI agents (Cursor, Claude, Gemini) via ai-cli-runner.

```
/external-ai cursor review the error handling
/external-ai claude explain this function
/external-ai gemini --model gemini-2.5-pro analyze the architecture
/external-ai cursor --fix fix the failing tests
/external-ai cursor --peer review this code
/external-ai cursor,claude review this code          # Multi-agent
/external-ai cursor --resume explain the last change  # Continue session
```

**Modes:**

| Flag | Behavior |
|------|----------|
| *(none)* | Read-only — agent cannot modify files |
| `--fix` | Agent can modify, create, and delete files |
| `--peer` | AI-to-AI debate loop until both agents agree |
| `--resume` | Continue most recent session context |
| `--model <name>` | Override the default model |

In **peer mode**, pi orchestrates an iterative review loop: the external agent reviews, pi acts on findings (fixing or counter-arguing), sends results back, and repeats until convergence. With multiple agents (e.g., `cursor,claude`), each agent reviews independently and all must agree before the loop exits.

For a deeper dive, see [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html).

### /refine-review — Polish Pending PR Review Comments

Refines your pending GitHub PR review comments with AI before submitting.

```
/refine-review https://github.com/owner/repo/pull/123
```

Fetches your unsubmitted review comments, generates improved versions, and shows side-by-side comparisons. You pick which refinements to accept, optionally submit with "Request Changes," and the command updates comments on GitHub.

When the review is submitted, comments are automatically stored in the local PR review database — enabling future `/pr-review` runs to track which comments were posted and verify they were addressed.

### /query-db — Query the Reviews Database

Runs analytics queries against your local review history database.

```
/query-db stats --by-source
/query-db stats --by-reviewer
/query-db patterns --min 2
/query-db dismissed --owner myorg --repo myrepo
/query-db SELECT * FROM comments WHERE status='skipped' LIMIT 10
```

The database stores all processed review comments from `/review-handler`, enabling you to find recurring patterns, track addressed rates by source, and run custom SQL queries.

> **Note:** Only SELECT statements are allowed — the database is read-only for safety.

### /remember — Save a Memory

Saves a pinned memory for future sessions.

```
/remember always run tests with --verbose flag
/remember the auth service requires Redis to be running
/remember we decided to use UTC timestamps everywhere
```

Pi determines the best category (lesson, decision, mistake, pattern, preference, done) and persists it. See [Working with Project Memory](memory-system.html) for more on the memory system.

### /coderabbit-rate-limit — Handle CodeRabbit Rate Limits

Waits for a CodeRabbit rate limit to expire and re-triggers the review automatically.

```
/coderabbit-rate-limit             # Current branch's PR
/coderabbit-rate-limit 123         # Specific PR number
```

### /review-handler-status — Check Running Review Agents

Shows the live state of running autoqodo/autorabbit review-handler agents.

```
/review-handler-status
```

Looks for active `reviews poll` agents and generates an HTML status report.

### /create-skill — Save a Workflow as a Reusable Skill

Captures a successful workflow from the current conversation and saves it as a reusable skill.

```
/create-skill debug-container-build
/create-skill                       # Prompts for a name
```

You choose whether the skill is **global** (`~/.agents/skills/`) or **project-scoped** (`.pi/skills/`). See [Customization and Extension Recipes](customization-recipes.html) for more on creating custom skills.

### /create-coms-feature-manager — Generate a Coms Feature Manager

Creates a project-specific coms feature manager prompt for coordinating between a manager agent and a coder agent via inter-agent communication.

```
/create-coms-feature-manager
```

See [Communicating Between Pi Sessions](inter-agent-communication.html) for details on the coms system.

## Extension Commands

Extension commands are registered by the orchestrator extension and execute directly — no prompt template involved. They're faster because they don't need an AI roundtrip.

### /btw — Quick Side Questions

Ask a quick question without disrupting your conversation history.

```
/btw what was the name of the config file we edited earlier?
/btw what port is the dev server running on?
```

The answer appears in a scrollable overlay and disappears when you dismiss it (Esc, Space, or q). Your main conversation context is not affected.

### /status — Session Status Snapshot

Shows a unified view of your current session state.

```
/status
```

Output includes:
- **Async agents** — count and status of background agents
- **Cron tasks** — active scheduled tasks with last run times
- **Git state** — current branch, dirty file count
- **Container status** — whether you're running inside a container
- **Loaded resources** — context files, skills, tools, and guidelines

### /async-status — Background Agent Status

Shows the status of all running background agents.

```
/async-status
```

See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for managing async agents.

### /cron — Scheduled Tasks

Schedule recurring tasks that run on an interval or at specific times.

```
/cron add every 2h run the test suite
/cron add at 09:00 check for new issues
/cron list
/cron list-all
/cron remove 3
```

Tasks survive `/reload` and `/new` but stop when pi exits. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for details.

### /dream — Memory Consolidation

Trigger memory consolidation manually, or toggle automatic dreaming.

```
/dream                  # Run consolidation now
/dream-auto on          # Enable auto-dreaming (default: every 3h + session end)
/dream-auto off         # Disable auto-dreaming
```

See [Working with Project Memory](memory-system.html) for how dreaming fits into the memory lifecycle.

### /coms and /coms-net — Inter-Agent Communication

Manage P2P and networked communication between pi sessions.

```
/coms start             # Start P2P communication
/coms-net connect       # Connect to the network hub
```

See [Communicating Between Pi Sessions](inter-agent-communication.html) for the full guide.

### /pidash and /pidiff — Web Dashboard and Diff Viewer

Manage the web dashboard and diff viewer daemons.

```
/pidash start           # Launch the web dashboard
/pidiff start           # Launch the diff viewer
```

See [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html) for setup and usage.

### /external-ai-models-refresh — Refresh Model Cache

Clears the cached model lists for all AI CLI providers and re-fetches them.

```
/external-ai-models-refresh
```

Useful when new models become available and Tab-completion isn't showing them.

## Tab Completion

Most commands support Tab-completion for arguments. Press Tab after the command name to see available options:

| Command | Tab completes |
|---------|---------------|
| `/external-ai` | Provider names, flags (`--fix`, `--peer`, `--model`), model IDs |
| `/pr-review` | Open PR numbers with titles |
| `/review-local` | Git branch names |
| `/release` | Recent git tags, flags (`--dry-run`, `--prerelease`, `--draft`, `--target`, `--tag-match`) |
| `/review-handler` | `--autorabbit`, `--autoqodo` |
| `/coderabbit-rate-limit` | Open PR numbers |
| `/cron` | Subcommands (`add`, `list`, `remove`), task IDs for removal |
| `/dream-auto` | `on`, `off` |

Completions are cached for 5 minutes. Model lists for `/external-ai` are pre-fetched when the session starts.

## How Prompt Templates Work

Prompt templates are markdown files in the `prompts/` directory with YAML frontmatter. When you type a slash command, pi:

1. Loads the matching `.md` file
2. Substitutes `$ARGUMENTS` with whatever you typed after the command name
3. Follows the instructions in the template

The orchestrator **always maintains control** of the prompt workflow. It never delegates the entire command to a specialist agent — only sub-tasks get routed to agents as the template directs.

### Anatomy of a Prompt Template

Every prompt template has this structure:

```markdown
---
description: "Short description — /command-name <args>"
argument-hint: "<task>"
---

## Raw Arguments

‍```text
$ARGUMENTS
‍```

> **Bug Reporting Policy:** If you encounter ANY error...

# Command Title

Instructions for the orchestrator to follow...
```

| Field | Purpose |
|-------|---------|
| `description` | Shown in the command list and autocomplete |
| `argument-hint` | Placeholder text shown in the input bar |
| `$ARGUMENTS` | Replaced with user input at runtime |
| Bug Reporting Policy | Standard block ensuring issues are reported, not silently worked around |

### Project-Level Prompt Templates

You can create custom prompt templates in your project's `.pi/prompts/` directory. Any `.md` file with YAML frontmatter automatically registers as a slash command.

For example, creating `.pi/prompts/deploy-staging.md`:

```markdown
---
description: "Deploy to staging — /deploy-staging [version]"
argument-hint: "[version]"
---

## Raw Arguments

‍```text
$ARGUMENTS
‍```

# Deploy to Staging

1. Run `make build`
2. Run `make deploy-staging VERSION=$ARGUMENTS`
3. Verify health check at https://staging.example.com/health
```

After creating the file, run `/reload` to register the new command.

> **Tip:** Use `/create-skill` to capture successful workflows as reusable skills, or write prompt templates directly for more complex multi-step commands. See [Customization and Extension Recipes](customization-recipes.html) for guidance on both approaches.

## Advanced Usage

### Chaining Commands

You can use the output of one command as context for another:

```
/scout-and-plan add rate limiting to the API
```

Review the plan, then:

```
/implement add rate limiting to the API following the plan above
```

Or use `/implement-and-review` to combine implementation with automated review in a single step.

### Auto-Mode Review Workflows

For fully unattended review handling, combine `--autorabbit` and `--autoqodo`:

```
/review-handler --autorabbit --autoqodo
```

This enters a polling loop that:
1. Fetches new comments from CodeRabbit and Qodo
2. Automatically fixes each finding
3. Commits and pushes changes
4. Waits for reviewers to re-evaluate
5. Repeats until all reviewers approve

The loop runs in the background — you can continue working in the same session. It exits only when all automated reviewers approve or you explicitly stop it.

### Peer Review With Multiple Agents

Run a multi-agent peer review debate:

```
/external-ai cursor,claude --peer review the error handling in src/api/
```

Each agent reviews independently, pi synthesizes findings, fixes code, and sends results back. The loop continues until all agents agree — with full group context so each agent sees what the others said.

### Release With Version Branch Targeting

For projects using version branches:

```
/release --target v2.10 --tag-match "v2.10.*"
```

This targets the `v2.10` branch and filters tags to that version range. On a version branch, automatic detection works without flags:

```
git checkout v2.10
/release
```

## Troubleshooting

**"myk-pi-tools is required" error**
Most commands need the `myk-pi-tools` CLI. Install it:
```
uv tool install myk-pi-tools
```

**Tab completion not showing results**
Completions are cached for 5 minutes. Run `/external-ai-models-refresh` to force a refresh of model lists, or wait for the cache to expire for PR and branch lists.

**"Unknown provider" error with /external-ai**
Only `cursor`, `claude`, and `gemini` are supported. For other agents (Codex, Copilot, Droid, Kiro, etc.), use the ACPX provider instead.

**PR detection fails for /pr-review or /review-handler**
Ensure you're on a branch with an open PR and `gh` is authenticated:
```bash
gh auth status
gh pr view
```

For the full command reference with all arguments and options, see [Slash Commands and Extension Commands Reference](commands-reference.html).

## Related Pages

- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Common Workflow Recipes](workflow-recipes.html)
- [Your First Coding Workflow](first-workflow.html)
- [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html)
- [Customization and Extension Recipes](customization-recipes.html)

---

Source: memory-system.md

# Working with Project Memory

Teach pi your preferences, lessons learned, and project conventions so it remembers them across sessions. The memory system scores each entry by how often you reinforce it, automatically decays stale knowledge, and injects the most relevant memories into every conversation.

## Prerequisites

- A pi session running in an initialized project (a `.pi/` directory will be created automatically)
- No extra setup — memory works out of the box in every session

## Quick Example

Tell pi something worth remembering:

```
/remember Always run tests with --verbose flag in this project
```

Or just say it naturally in conversation — pi auto-detects preference statements like "I prefer," "always use," or "never":

```
I prefer short commit messages, one line max
```

Both approaches store the memory and recall it in future sessions automatically.

## How Memories Are Organized

Memories are stored in topic files under `.pi/memory/topics/`, one file per category:

| Category | File | What to store | Decay half-life |
|----------|------|---------------|-----------------|
| `preference` | `preferences.md` | How the user likes things done | 90 days |
| `lesson` | `lessons.md` | Gotchas, tips, how things work | 60 days |
| `pattern` | `patterns.md` | Recurring conventions or approaches | 30 days |
| `decision` | `decisions.md` | Architectural or design choices | 30 days |
| `done` | `completions.md` | Completed features, merged PRs | 14 days |
| `mistake` | `mistakes.md` | Things that went wrong, to avoid | 14 days |

Each entry is a single short line — specific, actionable, and max ~100 characters:

```markdown
# Lessons

- [lesson] buildah chown -R breaks cache mounts — use --mount=type=cache with correct uid instead
- [lesson] Always check PR merge status before closing issues
```

## Adding Memories

You have three ways to add memories, depending on the situation.

### 1. The `/remember` command

Use this for anything you explicitly want pi to keep. Memories added this way are **pinned** — they never decay and dreaming never removes them:

```
/remember This repo uses pnpm, not npm
/remember Deploy to staging before production — always
```

### 2. Natural conversation

Pi automatically detects preference statements in your messages. Phrases like "I prefer," "always use," "from now on," and "please never" trigger auto-extraction:

```
From now on, use single quotes in TypeScript files
I always want error messages in English
```

> **Tip:** Auto-extracted preferences are learned (not pinned), so they'll decay if never reinforced. Say `/remember` if you want them permanent.

### 3. The CLI

For scripting or manual management outside a pi session:

```bash
# Add a learned memory
uv run myk-pi-tools memory add -c lesson -s "Run migrations before deploying"

# Add a pinned memory (never auto-removed)
uv run myk-pi-tools memory add -c preference -s "Use uv, not pip" --pinned
```

## Viewing Your Memories

Inside a pi session, ask pi to list your memory topics:

```
What's in my project memory?
```

Pi will call `memory_topics` and show you each topic file with its entry count and activity level.

From the CLI:

```bash
uv run myk-pi-tools memory show
```

## How Memories Reach Pi Automatically

You don't need to manually search memory before every question — three auto-injection mechanisms handle this:

1. **Situation report** — A token-budgeted summary of your highest-scored memories is always included in pi's system prompt. Preferences and lessons get top priority.

2. **Contextual memory recall** — When you send a message, pi runs a vector similarity search against your memories. Entries with high relevance appear automatically as context.

3. **Session history recall** — Pi also searches past conversation summaries by keyword, surfacing relevant discussions from previous sessions.

4. **File-change reminders** — After pi modifies files, it checks if any memories relate to those files and surfaces them as reminders.

> **Note:** Trivial messages like "ok," "thanks," or emoji-only responses skip the search — no wasted computation.

## Searching Memory Manually

When you need to look something up from a past session or check what pi remembers about a topic, just ask:

```
What do you remember about our Docker setup?
Search memory for "deployment"
```

Pi will use `memory_search` (hybrid keyword + vector search) to find matching entries. You can also ask pi to search past conversations:

```
What did we discuss about the API refactor last week?
```

## Removing and Editing Memories

### Remove an outdated memory

```
Remove the memory about Python 3.11 from lessons
```

Or from the CLI:

```bash
uv run myk-pi-tools memory forget -c lesson -s "Project uses Python 3.11"
```

### Edit a memory in place

Ask pi to update a memory without losing its scoring history:

```
Update the lesson about Docker caching — change it to "Use buildkit cache mounts with --mount=type=cache"
```

Pi uses `memory_edit` to replace the text while preserving the evidence count and score.

### Invalidate a superseded memory

```
The decision about using REST is outdated — we switched to gRPC. Invalidate it.
```

## Pinned vs Learned Memories

| | Pinned | Learned |
|---|---|---|
| **Created by** | `/remember`, `--pinned` flag, or `memory_add` with `pinned: true` | Auto-extraction, dreaming, pi's proactive writes |
| **Decays?** | Never (score = 9999) | Yes — based on category half-life |
| **Removed by dreaming?** | Never | Yes — if stale or redundant |
| **When to use** | Critical preferences, permanent rules | Everything else |

> **Tip:** Don't over-pin. Let learned memories decay naturally — if something is important, it gets reinforced through use and stays alive on its own.

## Understanding Scores and Decay

Every learned memory has a stability score that decreases over time unless reinforced. The formula combines three factors:

- **Recency** — how recently the memory was last reinforced (exponential decay based on category half-life)
- **Evidence** — how many times the memory has been reinforced (logarithmic growth)
- **Cue weight** — how the memory was created (explicit user statements score highest)

Memories move through lifecycle states as their score changes:

| State | Meaning |
|---|---|
| **Active** | Included in the situation report, injected into prompts |
| **Provisional** | Overflow — included if budget allows |
| **Candidate** | Low score, at risk of being dropped |
| **Dropped** | Below threshold, no longer injected |

Pi automatically reinforces memories it notices are relevant to the current task. You can also reinforce manually:

```
That lesson about cache mounts was really helpful — reinforce it
```

## Memory Capacity

The situation report header shows your current usage:

```
# Project Memory [72% — 1,224/1,700 tokens]
```

- **Below 80%** — Add memories freely
- **Above 80%** — Pi warns you to consolidate before adding more

When you're running out of space, ask pi to consolidate:

```
Consolidate my memories
```

Pi will review all entries, merge duplicates, remove contradictions, and clean up stale information. You can also remove entries manually to free space.

> **Note:** Each topic file is capped at approximately 3,000 tokens. If a single category gets too large, you'll need to remove or consolidate entries before adding more.

## Advanced Usage

### Dreaming: Background Memory Consolidation

Dreaming is a background process that reviews your session history, extracts useful knowledge, and cleans up memory — all without blocking your session.

**Automatic dreaming** runs on two schedules:
- Every 3 hours (configurable) — a background agent reads past sessions and extracts durable knowledge
- On session shutdown — a lightweight pass captures anything from the ending session

**Manual dreaming:**

```
/dream
```

**Toggle automatic dreaming:**

```
/dream-auto off    # Disable auto-dreaming
/dream-auto on     # Re-enable it
```

The status bar shows a 🌙 icon — highlighted when a dream is actively running.

#### What dreaming does

1. Reads the current session and recent past sessions
2. Extracts lessons, corrections, completed work, and preferences
3. Deduplicates and cleans up existing topic files
4. Auto-generates reusable skills from recurring multi-step workflows
5. **Never** touches pinned entries

#### Configuring dream frequency

Set the interval in `.pi/pi-config-settings.json`:

```json
{
  "dream_interval_hours": 6
}
```

Or via environment variable:

```bash
export PI_DREAM_INTERVAL_HOURS=6
```

Valid range: 0.5 to 24 hours. Default: 3 hours.

> **Note:** A separate scoring rebuild runs every 30 minutes (no LLM cost — it just recalculates stability scores and reorganizes entries).

### Duplicate Detection with Vector Embeddings

When pi adds a memory, it checks for near-duplicates using vector similarity (threshold: 0.85). If you try to add "Always use pnpm" and "Use pnpm, not npm" already exists, pi reinforces the existing entry instead of creating a duplicate.

This runs locally using an in-process embedding model — no API keys, no network calls. The first search in a session may take a moment to initialize the model; subsequent searches are near-instant (~2.5ms).

Embeddings are stored in `.pi/memory/embeddings.json` and managed automatically.

### Memory Quality Guidelines

Write memories that are specific and actionable — not vague observations:

| ❌ Bad | ✅ Good |
|--------|---------|
| "We had issues with Docker caching" | "buildah chown -R breaks cache mounts — use --mount=type=cache with correct uid" |
| "The memory system was incomplete" | "Never close issues with unchecked deliverables in Done section" |
| "User prefers a certain approach" | "Attach child processes to pi (no detached:true) — kills on exit" |

Rules of thumb:
- One line, ~100 characters max
- Concrete "do X" or "don't do Y" — not background explanations
- No fluff, no context, just the fact

### Skill Creation from Memory Patterns

When dreaming detects a multi-step workflow that recurs across entries (3+ steps), it can auto-generate a **skill** — a reusable procedure saved as a file. You can also create skills manually:

```
/create-skill deploy-staging
```

This extracts the workflow from the current conversation and saves it for future sessions. See [Customization and Extension Recipes](customization-recipes.html) for details.

### Per-Category Budget Caps

The scoring system enforces per-category limits to keep memory balanced:

| Category | Max active entries |
|----------|-------------------|
| `preference` | 8 |
| `lesson` | 8 |
| `pattern` | 6 |
| `decision` | 4 |
| `done` | 4 |
| `mistake` | 4 |

There's an additional overflow pool of 6 entries for provisional items, and a hard cap of 40 total active entries. Entries beyond these limits are demoted to lower lifecycle states.

### Retrieval Telemetry

Pi logs which memories are injected and whether they were actually used in responses. This data lives at `.pi/data/memory-telemetry.jsonl` and helps you understand which memories are providing value.

## Troubleshooting

**Memory not showing up in pi's responses**

- Check that the entry is in the right topic file: `uv run myk-pi-tools memory show`
- The entry may have decayed below the active threshold — ask pi to search for it and reinforce it
- Scoring rebuilds run every 30 minutes; a freshly added entry should be active immediately

**"Topic would exceed size limit" error**

- A single topic file has reached its ~3,000-token cap
- Remove outdated entries with `memory_remove` or ask pi to consolidate
- Run `/dream` to trigger automatic cleanup

**Memory capacity at 80%+**

- Ask pi: "Consolidate my memories"
- Remove completed work entries (`done` category) that are no longer relevant
- Check if duplicate entries exist across topics

**Auto-extracted preferences you didn't intend**

- Pi detects phrases like "I always" even in casual statements
- Remove unwanted entries: ask pi to remove the specific memory
- Auto-extracted entries are learned (not pinned), so they'll decay on their own if never reinforced

## Related Pages

- [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: async-agents-and-cron.md

# Running Background Agents and Scheduled Tasks

Offload long-running work — code reviews, memory consolidation, research — to background agents so your session stays responsive, and set up recurring tasks that run on a schedule.

## Prerequisites

- A running pi session with the orchestrator extension loaded
- At least one specialist agent available (check with `/status`)

## Quick Example

Ask pi to run a code review in the background while you keep working:

```
Review the changes on this branch for security issues — run it in the background
```

The orchestrator dispatches the review agent asynchronously. You'll see `⏳ async: 1` in your status bar, and the result appears in your conversation when it finishes.

Check on it anytime:

```
/async-status
```

## How Async Agents Work

When the orchestrator delegates a task with `async: true`, it spawns a detached pi process that runs independently. Your session stays free for other work.

There are two delivery modes:

| Mode | Result Delivery | Use Case |
|------|----------------|----------|
| **Tracked** (default) | Result injected into your conversation when complete | Code reviews, research, analysis |
| **Fire-and-forget** | Terminal notification only, no conversation injection | Memory dreaming, maintenance tasks |

### What Happens When an Async Agent Finishes

1. A desktop/terminal notification fires: *"Async agent Code Review completed (2m34s)"*
2. For tracked agents, the full output appears in your conversation as a follow-up message
3. The status bar updates from `⏳ async: 1` to `⏳ async: 0`

## Monitoring Background Agents

### Checking Status

Run `/async-status` to see all running and recently completed agents:

```
/async-status
```

If agents are running, you'll get an interactive selector. Pick one to see its **live output** — a scrollable view that updates in real time as the agent works.

| Key | Action |
|-----|--------|
| ↑/↓ | Scroll line by line |
| PgUp/PgDn | Scroll by page |
| Home/End | Jump to top/bottom |
| Esc | Close the viewer |

> **Tip:** The status bar always shows the current async agent count (`⏳ async: N`). You can also see async status via `/status` for a unified snapshot.

### Killing Background Agents

To stop a runaway or unwanted agent:

```
/async-kill
```

This opens an interactive selector. Pick the agent to terminate.

You can also kill by name or kill all:

```
/async-kill code-reviewer-security
/async-kill all
```

## Async-Only Agents

Certain agents are enforced to **always** run asynchronously. If the orchestrator tries to dispatch them synchronously, the system automatically promotes the call to async. These agents are:

- `code-reviewer-quality`
- `code-reviewer-guidelines`
- `code-reviewer-security`

This prevents your session from blocking on long-running reviews. See [Running the Automated Code Review Loop](code-review-loop.html) for how reviews use async agents.

> **Note:** Async-only agents cannot be used in chain mode (sequential steps with `{previous}` placeholder). They must be dispatched as separate async tasks.

## Scheduling Recurring Tasks with /cron

Use `/cron` to schedule tasks that run on a repeating interval or at a specific time each day.

### Creating a Scheduled Task

Use natural language — the orchestrator parses your intent:

```
/cron run tests every 30 minutes
/cron check for new PRs every 2 hours
/cron summarize git log daily at 09:00
```

You can also schedule slash commands:

```
/cron run /dream every 4 hours
```

### Listing Scheduled Tasks

```
/cron list
```

Output:

```
#1 | every 30m  | run tests                    | last run: 14:30:00
#2 | every 2h   | check for new PRs            | last run: 13:00:00
#3 | at 09:00   | summarize git log            | last run: never
```

To see cron tasks across all active pi sessions:

```
/cron list-all
```

### Removing a Scheduled Task

```
/cron remove 2
```

You can remove multiple at once:

```
/cron remove 1 3
```

### How Cron Tasks Execute

| Task Type | Behavior |
|-----------|----------|
| Starts with `/` | Runs as a slash command in your session |
| Plain text prompt | Spawns a `worker` async agent with the prompt |

> **Note:** Cron tasks are scoped to the pi process. They survive `/reload`, `/resume`, and `/new` but stop when you exit pi. The minimum interval is 10 seconds.

### Schedule Types

| Type | Description | Example |
|------|-------------|---------|
| **Interval** | Runs every N seconds/minutes/hours | `/cron run tests every 15 minutes` |
| **Daily time** | Runs once per day at a specific time | `/cron deploy status at 08:30` |

## Automatic Memory Dreaming

Pi includes a built-in background task that consolidates session memories on a timer. See [Working with Project Memory](memory-system.html) for the full picture.

By default, dreaming runs every **3 hours** as a fire-and-forget async agent and also triggers on session quit.

Toggle it:

```
/dream-auto off
/dream-auto on
```

Trigger a dream manually:

```
/dream
```

Configure the interval per-project in `.pi/pi-config-settings.json`:

```json
{
  "dream_interval_hours": 4
}
```

Valid range: 0.5–24 hours. You can also set it globally with the `PI_DREAM_INTERVAL_HOURS` environment variable. See [Configuration and Environment Variables Reference](configuration-reference.html) for all settings.

## Advanced Usage

### Sync vs Async Decision

The orchestrator enforces a **30-second sync limit**. Tasks estimated to take 30 seconds or longer must use `async: true`. The orchestrator handles this automatically, but understanding the rule helps:

| Duration | Mode | Orchestrator Blocks? |
|----------|------|---------------------|
| < 30s estimated | Sync (default) | Yes — waits for result |
| ≥ 30s estimated | Async required | No — returns immediately |
| Any code reviewer | Always async | No — auto-promoted |

For sync tasks, the orchestrator also enforces:
- Maximum **4 concurrent** sync agents in parallel mode
- Maximum **8 parallel tasks** total per subagent call

### Parallel Async Dispatch

The orchestrator can spawn multiple async agents in a single turn. This is how the code review loop works — all three reviewers launch simultaneously:

```
Review the current changes — run all three reviewers in parallel
```

Each gets its own status entry. When all agents in the group finish, their results are delivered together as a single combined message — so you see everything at once rather than results trickling in one by one.

### Using /status for a Unified View

The `/status` command gives you a snapshot of everything running:

```
/status
```

```
⏳ Async agents: 2 running
   • Code Review Quality — 1m23s — Review changes on feat/issue-42
   • Code Review Security — 1m23s — Review changes on feat/issue-42
⏰ Cron tasks: 1 active
   • #1 every 30m — run tests (last: 14:30:00)
🌿 Git: feat/issue-42 ● 3 changed files (my-project)
```

See [Using Slash Commands and Prompt Templates](slash-commands.html) for details on `/status` and other commands.

### Viewing Async Agents in the Web Dashboard

If you have the pidash web dashboard running, async agents appear there in real time — including live event streaming from each background agent. See [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html) for setup.

## Troubleshooting

**Async agent stuck as "running" forever**
The poller checks if the agent's process is still alive. If the process died, the agent is automatically marked as failed. Zombie agents from previous sessions are cleaned up on session start. If you see a stuck agent, use `/async-kill` to terminate it.

**Cron tasks disappeared after restarting pi**
Cron tasks are tied to the pi process. When you exit pi and start a new session, previous crons are gone. Re-create them with `/cron`.

**Async results not appearing in conversation**
Fire-and-forget agents don't inject results — they only send a terminal notification. If a tracked agent's result is missing, check `/async-status` to see if it's still running or if it failed.

**Debug logging for async agents**
Set the `PI_ASYNC_DEBUG` environment variable to enable detailed logging:

```bash
PI_ASYNC_DEBUG=1 pi
```

Logs are written to the project temp directory under `debug.log`.

## Related Pages

- [Running the Automated Code Review Loop](code-review-loop.html)
- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: inter-agent-communication.md

# Communicating Between Pi Sessions

Coordinate work across multiple pi sessions by enabling them to discover each other, exchange messages, and delegate tasks — useful for multi-agent workflows like manager/coder splits, parallel code review, and collaborative feature development.

## Prerequisites

- Two or more pi sessions running in the same project directory (or on the same machine for P2P)
- For networked mode (`/coms-net`): [Bun](https://bun.sh) installed (used to run the hub server)

## Quick Example

Open two terminals in the same project directory. In the first:

```
/coms start --cname reviewer --purpose "Code reviewer"
```

In the second:

```
/coms start --cname coder --purpose "Feature implementer"
```

Now either agent can ask pi to send a message to the other. The orchestrator uses the `coms_send` tool to send prompts and `coms_await` to wait for replies. A live pool widget appears below the editor showing connected peers with their context usage.

## Choosing Between P2P and Networked Mode

| | P2P (`/coms`) | Networked (`/coms-net`) |
|---|---|---|
| Transport | Direct Unix sockets between sessions | HTTP/SSE hub server |
| Scope | Same machine only | Same machine or across a network |
| Server required | No | Yes (auto-started by default) |
| Tool prefix | `coms_` | `coms_net_` |
| Best for | Quick local pairing | Multi-session teams, remote collaboration |

Both modes can run simultaneously in the same session. They use separate tool names so there's no conflict.

## Setting Up P2P Communication

### Starting

In each pi session, run:

```
/coms start --cname <agent-name> --purpose "<what this agent does>"
```

Available flags for `/coms start`:

| Flag | Description |
|---|---|
| `--cname` | Agent name (used by peers to address this session) |
| `--purpose` | Short description of the agent's role |
| `--project` | Project namespace for discovery (defaults to current directory) |
| `--color` | Hex color `#RRGGBB` for the pool widget |
| `--explicit` | Hide from auto-discovery (only addressable by exact name) |

> **Note:** The project namespace defaults to the current working directory. Sessions in different directories won't see each other unless you set `--project` explicitly.

### Checking Status

```
/coms status
```

### Stopping

```
/coms stop
```

## Setting Up Networked Communication

Networked mode uses a hub server that sessions connect to. The server is auto-managed — `/coms-net start` launches one if none is running.

### Starting

```
/coms-net start --cname planner --purpose "Architecture planning"
```

This automatically:
1. Checks for a running hub server for the current project
2. Starts one if none is found (requires Bun)
3. Connects the session to the hub

Available flags for `/coms-net start`:

| Flag | Description |
|---|---|
| `--cname` | Agent name |
| `--purpose` | Short description of the agent's role |
| `--project` | Project namespace |
| `--color` | Hex color `#RRGGBB` |
| `--explicit` | Hide from auto-discovery |
| `--port` | Server port (default: OS picks a free port) |
| `--host` | Server bind address (default: `127.0.0.1`) |

### Connecting to an Existing Server

If another session already started the server, use `connect` instead of `start`:

```
/coms-net connect --cname coder --purpose "Feature implementer"
```

To connect to a remote server:

```
/coms-net connect --cname coder --url http://192.168.1.50:8080 --auth-token <token>
```

### Checking Status

```
/coms-net status
```

Shows whether coms-net is active, the server URL, and whether this session started the server.

### Disconnecting vs Stopping

- **`/coms-net disconnect`** — Disconnects from the server but leaves it running (use when you joined someone else's server)
- **`/coms-net stop`** — Disconnects and kills the server (use when you started the server)

> **Tip:** The server is shared — if Session A started it, Session B should use `disconnect`, not `stop`. Pi enforces this and shows a warning if you try the wrong one.

## Sending Messages Between Sessions

Once coms is active, pi's orchestrator has access to communication tools. You can ask pi to talk to a peer directly:

> "Ask the coder to implement the login form"

Or be explicit:

> "Use coms_send to ask reviewer to check the auth module"

### The Message Flow

1. **List peers** — Pi discovers available agents
2. **Send message** — Pi sends a prompt to the target peer
3. **Peer processes** — The target session receives the message as a follow-up and generates a response
4. **Receive reply** — The response is automatically returned to the sender

### How Replies Work

When a session receives an inbound message, it appears as:

```
[from reviewer @ /home/user/project] Please check the auth implementation
```

The receiving session writes its answer as a normal response. The coms extension automatically captures the assistant's output at the end of the turn and sends it back to the sender. No extra tool calls are needed to reply.

> **Warning:** Peers should never call `coms_send` to reply to an inbound message — that creates a new outbound conversation instead of a reply, leading to infinite ping-pong loops.

### Message Queue Behavior

Messages are processed in FIFO order. When a session is busy handling one message:

1. Additional incoming messages are queued, not dropped
2. After the current message is answered, the next one is automatically injected
3. Each message gets its own dedicated turn and response
4. Senders always get a reply — nothing is silently lost

## Delegating Structured Tasks

When coordinating multi-step work, use structured task delegation. This creates trackable tasks in the peer's task widget:

> "Send the coder these tasks: 1) Add JWT auth middleware for /api routes, 2) Write unit tests for the middleware"

Pi passes these as structured `tasks` alongside the message. The peer receives them as actionable items in their task tracking widget (requires `@tintinweb/pi-tasks`).

## The Feature Manager Pattern

A common multi-agent workflow pairs a **manager** (reviewer) session with a **coder** (implementer) session. The manager reviews work, provides feedback, and gates PR creation. The coder writes code and responds to feedback.

Generate a project-specific feature manager prompt with:

```
/create-coms-feature-manager
```

This creates a customized prompt at `.pi/prompts/coms-feature-manager.md` that defines the manager role, review workflow, and coder coordination protocol for your project.

## Advanced Usage

### Project Namespaces

Sessions are isolated by project namespace. By default, the namespace is derived from the working directory. To create a custom namespace shared across directories:

```
/coms start --cname agent-a --project my-team
```

All sessions using `--project my-team` will discover each other regardless of their working directory.

### Hidden Agents

Use `--explicit` to hide an agent from auto-discovery:

```
/coms start --cname secret-reviewer --explicit
```

Explicit agents don't appear in peer lists by default. Other sessions can still reach them by exact name. To include hidden agents when listing peers, pi uses the `include_explicit` parameter on the list tool.

### Hop Limits

Messages can chain between agents (A sends to B, B forwards to C). A hop counter prevents infinite forwarding. The default limit is 5 hops, configurable via the `PI_COMS_MAX_HOPS` environment variable (P2P) or `PI_COMS_NET_MAX_HOPS` (networked).

### Network Configuration for coms-net

For LAN access, bind the server to all interfaces:

```
/coms-net start --host 0.0.0.0 --port 9000
```

> **Warning:** When binding to a non-loopback address, you must set the `PI_COMS_NET_AUTH_TOKEN` environment variable explicitly. The server refuses to start on a public interface without an explicit token for security.

Remote sessions connect with:

```
/coms-net connect --url http://<server-ip>:9000 --auth-token <token>
```

### Environment Variables

| Variable | Default | Description |
|---|---|---|
| `PI_COMS_MAX_HOPS` | `5` | Maximum message forwarding hops (P2P) |
| `PI_COMS_TIMEOUT_MS` | `1800000` (30 min) | Response timeout (P2P) |
| `PI_COMS_PING_INTERVAL_MS` | `10000` | Peer health check interval (P2P) |
| `PI_COMS_NET_MAX_HOPS` | `5` | Maximum message forwarding hops (networked) |
| `PI_COMS_NET_MESSAGE_TTL_MS` | `1800000` (30 min) | Message time-to-live (networked) |
| `PI_COMS_NET_HEARTBEAT_MS` | `10000` | Heartbeat interval (networked) |
| `PI_COMS_NET_HOST` | `127.0.0.1` | Server bind address |
| `PI_COMS_NET_PORT` | `0` (auto) | Server port |
| `PI_COMS_NET_AUTH_TOKEN` | Auto-generated | Bearer token for hub authentication |
| `PI_COMS_NET_SERVER_URL` | Auto-discovered | Override server URL for clients |

### Server Lifecycle

The coms-net hub server is automatically managed:

- **Auto-start:** `/coms-net start` launches a server if one isn't running
- **Shared:** Multiple sessions connect to the same server
- **Auto-cleanup:** The server is killed when the session that started it shuts down (unless other peers are connected)
- **Crash recovery:** Stale registry entries and dead sockets are pruned automatically on session start

Server logs are written to `~/.pi/coms-net/projects/<project>/server.log`.

### Authentication

Token resolution follows a priority chain:

1. `--auth-token` flag (highest priority)
2. `PI_COMS_NET_AUTH_TOKEN` environment variable
3. Auto-discovered from `~/.pi/coms-net/projects/<project>/server.secret.json` (local servers only, file must be mode `0600`)

For local-only servers, the token is auto-generated and stored securely. For remote servers, always set the token explicitly.

## Troubleshooting

**"coms not active" when trying to send messages**
Run `/coms start` or `/coms-net start` first. Communication tools are unavailable until explicitly activated.

**Peers can't see each other (P2P)**
Verify both sessions are in the same project namespace. Run `/coms status` in each session. Check that both are running from the same directory, or set `--project` to match.

**"bun not found" when starting coms-net**
The hub server requires [Bun](https://bun.sh). Install it with `curl -fsSL https://bun.sh/install | bash`. Use P2P mode (`/coms start`) as an alternative that doesn't need Bun.

**Server port/host mismatch**
If you change `--port` or `--host` on a restart, `/coms-net start` automatically detects the mismatch and restarts the server with the new settings.

**Session shows stale peers in the pool widget**
Stale peers (marked with `✗`) are sessions that stopped responding to health checks. They're automatically removed after several missed checks. Run `/coms` or `/coms-net` to force-refresh the pool.

See [Slash Commands and Extension Commands Reference](commands-reference.html) for the complete `/coms` and `/coms-net` command syntax. See [Configuration and Environment Variables Reference](configuration-reference.html) for all coms-related environment variables.

## Related Pages

- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Customization and Extension Recipes](customization-recipes.html)

---

Source: external-ai-agents.md

# Using External AI Agents (Cursor, Claude, Gemini)

Get a second opinion from another AI by routing prompts to Cursor, Claude, or Gemini CLIs directly from your pi session. Use `/external-ai` for peer reviews, code generation, multi-agent debates, and any task where you want a different model's perspective.

## Prerequisites

- **AI CLI binaries installed:** At least one of `cursor` (agent CLI), `claude`, or `gemini` must be available on your system and authenticated.
- **myk-pi-tools installed:** The CLI that wraps the AI calls. Install with `uv tool install myk-pi-tools` if not already present.

## Quick Example

Ask Claude to review your code (read-only by default):

```
/external-ai claude review the error handling in this module
```

Ask Cursor to fix test failures (with file modification enabled):

```
/external-ai cursor --fix fix the failing tests
```

Run a peer review debate between pi and Gemini:

```
/external-ai gemini --peer review this code for correctness and edge cases
```

## Step-by-Step: Read-Only Review

The most common use case is getting a second opinion on code without modifying any files.

1. **Pick a provider and write your prompt:**

   ```
   /external-ai cursor explain why this function is slow and suggest improvements
   ```

2. **Pi runs the prompt** through the selected provider's CLI. The agent is explicitly told not to modify any files.

3. **View the results.** Pi displays the agent's response along with a usage summary showing tokens consumed, cost, and duration.

That's it. The external agent reads your project files, analyzes them, and reports back — all within your pi session.

## Choosing a Provider and Model

Three providers are supported:

| Provider | CLI Binary | Default Model |
|----------|------------|---------------|
| `cursor` | `agent` | `composer-2-fast` |
| `claude` | `claude` | `claude-sonnet-4-6` |
| `gemini` | `gemini` | `gemini-2.5-flash` |

Override the model with `--model`:

```
/external-ai cursor --model gpt-5.4-high review the architecture
```

Use Tab completion after `/external-ai` to browse available providers, and after `--model` to browse available models for each provider. If models seem stale, run `/external-ai-models-refresh` to update the cache.

> **Tip:** If you omit the provider name entirely, pi checks your saved config from the last run and asks whether to reuse it.

## Modes of Operation

### Read-Only (Default)

The external agent can read your files but cannot modify anything. Use this for reviews, explanations, and analysis.

```
/external-ai gemini explain the authentication flow in this project
```

### Fix Mode (`--fix`)

Enable file modifications so the agent can directly edit your code.

```
/external-ai cursor --fix fix the code quality issues
```

Before running in fix mode, pi checks your Git workspace state and offers to create a checkpoint commit so you can easily roll back. After the agent finishes, pi shows a diff summary of all changes made.

### Peer Review Mode (`--peer`)

Start an AI-to-AI debate loop where the external agent reviews your code and pi acts on the findings — fixing agreed issues, pushing back on disagreements, and sending changes back for re-review until both sides converge.

```
/external-ai claude --peer review this module for bugs and design issues
```

The loop works like this:

1. The external agent reviews the code and reports findings.
2. Pi evaluates each finding — fixing valid issues and preparing counter-arguments for disagreements.
3. Pi sends the fixes and counter-arguments back to the external agent.
4. The agent re-reviews, confirms fixes, and raises new issues or concedes points.
5. Steps 2–4 repeat until the agent reports no remaining issues.

> **Note:** Only the peer agent can end the loop. Pi fixing code doesn't count as convergence — the agent must verify the fixes are correct.

After convergence, pi displays a structured summary showing addressed findings, agreements reached after debate, unresolved disagreements, and per-round usage/cost tracking.

### Multi-Agent Reviews

Specify multiple providers separated by commas:

```
/external-ai cursor,claude review this code
```

Both agents run in parallel and their findings are collected. In peer mode, each agent gets full visibility into what the others said (group context), enabling a true multi-agent discussion:

```
/external-ai cursor,gemini --peer review the error handling strategy
```

## Session Management

By default, each `/external-ai` call starts a fresh conversation. Use `--resume` to continue where you left off:

```
/external-ai claude --resume what about the edge cases we discussed?
```

For precise session targeting, use `--session-id`:

```
/external-ai claude --session-id abc123 continue reviewing the auth module
```

| Flag | Behavior |
|------|----------|
| *(none)* | Fresh session each time |
| `--resume` | Continue the most recent session |
| `--session-id <id>` | Resume a specific session by ID |

> **Note:** `--resume` and `--peer` cannot be combined — peer mode manages sessions automatically across rounds.

## Combining Flags

Flags can be combined where it makes sense:

```
/external-ai cursor --model gpt-5.4-high --fix fix the code
/external-ai cursor --fix --resume continue fixing from where we left off
```

These combinations are **not allowed:**

| Combination | Why |
|-------------|-----|
| `--fix` + `--peer` | Mutually exclusive modes |
| `--resume` + `--peer` | Peer mode manages sessions automatically |
| `--fix` + multiple agents | Fix mode only works with a single agent |

## Saved Configuration

After each successful run, pi saves your provider and model choices to `.pi/external-ai-config.json`. Next time you run `/external-ai` without specifying a provider, pi offers to reuse your last selection:

```
/external-ai review this code
```

Pi will prompt: *"Last used: cursor. Use this?"* with options to accept, change, or cancel.

Peer mode saves its own config separately, so `/external-ai --peer review this` remembers your last peer providers independently.

## Advanced Usage

### Passing Extra CLI Flags

Send additional flags directly to the underlying AI CLI binary with `--cli-flags`:

```
/external-ai cursor --cli-flags=--trust review the security model
```

This is useful for provider-specific options that aren't exposed through `/external-ai` directly.

### Using Custom Models for Multi-Agent Peer Reviews

When running multi-agent peer reviews, you can specify different models for each provider using `--model`:

```
/external-ai cursor --model gpt-5.4-high --peer review the architecture
```

The usage summary at the end breaks down token usage and cost per provider, per round, and in aggregate — so you can see exactly what each agent contributed.

### AGENTS.md-Aware Reviews

If your project has an `AGENTS.md` file with coding conventions and guidelines, the peer review framing automatically instructs the external agent to read it and flag any violations. No extra configuration needed.

## Troubleshooting

**"Unknown provider" error**
Only `cursor`, `claude`, and `gemini` are supported by `/external-ai`. For other AI agents (codex, copilot, droid, kiro, etc.), use the `/acpx-prompt` command instead.

**Agent tries to modify files in read-only mode**
Pi automatically retries with a stricter read-only instruction. If it fails twice, the error is shown. Consider using `--fix` if you actually want modifications.

**"myk-pi-tools not found"**
Install it with `uv tool install myk-pi-tools`. See [Installing and Starting Your First Session](quickstart.html) for full setup instructions.

**Model autocomplete not showing results**
Run `/external-ai-models-refresh` to rebuild the model cache. The cache refreshes automatically every 5 minutes, but a manual refresh is useful after installing a new CLI or updating provider credentials.

**Long-running prompts**
External agents can take several minutes for complex tasks (reading many files, multi-step tool calls). There is no timeout — the command runs until the agent finishes. This is by design.

For the full list of flags and argument syntax, see [Slash Commands and Extension Commands Reference](commands-reference.html). For CLI details on the underlying `myk-pi-tools ai-cli` subcommands, see [myk-pi-tools CLI Reference](cli-reference.html).

## Related Pages

- [Using ACPX Provider for External Agent Models](acpx-provider.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [myk-pi-tools CLI Reference](cli-reference.html)
- [Common Workflow Recipes](workflow-recipes.html)

---

Source: docker-deployment.md

# Running Pi in a Docker Container

Run pi-config inside a sandboxed Docker container to get filesystem isolation, consistent tooling, and all dependencies pre-installed — without modifying your host system.

## Prerequisites

- **Docker** (or a compatible runtime like Podman) installed on your host
- An **LLM provider** configured (e.g., Google Cloud / Vertex AI credentials, or an API key)
- **Git**, **SSH keys**, and **GitHub CLI** (`gh`) configured on your host
- An environment file (`.env`) with your API keys and settings (see [Setting up the environment file](#setting-up-the-environment-file) below)

## Quick Start

Pull the pre-built image and launch a session from any project directory:

```bash
docker pull ghcr.io/myk-org/pi-config:latest

docker run --rm -it \
  --name "pi-config-$(basename $PWD)-$(date +%s)" \
  --network host \
  --env-file "$HOME/.pi/.env" \
  -v "$PWD":"$PWD":rw \
  -v "$HOME/.pi":"$HOME/.pi":rw \
  -v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
  -v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
  -v "$HOME/.ssh":"$HOME/.ssh":ro \
  -v "$HOME/.config/gh":"$HOME/.config/gh":ro \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

On first run, the container installs the latest `pi` and `pi-config` package, then drops you into an interactive pi session. Subsequent starts reuse cached packages and only pull updates.

## Setting Up the Environment File

Create a `.env` file at `~/.pi/.env` (or any path you prefer) with your credentials and configuration:

```env
# Timezone (match your host for correct timestamps)
TZ=America/New_York

# Host username — maps /home/<user> paths between host and container
PI_HOST_USER=yourname

# Google Cloud / Vertex AI
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-east5
GOOGLE_APPLICATION_CREDENTIALS=/home/yourname/.config/gcloud/application_default_credentials.json
VERTEX_PROJECT_ID=your-project-id
VERTEX_REGION=us-east5

# GitHub
GITHUB_TOKEN=ghp_xxx
GITHUB_API_TOKEN=ghp_xxx
GH_CONFIG_DIR=/home/yourname/.config/gh

# Gemini (optional — for image generation)
GEMINI_API_KEY=xxx
PI_IMAGE_MODEL=gemini-3-pro-image

# MCP Launchpad config path (must match mount target inside container)
MCPL_CONFIG_FILES=/home/yourname/.config/mcpl/mcp.json
```

> **Note:** Paths in the `.env` file should use your **host home directory path** (e.g., `/home/yourname/...`). The `PI_HOST_USER` setting creates symlinks inside the container so these paths resolve correctly.

## Understanding Volume Mounts

Every file the container can access must be explicitly mounted. This is the core of Docker's filesystem isolation.

### Required Mounts

| Mount | Mode | Purpose |
|-------|------|---------|
| `-v "$PWD":"$PWD"` | `rw` | Your project directory — the agent reads and writes code here |
| `-v "$HOME/.pi":"$HOME/.pi"` | `rw` | Pi settings, sessions, memory, and cached packages |
| `-v "$HOME/.gitconfig":"$HOME/.gitconfig"` | `ro` | Git configuration (name, email, aliases) |
| `-v "$HOME/.gitignore-global":"$HOME/.gitignore-global"` | `ro` | Global gitignore rules |
| `-v "$HOME/.ssh":"$HOME/.ssh"` | `ro` | SSH keys for git push/pull over SSH |
| `-v "$HOME/.config/gh":"$HOME/.config/gh"` | `ro` | GitHub CLI authentication |

### Optional Mounts

Add these for specific features:

| Mount | Mode | Purpose |
|-------|------|---------|
| `-v "$HOME/.config/gcloud/application_default_credentials.json":"$HOME/.config/gcloud/application_default_credentials.json"` | `ro` | Google Cloud ADC (for Claude via Vertex AI) |
| `-v "$HOME/.config/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json"` | `ro` | MCP server config for `mcpl` |
| `-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json"` | `ro` | Cursor CLI auth (for ACPX cursor models) |
| `-v "$HOME/.config/glab-cli":"$HOME/.config/glab-cli"` | `ro` | GitLab CLI config (auth tokens, host settings) |
| `-v "$HOME/.agents":"$HOME/.agents"` | `rw` | User-level skills (install/uninstall from container) |
| `-v "$HOME/.coderabbit":"$HOME/.coderabbit"` | `rw` | CodeRabbit CLI auth and review data |
| `-v "$HOME/screenshots":"$HOME/screenshots"` | `ro` | Share screenshots/images with the agent |

## Host User Mapping with `PI_HOST_USER`

The container runs as the `node` user (UID 1000) internally. When you mount host directories like `$HOME/.ssh` or `$HOME/.config/gh`, the paths inside the container don't match because the container's home is `/home/node`.

Set `PI_HOST_USER` in your `.env` file to your host username:

```env
PI_HOST_USER=yourname
```

The init entrypoint will:

1. Create `/home/yourname` inside the container and symlink it to the container's internal directories
2. Set `HOME=/home/yourname` so all your host paths (SSH keys, Git config, GCloud credentials) resolve correctly
3. Reverse-symlink mounted content back to `/home/node` so container tools find everything regardless of which home they check

> **Tip:** If your host UID is also 1000, you can skip `PI_HOST_USER` — paths under `/home/node` will match permission-wise. But if your username differs from `node`, you still need it for path resolution.

## Docker Socket Access

To let pi inspect running containers (via the read-only `docker-safe` wrapper), mount the Docker socket:

```bash
-v /var/run/docker.sock:/var/run/docker.sock:ro
```

The container's init entrypoint automatically detects the mounted socket and grants the `node` user access using ACLs or group membership — no manual `--group-add` is needed.

For Podman, mount the Podman socket instead:

```bash
-v /var/run/podman/podman.sock:/var/run/podman/podman.sock:ro
```

The `docker-safe` wrapper only allows **read-only inspection commands**: `ps`, `logs`, `inspect`, `top`, `stats`, `port`, `diff`, `images`, `version`, and `info`. All state-modifying commands (`run`, `exec`, `rm`, `build`, etc.) are blocked. See [Command Safety Guards and Enforcement](command-enforcement.html) for details.

## Networking

The `--network host` flag shares your host's network stack with the container. This is needed for:

- **Local MCP servers** — pi connects to MCP servers running on your host
- **File preview** — agents serve generated HTML files via HTTP for browser access
- **Pidash dashboard** — the web dashboard listens on port `19190` (accessible at `http://localhost:19190`)
- **Pidiff viewer** — the diff viewer listens on port `19290`

> **Tip:** If your LLM provider is cloud-based, you don't use local MCP servers, and you don't need the web dashboard or file preview, you can omit `--network host` and use the default bridge network instead.

## Creating a Shell Alias

Add this to your `~/.bashrc` or `~/.zshrc` to launch pi with a single command from any project directory:

```bash
alias pi-docker='docker pull ghcr.io/myk-org/pi-config:latest && \
  docker run --rm -it \
  --name "pi-config-$(basename $PWD)-$(date +%s)" \
  --network host \
  --env-file "$HOME/.pi/.env" \
  -v "$PWD":"$PWD":rw \
  -v "$HOME/.pi":"$HOME/.pi":rw \
  -v "$HOME/.gitconfig":"$HOME/.gitconfig":ro \
  -v "$HOME/.gitignore-global":"$HOME/.gitignore-global":ro \
  -v "$HOME/.ssh":"$HOME/.ssh":ro \
  -v "$HOME/.config/gh":"$HOME/.config/gh":ro \
  -v "$HOME/.config/gcloud/application_default_credentials.json":"$HOME/.config/gcloud/application_default_credentials.json":ro \
  -v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro \
  -v "$HOME/.config/glab-cli":"$HOME/.config/glab-cli":ro \
  -v "$HOME/.config/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json":ro \
  -v "$HOME/.agents":"$HOME/.agents":rw \
  -v "$HOME/screenshots":"$HOME/screenshots":ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest'
```

Then run `pi-docker` from any project directory. Remove any `-v` lines for mounts you don't need.

## What's Included in the Image

The container ships with all tools pre-installed:

| Tool | Purpose |
|------|---------|
| `pi` | Coding agent (installed/updated on each start) |
| `git`, `gh`, `glab` | Version control, GitHub CLI, GitLab CLI |
| `uv` / `uvx` | Python execution (enforced by the orchestrator) |
| `go` | Go development |
| `bun` | JavaScript/TypeScript runtime |
| `kubectl` / `oc` | Kubernetes and OpenShift CLI |
| `mcpl` | MCP server access |
| `myk-pi-tools` | PR review, release, and CLI utilities |
| `acpx` | Agent proxy for remote models |
| `agent-browser` | Browser automation (Chromium via Playwright) |
| `docker` / `podman` | Container CLIs (via `docker-safe` read-only wrapper) |
| `cr` | CodeRabbit CLI for local AI code reviews |
| `prek` | Pre-commit hook runner |
| `jq`, `curl` | JSON processing, HTTP requests |
| `procps` | Process utilities (`ps`, `top`, `pgrep`, `pkill`) |

## What's Protected

The container cannot access anything outside your mounted volumes:

- ✅ `$PWD` (your project) — read/write
- ✅ `~/.pi` (pi settings, sessions, memory) — read/write
- ✅ Git, GitHub, SSH config — read-only
- ❌ Other directories on your host — not accessible
- ❌ Other git repos — not accessible
- ❌ System files — not accessible

## Advanced Usage

### Building the Image from Source

> **Note:** The image is built for **linux/amd64** only. On ARM hosts (e.g., Apple Silicon), build with `--platform linux/amd64`.

```bash
git clone https://github.com/myk-org/pi-config.git
cd pi-config
docker build -t ghcr.io/myk-org/pi-config:latest .
```

### Updating the Image

```bash
docker pull ghcr.io/myk-org/pi-config:latest
```

The container also runs `pi update` automatically on each start, so you always get the latest pi-config package even without pulling a new image.

### Custom Dashboard and Diff Viewer Ports

Override the default ports via environment variables:

```env
PI_PIDASH_PORT=9999
PI_PIDIFF_PORT=9998
```

Or disable them entirely:

```env
PI_PIDASH_ENABLE=false
PI_PIDIFF_ENABLE=false
```

See [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html) for more on pidash and pidiff.

### Using ACPX Agent Providers

To route LLM requests through external agents (Cursor, Claude CLI, Gemini CLI), set `ACPX_AGENTS` in your `.env` and mount the appropriate auth files:

```env
ACPX_AGENTS=cursor
```

```bash
-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro
```

See [Using ACPX Provider for External Agent Models](acpx-provider.html) for setup details.

### Discord Bot in the Container

The Discord bot runs inside the pidash daemon. To enable it, create a Discord config file on your host:

```bash
cat > ~/.pi/discord.env << 'EOF'
DISCORD_BOT_TOKEN=your-token-here
DISCORD_ALLOWED_USERS=your-discord-user-id
EOF
```

Since `~/.pi` is already mounted read/write, the pidash daemon inside the container picks up this file automatically. Run `/pidash restart` in your pi session to activate it. See [Controlling Pi Sessions from Discord](discord-bot.html) for full setup.

### Project-Level Settings

Create `.pi/pi-config-settings.json` in your project directory to override defaults per-project:

```json
{
  "co_author": true,
  "use_worktrees": false,
  "dream_interval_hours": 6
}
```

See [Configuration and Environment Variables Reference](configuration-reference.html) for all available settings.

## Troubleshooting

### Container exits immediately on start

Check that your `.env` file path is correct in `--env-file`. A missing file causes Docker to fail silently. Verify with:

```bash
docker run --rm -it --env-file "$HOME/.pi/.env" ghcr.io/myk-org/pi-config:latest echo "env loaded"
```

### Permission denied on mounted volumes

The container runs as user `node` (UID 1000). If your host UID differs, mounted files may not be readable. Ensure your SSH keys and config files are world-readable or owned by UID 1000:

```bash
chmod 644 ~/.gitconfig
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_*
```

### `WARNING` about packages on startup

A warning about already-cached packages during startup is normal. The entrypoint runs `pi install` / `pi update` on every start. If the warning persists or you see errors, check your network connection — the container needs internet access to fetch packages.

### Git push/pull fails with SSH errors

Verify your SSH agent is running on the host and keys are loaded. The container mounts `~/.ssh` read-only but cannot access the host's SSH agent socket by default. Add the agent socket mount:

```bash
-v "$SSH_AUTH_SOCK":"$SSH_AUTH_SOCK":ro \
-e SSH_AUTH_SOCK="$SSH_AUTH_SOCK"
```

### Host paths don't resolve inside the container

Make sure `PI_HOST_USER` in your `.env` matches your host username exactly. The container creates a `/home/<PI_HOST_USER>` directory with symlinks so that paths like `/home/yourname/.config/gh` work inside the container.

## Related Pages

- [Installing and Starting Your First Session](quickstart.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)
- [Controlling Pi Sessions from Discord](discord-bot.html)

---

Source: dashboards-and-diffs.md

# Using the Web Dashboard and Diff Viewer

Monitor all your pi sessions from a browser and review code diffs with inline comments — without leaving your workflow. Pidash gives you a real-time web dashboard, and pidiff gives you a rich diff viewer that sends review comments back to pi.

## Prerequisites

- Pi is installed and running in TUI mode (interactive terminal)
- Your project is inside a git repository (required for pidiff)

## Quick Start

Both dashboards auto-start when you launch a pi session. Open them in your browser:

- **Dashboard:** [http://localhost:19190](http://localhost:19190)
- **Diff viewer:** [http://localhost:19290](http://localhost:19290)

The URLs appear in your pi status line automatically once the daemons are ready.

> **Tip:** If the daemons didn't auto-start (e.g., first run with cold compilation), use `/pidash start` and `/pidiff start` in your pi session.

## Managing the Dashboard (pidash)

### Checking Status

```
/pidash status
```

This shows whether the server is running, the port it's listening on, and whether your session is connected.

### Starting, Stopping, and Restarting

```
/pidash start
/pidash stop
/pidash restart
```

### What You Can Do in the Browser

Once you open `http://localhost:19190`, the dashboard shows:

- **Session sidebar** — all active pi sessions, grouped by project. Click any session to watch it live.
- **Message stream** — user prompts, AI responses (including thinking blocks), tool calls and results, all in real-time.
- **Input bar** — type prompts directly from the browser. They're delivered to the pi session as follow-up messages.
- **Info bar** — model name, thinking level, token usage, git branch/status, async agent count, and cron tasks.
- **Search** — filter messages by content or by role (user, assistant, tool, thinking).

### Sending Prompts from the Browser

Type in the input bar at the bottom. Your message is forwarded to the active pi session. If the AI is currently streaming a response, a "prompt queued" banner appears — your message will run after the current turn.

You can also send slash commands (e.g., `/status`, `/btw what's the test coverage?`) directly from the browser input bar.

> **Note:** You can attach images via the browser input bar. They're sent as base64 to the pi session alongside your text prompt.

### Switching Between Sessions

The sidebar lists all active sessions. Click one to watch it. The dashboard replays the session's message history so you can catch up.

Keyboard shortcuts for fast switching:

| Shortcut | Action |
|----------|--------|
| `Ctrl+K` | Open session switcher (fuzzy search) |
| `Ctrl+↑` / `Ctrl+↓` | Previous / next session |
| `Ctrl+1` through `Ctrl+9` | Jump to session by position |
| `Escape` | Abort the current AI turn |

> **Tip:** Keybindings are customizable. Click the settings icon in the sidebar to rebind any shortcut.

### Changing Model and Thinking Level

Click the model name or thinking level in the info bar to open a dropdown. Selecting a new value takes effect immediately in the pi session.

- **Model:** searchable list of all available models
- **Thinking level:** off, minimal, low, medium, high

### Monitoring Background Agents and Cron Tasks

The info bar shows async agent and cron task counts. Click them to expand:

- **Async agents** — see each running agent's name, task, elapsed time. Click "Kill" to terminate one, or "Kill All" to stop all.
- **Cron tasks** — see schedules, last/next run times. Kill individual tasks or all at once.

See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for more on async agents and cron.

### Responding to Dialogs

When pi asks a question (via `ask_user`), the dialog appears inline in the message stream. You can respond from either the terminal or the browser — whichever answers first wins.

### Browser Notifications

The dashboard sends browser notifications for events in non-watched sessions (or when the tab is unfocused):

| Notification | Default |
|---|---|
| AI turn complete | On |
| Agent finished | On |
| Test results | On |
| Session errors | On |
| Input needed | On |
| Tool complete | Off |

Click the bell icon in the sidebar to toggle individual categories. Grant browser notification permission when prompted.

## Using the Diff Viewer (pidiff)

### Checking Status

```
/pidiff status
```

### Starting, Stopping, and Restarting

```
/pidiff start
/pidiff stop
/pidiff restart
```

### Viewing Diffs

Open `http://localhost:19290` in your browser. The diff viewer shows:

- **Session selector** — pick which pi session's repository to view
- **File tree** — left panel with all changed files, color-coded by git status (added, modified, deleted, renamed)
- **Diff panes** — syntax-highlighted side-by-side or unified diffs

Diffs are categorized into three areas:

| Area | Description |
|------|-------------|
| **Committed** | Changes between the branch's merge base and HEAD |
| **Staged** | Files added to the git index (`git add`) |
| **Unstaged** | Working tree modifications and untracked files |

### Branch vs. Commit Mode

Two diff modes are available via the header buttons:

- **Branch** (default) — shows all changes on the current branch relative to the default remote branch (e.g., `origin/main`)
- **Commits** — select two commits from a dropdown to compare them directly

### Worktree Support

If your project uses git worktrees, tabs appear in the header — one per worktree. Click a tab to switch between worktree views. A yellow dot on a tab indicates that worktree has changed since you last looked at it.

### Leaving Review Comments

Click any line number gutter in a diff to open an inline comment form. Write your review comment and click "Comment" (or press `Ctrl+Enter`).

Comments accumulate in the "Pending" panel below the file tree. You can:

- **Edit** — click a pending comment to re-open its form
- **Delete** — hover and click the ✕ icon
- **Reply** — add threaded replies to existing comments
- **Resolve** — mark a comment as addressed

### Publishing Review Comments

Click the green **Publish** button in the header (or in the pending panel) to send all comments to the pi session. Pi receives them as a structured code review and will address the feedback.

> **Note:** Publishing clears all pending comments. The comments are delivered to the pi session as a follow-up message containing the review in JSON format.

### Real-Time Change Detection

The diff viewer watches your file system using chokidar. When files change, an amber "Files have changed" banner appears. Click **Refresh** to reload the diffs.

### Customizing Diff Display

The settings toolbar lets you adjust:

| Setting | Options |
|---------|---------|
| **Diff style** | Split (side-by-side) or Unified |
| **Indicators** | Bars, Classic (+/-), or None |
| **Line diff** | word-alt, word, char, none |
| **Hunk separators** | line-info, line-info-basic, metadata, simple |
| **Theme** | 30+ themes including pierre-dark, github-dark, dracula, monokai, tokyo-night, catppuccin, and more |
| **Font size** | 11px – 16px |
| **Backgrounds** | Toggle diff background colors |
| **Wrapping** | Scroll or wrap long lines |
| **Line numbers** | Toggle visibility |

## Advanced Usage

### Custom Ports

Override the default ports with environment variables:

| Variable | Default | Description |
|----------|---------|-------------|
| `PI_PIDASH_PORT` | `19190` | Pidash dashboard port |
| `PI_PIDIFF_PORT` | `19290` | Pidiff diff viewer port |

Set these before starting your pi session:

```bash
PI_PIDASH_PORT=8080 PI_PIDIFF_PORT=8081 pi
```

### Disabling Auto-Start

If you don't want the daemons to start automatically:

```bash
PI_PIDASH_ENABLE=false pi    # Disable dashboard
PI_PIDIFF_ENABLE=false pi    # Disable diff viewer
```

When disabled, the `/pidash` and `/pidiff` commands still exist but will tell you the extension is disabled.

### Linking Pidash and Pidiff

The dashboard info bar includes a direct link to the diff viewer when both are running. Look for the "diff" link next to the git branch indicator — clicking it opens the diff viewer for the currently watched session.

### Discord Bot Integration

Pidash includes an optional Discord bot that bridges DMs to pi sessions. This lets you monitor and interact with pi from your phone.

To enable it, create `~/.pi/discord.env`:

```
DISCORD_BOT_TOKEN=your-bot-token-here
DISCORD_ALLOWED_USERS=your-discord-user-id
```

Once configured, the bot starts with the pidash daemon. Use these Discord commands:

| Command | Description |
|---------|-------------|
| `/sessions` | List active sessions — tap a button to watch one |
| `/status` | Show current watched session info |
| `/stop` | Interrupt the current AI turn |

You can also send prompts by DM'ing the bot directly (including image attachments). Responses stream back to Discord.

> **Warning:** If you omit `DISCORD_ALLOWED_USERS`, the bot accepts DMs from everyone. Always restrict access in production.

### Network Access

Pidash binds to `0.0.0.0` (accessible from your LAN) while pidiff binds to `127.0.0.1` (localhost only). The pidash server validates the `Origin` header, accepting only localhost and RFC 1918 private IP ranges.

### Session Switching from the Browser

Click the "sessions" dropdown in the info bar to see all saved sessions for the current project. Selecting a different session tells pi to switch to it (equivalent to `/resume` in the terminal).

### Session History on Reconnect

If the pidash daemon restarts, sessions automatically reconnect. The dashboard loads full session history from pi's session file (the source of truth), so you never lose context.

## Troubleshooting

**Dashboard shows "← Select a session" but sessions are running**

The daemon may be starting for the first time (cold compilation can take up to 60 seconds). Wait for the status line URL to appear in your pi terminal, then refresh the browser.

**Diff viewer shows "Waiting for pi sessions…"**

Your pi session must be in a git repository. Non-git directories won't register with pidiff.

**Commands from the browser don't work**

Make sure you've typed at least one command in the terminal first. The browser command handler needs to capture pi's command context from the first interactive use.

**Server logs**

Check the daemon logs for errors:

- `~/.pi/pidash-server.log` — pidash daemon output
- `~/.pi/pidash-debug.log` — pidash extension debug log
- `~/.pi/pidiff-debug.log` — pidiff extension debug log

**Stale diffs after branch switch**

The amber banner may not appear immediately for branch-level changes. Click the "Refresh" button manually or switch modes to force a reload.

## Related Pages

- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Controlling Pi Sessions from Discord](discord-bot.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Running the Automated Code Review Loop](code-review-loop.html)

---

Source: workflow-recipes.md

# Common Workflow Recipes

Copy-paste patterns for the most common pi workflows. Each recipe is self-contained — run exactly as shown.

> **Note:** All recipes assume `myk-pi-tools` is installed. If not, run `uv tool install myk-pi-tools` first. See [Installing and Starting Your First Session](quickstart.html) for full setup.

---

## Implement a Feature End-to-End

The most common workflow: scout the codebase, plan changes, and implement in one command.

```
/implement add pagination to the /api/users endpoint
```

This chains three agents sequentially: **scout** explores the codebase to find relevant files and dependencies, **planner** creates a detailed implementation plan, and **worker** executes the plan. Use this when you know what you want built and want pi to handle the full cycle.

- For tasks where you want to review the plan before coding, use `/scout-and-plan` instead (see below)
- The orchestrator will follow the [code review loop](code-review-loop.html) automatically after implementation

---

## Implement with Automatic Code Review

Implement a change and immediately run the three parallel code reviewers, then auto-fix any findings.

```
/implement-and-review refactor the database connection pool to use async context managers
```

This chains: **worker** implements the task → three review agents (**code-reviewer-quality**, **code-reviewer-guidelines**, **code-reviewer-security**) run in parallel → **worker** fixes all findings. Use this when you want a single-command implement-and-polish cycle without manual intervention.

- Reviewers are enforced as async subagents — they run in the background without blocking your session
- See [Running the Automated Code Review Loop](code-review-loop.html) for details on how the three reviewers work

---

## Scout and Plan Without Implementing

Explore the codebase and get a detailed plan before committing to changes.

```
/scout-and-plan migrate the authentication module from JWT to session-based auth
```

This chains two agents: **scout** maps out relevant files, functions, and dependencies, then **planner** produces a step-by-step implementation plan with edge cases and testing approach. Use this when you want to understand the scope of a change before writing any code.

- The plan output includes specific file paths, function names, and line numbers
- After reviewing the plan, you can run `/implement` with the plan as context

---

## Review a GitHub PR

Review an open PR and optionally post inline comments on GitHub.

```
/pr-review 42
```

Or let pi auto-detect the PR from your current branch:

```
/pr-review
```

Or use a full URL:

```
/pr-review https://github.com/owner/repo/pull/42
```

This clones the PR's repository, checks past review comments from previous cycles, then sends all three code review agents in parallel — each with full repo access. Reviewers independently read the project's AGENTS.md (or CLAUDE.md) for guideline compliance. After analysis, pi presents findings grouped by severity (CRITICAL, WARNING, SUGGESTION) and lets you choose which to post as inline GitHub comments. Posted comments are stored in a local database for tracking across review cycles.

- Requires `gh` CLI to be authenticated
- Past review comments (resolved and unresolved) are verified against the current diff
- See [Using Slash Commands and Prompt Templates](slash-commands.html) for all command variants

---

## Review Local Uncommitted Changes

Run the three-reviewer code review on local changes without creating a PR.

Review uncommitted changes (staged + unstaged):

```
/review-local
```

Review changes compared to a specific branch:

```
/review-local main
```

This runs all three code review agents in parallel against your local diff. Findings are grouped by severity. Use this as a pre-commit quality check before pushing.

---

## Handle PR Reviews (Human, CodeRabbit, Qodo)

Process and respond to all review comments on your current branch's PR.

```
/review-handler
```

This fetches review comments from all sources (human reviewers, CodeRabbit, Qodo), presents them in a table grouped by source and priority, and lets you decide which to address. For each approved comment, pi delegates to the appropriate specialist agent, runs tests, commits fixes (always as new commits — never amends), and posts replies on GitHub.

> **Tip:** You can also target a specific review URL:
> ```
> /review-handler https://github.com/owner/repo/pull/42#pullrequestreview-789
> ```

---

## Auto-Fix CodeRabbit Comments

Automatically address all CodeRabbit comments in a polling loop — no manual approval needed.

```
/review-handler --autorabbit
```

This skips the manual decision phase for CodeRabbit comments, auto-approving all of them. After fixing and pushing, pi enters a polling loop that watches for new CodeRabbit comments triggered by your push. The loop runs until CodeRabbit approves the PR or you explicitly stop it.

- Human review comments are still presented for manual decision
- The session remains interactive while the polling loop runs in the background

---

## Auto-Fix Qodo Comments

Automatically address all Qodo review findings — every finding gets a code fix or an issue spec update.

```
/review-handler --autoqodo
```

Every Qodo finding type (`qodo_bug`, `qodo_rule_violation`, `qodo_requirement_gap`, etc.) must be addressed — none are optional. Findings result in either a code fix or a GitHub issue spec update via `gh issue edit`.

- Combine both automated reviewers: `/review-handler --autorabbit --autoqodo`
- Human comments are always presented for manual decision, even in auto modes

> **Warning:** `--autorabbit` and `--autoqodo` are command-level flags for pi — they are never passed to the `myk-pi-tools` CLI.

---

## Check Review Handler Status

See the live state of running autorabbit/autoqodo review agents.

```
/review-handler-status
```

This checks `/async-status` for agents running `reviews poll`, then generates an HTML status report for each active PR. Use this to monitor long-running auto-fix loops.

---

## Create a GitHub Release

Generate a changelog from conventional commits and create a GitHub release.

Auto-detect version bump from commit types:

```
/release
```

Release with an explicit version (skips approval):

```
/release 2.1.0
```

Preview without creating:

```
/release --dry-run
```

This analyzes commits since the last tag, categorizes them by conventional commit type (`feat:` → MINOR, `fix:` → PATCH, breaking changes → MAJOR), generates a formatted changelog with emoji section headers, and creates the GitHub release. If version files are detected (e.g., `pyproject.toml`, `package.json`), pi bumps them via a PR before creating the release.

- Use `--prerelease` for pre-release versions or `--draft` for draft releases
- Use `--target <branch>` to release from a branch other than the default
- See [Slash Commands and Extension Commands Reference](commands-reference.html) for all flags

---

## Refine Pending PR Review Comments

Polish your in-progress GitHub review comments with AI before submitting.

```
/refine-review https://github.com/owner/repo/pull/42
```

This fetches your pending (unsubmitted) review comments from the PR, uses the diff context to generate refined versions that are clearer and more actionable, presents original vs. refined side-by-side, and lets you accept, reject, or customize each refinement. Optionally submits the review as "Request Changes". If submitted, comments are stored in the PR review database for future cycle tracking.

- You must have a pending review on the PR (started via GitHub UI but not yet submitted)
- You can provide custom replacement text for any comment during the approval step

---

## Query the Review Database

Analyze your PR review history with built-in analytics queries.

Stats by review source (human, CodeRabbit, Qodo):

```
/query-db stats --by-source
```

Stats by individual reviewer:

```
/query-db stats --by-reviewer
```

Find recurring dismissed suggestions:

```
/query-db patterns --min 2
```

Run a custom SQL query (read-only):

```
/query-db query "SELECT source, status, COUNT(*) as cnt FROM comments GROUP BY source, status ORDER BY cnt DESC"
```

Find comments similar to previously dismissed ones:

```
/query-db find-similar < comments.json
```

The review database stores all processed review comments with their status, source, priority, and replies. Only `SELECT` statements and CTEs are allowed — the database is read-only for queries. See [myk-pi-tools CLI Reference](cli-reference.html) for all `db` subcommands.

---

## Handle a CodeRabbit Rate Limit

Automatically wait out a CodeRabbit rate limit and re-trigger the review.

```
/coderabbit-rate-limit
```

Or target a specific PR:

```
/coderabbit-rate-limit 42
```

This checks if the PR is currently rate-limited by CodeRabbit, waits for the cooldown period (plus a 30-second buffer), then posts `@coderabbitai review` to re-trigger. It polls until the review starts. Use this when CodeRabbit hits its hourly limit during active development.

---

## Save a Memory for Future Sessions

Persist a lesson, preference, or decision so pi remembers it across sessions.

```
/remember always use ruff instead of flake8 for Python linting
```

```
/remember the payment service uses idempotency keys — never retry without checking
```

This saves the text as a **pinned** memory entry, automatically categorized (lesson, preference, decision, mistake, pattern, or done). Pinned memories resist decay and are injected into future session context. See [Working with Project Memory](memory-system.html) for the full memory system.

---

## Route a Task to an External AI Agent

Send a prompt to Cursor, Claude, or Gemini CLI for a second opinion or peer review.

Read-only review (no file changes):

```
/external-ai cursor review the error handling in src/api/
```

Fix mode (agent can modify files):

```
/external-ai claude --fix refactor the retry logic in src/client.py
```

AI-to-AI peer review loop:

```
/external-ai cursor --peer review the authentication module
```

Multi-agent review:

```
/external-ai cursor,claude review the database migration
```

Select a specific model:

```
/external-ai cursor --model gpt-5.4-high review the architecture
```

This runs your prompt through [ai-cli-runner](https://github.com/myk-org/ai-cli-runner), which calls the AI CLI tool as a subprocess. In `--peer` mode, pi orchestrates an iterative debate loop where the external agent reviews code, pi fixes findings, and the agent re-reviews until convergence. See [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html) for the full guide.

> **Tip:** Your last-used agent and model are saved to `.pi/external-ai-config.json`. Run `/external-ai` without an agent name to reuse them.

---

## Handle Reviews for Multiple PRs

Use git worktrees to process reviews for multiple PRs in parallel without branch switching.

```
git worktree add .worktrees/pr-42 origin/fix/issue-42
git worktree add .worktrees/pr-43 origin/feat/issue-43
```

Then run `/review-handler` in each worktree directory. When done:

```
git worktree remove .worktrees/pr-42
git worktree remove .worktrees/pr-43
```

Branch switching in the main worktree corrupts parallel agent work. Always use `.worktrees/` — it's in the global gitignore. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for more on parallel agent patterns.

---

## Save a Reusable Skill from a Workflow

Turn a successful workflow into a reusable skill that pi can apply in future sessions.

```
/create-skill debug-container-build
```

This analyzes the current conversation, extracts the steps you followed (commands, pitfalls, verification), and writes a `SKILL.md` file. You choose whether the skill is **global** (`~/.agents/skills/`) or **project-scoped** (`.pi/skills/`). See [Customization and Extension Recipes](customization-recipes.html) for more on extending pi.

> **Tip:** Skills are matched to tasks by their one-line description. Make it specific: "Debug Docker build failures caused by missing system dependencies" beats "Debug Docker".

## Related Pages

- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Your First Coding Workflow](first-workflow.html)
- [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html)
- [Working with Project Memory](memory-system.html)

---

Source: customization-recipes.md

# Customization and Extension Recipes

Recipes for tailoring pi to your project — adding specialist agents, building prompt templates, capturing skills, tuning project settings, and connecting MCP servers.

## Add a Project-Scoped Specialist Agent

Create an agent that's available only within a specific project.

```markdown
<!-- File: .pi/agents/terraform-expert.md -->
---
name: terraform-expert
description: Terraform and OpenTofu infrastructure-as-code creation, modification, and troubleshooting.
tools: read, write, edit, bash
---

You are a Terraform Expert specializing in infrastructure-as-code.

## Base Rules

- Execute first, explain after
- Do NOT explain what you will do — just do it
- Do NOT ask for confirmation unless creating/modifying resources
- If a task falls outside your domain, report it and hand off

## Core Expertise

- Terraform and OpenTofu (HCL syntax, modules, state)
- Providers: AWS, GCP, Azure, Kubernetes
- Remote state (S3, GCS, Consul)
- Sentinel and OPA policy-as-code

## Quality Checklist

- [ ] `terraform fmt` passes
- [ ] `terraform validate` passes
- [ ] Variables have descriptions and types
- [ ] Outputs documented
- [ ] State locking configured
```

The agent file must have YAML frontmatter with `name`, `description`, and `tools`. Place it in `.pi/agents/` (project-scoped) or `~/.pi/agent/agents/` (user-global). Pi discovers it automatically on the next session — no restart needed.

- **Supported frontmatter fields:** `name` (required), `description` (required), `tools` (comma-separated), `model` (override LLM model), `provider` (override LLM provider)
- **Override built-in agents:** a project agent with the same `name` as a package agent replaces it
- **Priority:** package agents < user agents < project agents (later overrides earlier by name)

> **Note:** After adding the agent, update the routing table in `rules/10-agent-routing.md` so the orchestrator knows when to use it. See [Understanding Agent Routing and Delegation](agent-routing.html) for details.

## Add a Lightweight Agent with a Model Override

Create a cheap, fast agent for simple tasks by pinning it to a smaller model.

```markdown
<!-- File: .pi/agents/quick-formatter.md -->
---
name: quick-formatter
description: Fast code formatting and linting fixes using a lightweight model.
tools: read, write, edit, bash
model: claude-haiku-4-5
---

You are a code formatter. Run the project's formatter and linter, fix any issues.

## Approach

1. Detect the project type (package.json, pyproject.toml, Cargo.toml)
2. Run the formatter (prettier, ruff format, rustfmt)
3. Run the linter and fix auto-fixable issues
4. Report what changed
```

The `model` field in frontmatter forces this agent to always use the specified model, regardless of what the parent session is running. Use this for agents that don't need a large reasoning model.

## Create a Custom Prompt Template

Build a reusable slash command that becomes available as `/my-command`.

```markdown
<!-- File: .pi/prompts/lint-and-fix.md -->
---
description: "Run linters, fix all auto-fixable issues, and report remaining problems — /lint-and-fix [path]"
argument-hint: "[path]"
---

## Raw Arguments

```text
$ARGUMENTS
```

> **Bug Reporting Policy:** If you encounter ANY error, unexpected behavior, or reproducible bug while executing this command — DO NOT work around it silently. Ask the user: "Should I create a GitHub issue for this?" Route to `myk-org/pi-config` for prompt/extension issues, or to the relevant tool's repository for CLI issues.

# Lint and Fix

Run all project linters with auto-fix enabled, then report remaining issues.

## Workflow

1. Detect the project type and available linters
2. Run auto-fix:
   - Python: `uv run ruff check --fix . && uv run ruff format .`
   - Node.js: `npx eslint --fix . && npx prettier --write .`
   - Go: `gofmt -w . && golangci-lint run --fix`
3. Run a second pass without `--fix` to collect remaining issues
4. Report: files changed, issues fixed, issues remaining
```

Place the file in `.pi/prompts/` and reload pi (or start a new session). The file name becomes the command name — `lint-and-fix.md` → `/lint-and-fix`. The `$ARGUMENTS` placeholder is replaced with whatever the user types after the command.

> **Warning:** Every prompt template **must** include the Bug Reporting Policy blockquote after the Raw Arguments section. This is mandatory for all templates.

- The `description` field in frontmatter is displayed in command completion
- The `argument-hint` field shows usage hints during autocomplete
- The orchestrator executes the prompt directly — it is **not** delegated to an agent (see [Orchestrator Rules Reference](rules-reference.html))

## Save a Workflow as a Reusable Skill

Capture a successful multi-step workflow from the current conversation so pi can replay it later.

```text
/create-skill debug-container-build
```

Pi will:

1. Analyze the current conversation to extract the steps you followed
2. Ask whether to save **globally** (`~/.agents/skills/`) or **per-project** (`.pi/skills/`)
3. Write a `SKILL.md` file with exact commands, verification steps, and pitfalls

The resulting skill file looks like this:

```markdown
<!-- Generated: ~/.agents/skills/debug-container-build/SKILL.md -->
---
name: debug-container-build
description: "Debug Docker multi-stage build failures by isolating the failing stage and inspecting intermediate layers"
---

# Debug Container Build

## When to Use

- Docker multi-stage build fails at an intermediate stage
- Build cache invalidation causes unexpected rebuilds

## Steps

1. Identify the failing stage: `docker build --target <stage> .`
2. Run the intermediate image interactively: `docker run --rm -it <image> sh`
3. Check file permissions and paths inside the container
4. Fix the Dockerfile and rebuild with `--no-cache` for the failing stage

## Pitfalls

- Alpine images use `ash` not `bash` — use `sh` for shell access
- Multi-stage COPY --from references are positional if stages are unnamed
```

> **Tip:** Run `/create-skill` immediately after solving a tricky problem — the conversation context is freshest. Skill names must be lowercase and hyphenated (e.g., `fix-flaky-tests`, not `Fix Flaky Tests`).

## Configure Project Settings

Customize pi's behavior per-project using `.pi/pi-config-settings.json`.

```json
{
  "co_author": true,
  "use_worktrees": false,
  "dream_interval_hours": 6
}
```

Create this file at `.pi/pi-config-settings.json` in your project root. Settings take effect on the next session start.

| Setting | Type | Default | Effect |
|---------|------|---------|--------|
| `co_author` | boolean | `false` | Add `Co-authored-by: pi` trailer to git commits |
| `use_worktrees` | boolean | `false` | Force worktree-only workflow (no branch switching in main worktree) |
| `dream_interval_hours` | number | `3` | How often auto-dreaming runs (memory consolidation) |

- **Resolution order:** project file → environment variable → default
- **Environment variables:** `PI_CO_AUTHOR`, `PI_USE_WORKTREES`, `PI_DREAM_INTERVAL_HOURS` are used as fallbacks if the setting isn't in the JSON file
- **Live reload:** the settings file is re-read on a throttled interval (every 30 seconds) — edits take effect without restarting

See [Configuration and Environment Variables Reference](configuration-reference.html) for the full list of environment variables.

## Discover and Use MCP Server Tools

Find and call tools from MCP (Model Context Protocol) servers using `mcpl`.

```bash
# Search for a tool across all connected servers
mcpl search "list projects"

# List all tools on a specific server
mcpl list vercel

# Get full schema with an example call
mcpl inspect sentry search_issues --example

# Call a tool with arguments
mcpl call vercel list_projects '{"teamId": "team_xxx"}'

# Verify all server connections are healthy
mcpl verify
```

The orchestrator uses `mcpl search` and `mcpl list` for discovery, then delegates actual tool execution to specialist agents. You don't need to configure MCP servers in pi-config — they're managed by your MCP server configuration (e.g., `mcp.json`).

- **Never guess tool names** — always `mcpl search` or `mcpl list` first
- **Troubleshoot connections:** `mcpl verify` tests all servers, `mcpl session stop` restarts the daemon
- **Timeout issues:** set `MCPL_CONNECTION_TIMEOUT=120` for slow servers

See [Orchestrator Rules Reference](rules-reference.html) for how MCP tools fit into the delegation model.

## Override a Built-In Agent for Your Project

Replace a package-bundled agent with a customized version for your project.

```markdown
<!-- File: .pi/agents/python-expert.md -->
---
name: python-expert
description: Python expert customized for our Django + Celery monorepo.
tools: read, write, edit, bash
---

You are a Python Expert for this Django + Celery monorepo.

## Base Rules

- Execute first, explain after
- Do NOT ask for confirmation unless creating/modifying resources
- If a task falls outside your domain, report it and hand off

## Project Conventions

- Always use `uv run` and `uvx` — never raw `python` or `pip`
- Models go in `apps/<app>/models/` — one model per file
- Use `pytest-django` with `@pytest.mark.django_db` for DB tests
- Celery tasks must have `bind=True, max_retries=3, default_retry_delay=60`
- All API views use `rest_framework.decorators.api_view`, never class-based views

## Quality Checklist

- [ ] `uv run ruff check --fix .` passes
- [ ] `uv run pytest --tb=short` passes
- [ ] Type hints on all public functions
- [ ] Celery tasks have retry config
```

Because the project agent's `name` field matches the built-in `python-expert`, it completely replaces the package version for this project. Other projects continue using the original.

## Add Autocomplete for a Custom Prompt Template

Wire up Tab-completion for a custom prompt template's arguments.

To add autocomplete for your own prompt template, edit `extensions/orchestrator/extended-autocomplete.ts`:

```typescript
// 1. Add the completion function to the `completions` map:
"my-command": (prefix: string) => {
  return filter([
    { value: "--verbose", label: "--verbose", description: "Show detailed output" },
    { value: "--dry-run", label: "--dry-run", description: "Preview without changes" },
    { value: "src/", label: "src/", description: "Source directory" },
    { value: "tests/", label: "tests/", description: "Test directory" },
  ], prefix);
},

// 2. Add the command name to promptTemplateCommands:
const promptTemplateCommands = new Set([
  "external-ai", "pr-review", "coderabbit-rate-limit",
  "review-local", "release", "review-handler", "cron",
  "create-skill", "create-coms-feature-manager",
  "my-command",  // ← add here
]);
```

This gives users Tab-completion when typing `/my-command <Tab>`. Extension commands (registered via `pi.registerCommand`) get autocomplete automatically through the `getArgumentCompletions` wrapper — only prompt templates need this manual step.

> **Note:** This recipe requires modifying the pi-config source. See [Extension Architecture and Lifecycle Hooks](extension-architecture.html) for how the autocomplete system works.

## Store a Permanent Memory via /remember

Save a project convention or preference that persists across sessions.

```text
/remember Always use conventional commits: feat(), fix(), chore(), docs()
```

This creates a **pinned** memory entry that won't decay over time. Pi automatically categorizes it (preference, lesson, decision, pattern, mistake, or done) and stores it in the topic-based memory system.

```text
/remember We deploy to staging via: make deploy-staging ENV=stg
/remember The payments service is owned by team-billing — always tag them on payment PRs
/remember Never use SELECT * in production queries — always specify columns
```

- Pinned memories have maximum stability score and never expire
- Use `/remember` for hard rules; let pi's auto-extraction handle soft preferences (e.g., "I prefer tabs over spaces" said in conversation)
- View stored memories with `memory_search` or `/dream` for consolidation

See [Working with Project Memory](memory-system.html) for the full memory system guide.

## Create a Multi-Agent Prompt Template with Chain

Build a prompt that runs multiple agents in sequence, passing results between them.

```markdown
<!-- File: .pi/prompts/refactor-safely.md -->
---
description: "Scout → plan → refactor → test a component — /refactor-safely <component>"
argument-hint: "<component>"
---

## Raw Arguments

```text
$ARGUMENTS
```

> **Bug Reporting Policy:** If you encounter ANY error, unexpected behavior, or reproducible bug while executing this command — DO NOT work around it silently. Ask the user: "Should I create a GitHub issue for this?" Route to `myk-org/pi-config` for prompt/extension issues, or to the relevant tool's repository for CLI issues.

# Safe Refactor

Use the subagent tool with a chain of 4 agents:

1. **scout** — Find all files, functions, and tests related to the component described above.
   Return file paths, key functions, import chains, and test coverage.

2. **planner** — Based on {previous}, create a refactoring plan:
   - Files to modify and why
   - New abstractions to introduce
   - Breaking changes and migration steps
   - What tests need updating

3. **worker** — Based on {previous}, execute the refactoring:
   - Make all code changes
   - Update imports across the codebase
   - Keep backward compatibility where noted in the plan

4. **test-automator** — Based on {previous}, verify and update tests:
   - Run existing tests, fix any failures caused by the refactoring
   - Add tests for new abstractions
   - Ensure coverage doesn't decrease
```

The `{previous}` placeholder is automatically replaced with the output of the preceding agent in the chain. See [Using Slash Commands and Prompt Templates](slash-commands.html) for more on how prompt templates interact with the orchestrator.

## Set Up a Project-Scoped .gitignore for Pi Files

Ensure pi's working files don't leak into your repository.

```gitignore
# Add to your project's .gitignore
.pi/
```

The `.pi/` directory contains all pi state — memory, settings, skills, agents, temp files, and async worker data. It should always be gitignored. The container entrypoint adds this automatically, but for native installs, add it manually.

> **Tip:** If you need to version-control your project agents or prompts (so teammates share them), move them to a committed directory and symlink:
> ```bash
> # Version-controlled agents
> mkdir -p .agents/
> ln -s ../.agents .pi/agents
> ```

## Related Pages

- [Specialist Agents Reference](agents-reference.html)
- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Working with Project Memory](memory-system.html)

---

Source: agents-reference.md

# Specialist Agents Reference

This page documents all 24 specialist agents bundled with pi-config. Each agent is a markdown file in the `agents/` directory with YAML frontmatter defining its name, description, tools, and optional model override.

> **Note:** The orchestrator never performs code changes directly — it delegates all work to these specialist agents via the `subagent` tool. See [Understanding Agent Routing and Delegation](agent-routing.html) for how routing decisions are made.

## Agent Discovery and Loading

Agents are discovered from three directories in priority order (later overrides earlier by name):

| Priority | Source | Directory | Label |
|----------|--------|-----------|-------|
| 1 (lowest) | Package-bundled | `<pi-config>/agents/` | `package` |
| 2 | User-defined | `~/.pi/agent/agents/` | `user` |
| 3 (highest) | Project-local | `<project>/.pi/agents/` | `project` |

The `agentScope` parameter on the `subagent` tool controls which directories are searched:

| Scope | Package | User | Project |
|-------|---------|------|---------|
| `"user"` (default) | ✅ | ✅ | ❌ |
| `"project"` | ✅ | ❌ | ✅ |
| `"both"` | ✅ | ✅ | ✅ |

## Agent Frontmatter Schema

Every agent markdown file uses YAML frontmatter with these fields:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | ✅ | Unique agent identifier used in routing and `subagent` calls |
| `description` | string | ✅ | One-line description of the agent's purpose |
| `tools` | string | ❌ | Comma-separated list of tools the agent can use (e.g., `read, write, edit, bash`) |
| `model` | string | ❌ | Model override — uses this model instead of the parent session's model |
| `provider` | string | ❌ | Provider override — uses this provider instead of the parent session's provider |

```yaml
---
name: my-agent
description: What this agent does — one sentence.
tools: read, write, edit, bash
model: claude-haiku-4-5
---
```

## Async-Only Agents

Three agents are enforced to run only in async mode (`async: true`). Sync calls to these agents are automatically promoted to async by `subagent-tool.ts`. Chain mode is rejected entirely for these agents.

| Agent | Reason |
|-------|--------|
| `code-reviewer-quality` | Long-running review — would block the session |
| `code-reviewer-guidelines` | Long-running review — would block the session |
| `code-reviewer-security` | Long-running review — would block the session |

See [Running the Automated Code Review Loop](code-review-loop.html) for the full review workflow.

## Routing Table

The orchestrator routes tasks to agents based on intent, not just file type. The full routing table is defined in `rules/10-agent-routing.md`.

| Domain | Agent | Routing Trigger |
|--------|-------|-----------------|
| Python (.py) | `python-expert` | Python code creation, modification, testing |
| Go (.go) | `go-expert` | Go code creation, modification, testing |
| Frontend (JS/TS/React/Vue/Angular) | `ts-expert` | JavaScript/TypeScript/frontend work |
| Java (.java) | `java-expert` | Java code, Spring Boot, Maven/Gradle |
| Shell scripts (.sh) | `bash-expert` | Bash/Zsh/POSIX shell scripting |
| Markdown (.md) | `technical-documentation-writer` | Documentation authoring |
| Docker | `docker-expert` | Dockerfiles, containers, images |
| Kubernetes/OpenShift | `kubernetes-expert` | K8s manifests, Helm, GitOps |
| Jenkins/CI/Groovy | `jenkins-expert` | Jenkinsfiles, CI/CD pipelines |
| Git operations (local) | `git-expert` | Commits, branches, merges, rebases |
| GitHub (PRs, issues, releases) | `github-expert` | GitHub platform operations via `gh` CLI |
| Tests | `test-automator` | Test suite creation and CI configuration |
| Debugging | `debugger` | Error diagnosis and root cause analysis |
| API docs | `api-documenter` | OpenAPI specs, SDK docs |
| Security audits | `security-auditor` | External repo security evaluation |
| External library docs | `docs-fetcher` | Fetching docs for React, FastAPI, etc. |
| No specialist match | `worker` | General-purpose fallback |

> **Tip:** Routing is by *intent*, not tool. Running Python tests routes to `python-expert`, not `bash-expert`. Creating a PR routes to `github-expert`, not `git-expert`.

---

## Language Specialist Agents

### python-expert

| Property | Value |
|----------|-------|
| **Name** | `python-expert` |
| **Description** | Python code creation, modification, refactoring, and fixes. Specializes in idiomatic Python, async/await, testing, and modern Python development. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Enforces `uv`/`uvx` — never uses `python`, `pip`, or `pip3` directly
- Type hints on all public functions
- Uses `pytest` for testing with >90% coverage target
- Formats with `ruff`/`black`, lints with `ruff check`

```text
subagent(agent="python-expert", task="Add retry logic to the API client in src/client.py", cwd="/project", estimatedSeconds=15)
```

### go-expert

| Property | Value |
|----------|-------|
| **Name** | `go-expert` |
| **Description** | Go code creation, modification, refactoring, and fixes. Specializes in goroutines, channels, modules, testing, and high-performance Go. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Idiomatic Go with proper error wrapping (`fmt.Errorf("...: %w", err)`)
- Context propagation through call chains
- Table-driven tests with `-race` flag
- Linting via `golangci-lint`

```text
subagent(agent="go-expert", task="Implement the UserService with CRUD operations", cwd="/project", estimatedSeconds=20)
```

### ts-expert

| Property | Value |
|----------|-------|
| **Name** | `ts-expert` |
| **Description** | TypeScript, JavaScript, and frontend framework development (React/Vue/Angular/CSS). UI design, component creation, and modern web technologies. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Covers JavaScript, TypeScript, React, Vue, Angular, CSS
- Frontend testing with Jest, Vitest, Cypress, Playwright
- Build tooling: Vite, Webpack, esbuild

```text
subagent(agent="ts-expert", task="Create a React component for the settings panel", cwd="/project", estimatedSeconds=15)
```

### java-expert

| Property | Value |
|----------|-------|
| **Name** | `java-expert` |
| **Description** | Java code creation, modification, refactoring, and fixes. Specializes in Spring Boot, Maven, Gradle, JUnit testing, and enterprise applications. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Targets Java 17+ (records, sealed classes, pattern matching)
- Spring ecosystem: Boot, MVC, Data, Security, WebFlux
- Build tools: Maven, Gradle (Kotlin DSL)
- Testing: JUnit 5, Mockito, TestContainers
- Logging with SLF4J, JavaDoc on public APIs

```text
subagent(agent="java-expert", task="Add Spring Security OAuth2 configuration", cwd="/project", estimatedSeconds=20)
```

### bash-expert

| Property | Value |
|----------|-------|
| **Name** | `bash-expert` |
| **Description** | Bash and shell scripting creation, modification, refactoring, and fixes. Specializes in Bash, Zsh, POSIX shell, automation scripts, and system administration. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Defensive scripting: `set -euo pipefail`
- Proper quoting: always `"$var"`
- POSIX portability when possible, bash-specific when needed
- Must pass `shellcheck` with no warnings
- Includes trap for cleanup

```text
subagent(agent="bash-expert", task="Create a deployment script with rollback support", cwd="/project", estimatedSeconds=15)
```

---

## Infrastructure Agents

### docker-expert

| Property | Value |
|----------|-------|
| **Name** | `docker-expert` |
| **Description** | Docker and container-related tasks including Dockerfile creation, container orchestration, image optimization, and containerization workflows. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Multi-stage builds, BuildKit, Buildx
- Security: non-root users, minimal base images, image scanning (Trivy)
- Pinned base image versions (never `:latest`)
- Orchestration: Docker Compose, Docker Swarm
- Alternative runtimes: Podman, Buildah, Skopeo

```text
subagent(agent="docker-expert", task="Optimize the Dockerfile for smaller image size", cwd="/project", estimatedSeconds=15)
```

### kubernetes-expert

| Property | Value |
|----------|-------|
| **Name** | `kubernetes-expert` |
| **Description** | Kubernetes-related tasks including cluster management, workload deployment, service mesh, and cloud-native orchestration. Specializes in K8s, OpenShift, Helm, and GitOps. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Declarative/GitOps approach (ArgoCD, Flux)
- Security: RBAC, NetworkPolicies, Pod Security Standards
- Observability: Prometheus, Grafana
- Resource requests/limits, liveness/readiness probes
- Platforms: OpenShift, EKS, GKE, AKS, k3s
- Package management: Helm, Kustomize
- Manifests validated with kubeval/kubeconform

```text
subagent(agent="kubernetes-expert", task="Create Helm chart for the API service with HPA", cwd="/project", estimatedSeconds=20)
```

### jenkins-expert

| Property | Value |
|----------|-------|
| **Name** | `jenkins-expert` |
| **Description** | Jenkins-related code including CI/CD pipelines, Jenkinsfiles, Groovy scripts, and build automation. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Declarative and scripted pipelines
- Groovy shared libraries
- Never hardcodes credentials — uses `withCredentials`
- Uses `@NonCPS` for non-serializable code
- JCasC (Jenkins Configuration as Code)
- Parallel stages, timeouts, post-action handling

```text
subagent(agent="jenkins-expert", task="Add a parallel testing stage to the Jenkinsfile", cwd="/project", estimatedSeconds=15)
```

---

## Version Control Agents

### git-expert

| Property | Value |
|----------|-------|
| **Name** | `git-expert` |
| **Description** | Local git operations including commits, branching, merging, rebasing, stash, and resolving git issues. Never uses --no-verify. For GitHub platform operations (PRs, issues, releases), use github-expert instead. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Executes git commands immediately — no confirmation needed
- Never commits or pushes to `main`/`master`
- Never uses `--no-verify`
- Never uses `git add .` — always stages specific files
- Commits via `echo -e "title\n\nbody" | git commit -F -`
- Branch prefixes: `feature/`, `fix/`, `hotfix/`, `refactor/`
- Does not run tests — asks orchestrator if tests passed before pushing
- Does not fix code — reports pre-commit hook failures

**Scope boundary:** Handles commit, branch, merge, rebase, stash, cherry-pick, log, diff, status, config. Delegates PRs, issues, releases, workflows to `github-expert`.

```text
subagent(agent="git-expert", task="Create branch fix/issue-42-null-check and commit the changes", cwd="/project", estimatedSeconds=10)
```

### github-expert

| Property | Value |
|----------|-------|
| **Name** | `github-expert` |
| **Description** | GitHub platform operations including PRs, issues, releases, repos, and workflows. Uses the gh CLI for all GitHub API interactions. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Uses `gh` CLI exclusively for GitHub API interactions
- Executes commands immediately — no confirmation needed
- Never pushes to `main`/`master`, never commits to merged branches
- Does not run tests — delegates to `test-runner` first
- Returns URLs when creating PRs, issues, releases
- Uses `--json` flag for structured data

**Scope boundary:** Handles PRs, issues, releases, repos, workflows, GitHub API. Delegates commit, branch, merge, rebase to `git-expert`.

```text
subagent(agent="github-expert", task="Create a PR from fix/issue-42-null-check to main with title 'Fix null pointer in UserService'", cwd="/project", estimatedSeconds=10)
```

---

## Code Review Agents

All three code review agents run in parallel as part of the mandatory code review loop. They are all enforced as async-only. See [Running the Automated Code Review Loop](code-review-loop.html) for the full workflow.

> **Warning:** These agents only **review** code — they never modify files. The orchestrator delegates fixes to the appropriate language specialist based on review findings.

### code-reviewer-quality

| Property | Value |
|----------|-------|
| **Name** | `code-reviewer-quality` |
| **Description** | Code review focused on general code quality and maintainability. Reviews for clean code, proper abstractions, DRY, and readability. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | ✅ Yes |

**Review focus:**

- Code readability and clarity
- Proper abstractions and encapsulation
- DRY violations
- Code complexity (cognitive and cyclomatic)
- Error handling patterns
- Observability and debugging (silent error swallowing, missing logging, poor error context, opaque async code)
- Dead code and unused imports

**Reads project guidelines** (`AGENTS.md` or `CLAUDE.md`) before every review.

**Output format:**

```text
[SEVERITY] file:line — Description
  Suggestion: What to change and why
```

Severity levels: `[CRITICAL]`, `[WARNING]`, `[SUGGESTION]`

Approval output: `"No quality issues found. Code approved."`

### code-reviewer-guidelines

| Property | Value |
|----------|-------|
| **Name** | `code-reviewer-guidelines` |
| **Description** | Code review focused on project guidelines and style adherence. Reviews for AGENTS.md compliance, naming conventions, and project patterns. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | ✅ Yes |

**Review focus:**

- AGENTS.md / CLAUDE.md compliance
- **Documentation updates** — flags missing AGENTS.md/README.md updates as `[CRITICAL]`
- Project-specific coding standards
- Naming conventions, file/folder structure consistency
- Commit message and branch naming conventions
- Import ordering and grouping
- Configuration file formats

**Reads project guidelines** (`AGENTS.md` or `CLAUDE.md`) before every review.

**Output format:**

```text
[SEVERITY] file:line — Description
  Rule: Which guideline is violated
  Suggestion: How to fix
```

Approval output: `"Code follows all project guidelines. Approved."`

### code-reviewer-security

| Property | Value |
|----------|-------|
| **Name** | `code-reviewer-security` |
| **Description** | Code review focused on bugs, logic errors, and security vulnerabilities. Reviews for correctness, edge cases, and potential exploits. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | ✅ Yes |

**Review focus:**

- Logic errors and off-by-one bugs
- Null/undefined reference risks
- Race conditions and concurrency issues
- Input validation and sanitization
- SQL injection, XSS, CSRF vulnerabilities
- Hardcoded secrets or credentials
- Path traversal and file access
- Resource leaks (unclosed connections/files)
- Edge cases and boundary conditions

**Reads project guidelines** (`AGENTS.md` or `CLAUDE.md`) before every review.

**Output format:**

```text
[SEVERITY] file:line — Description
  Risk: What could go wrong
  Suggestion: How to fix
```

Approval output: `"No bugs or security issues found. Code approved."`

---

## Testing Agents

### test-automator

| Property | Value |
|----------|-------|
| **Name** | `test-automator` |
| **Description** | Create comprehensive test suites with unit, integration, and e2e tests. Sets up CI pipelines, mocking strategies, and test data. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Follows test pyramid: many unit, fewer integration, minimal E2E
- Arrange-Act-Assert pattern
- Tests behavior, not implementation
- Deterministic tests — no flakiness
- Follows mandatory TDD discipline (RED-GREEN-REFACTOR cycle)
- Supports Jest, pytest, and framework-appropriate tools

```text
subagent(agent="test-automator", task="Write unit tests for the UserService class in src/services/user.py", cwd="/project", estimatedSeconds=20)
```

### test-runner

| Property | Value |
|----------|-------|
| **Name** | `test-runner` |
| **Description** | Run tests and analyze failures. Returns detailed failure analysis without making fixes. |
| **Tools** | `bash`, `read` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Runs exactly the test command specified
- Never modifies files — analysis and reporting only
- Provides concise failure analysis with actionable fix suggestions
- Returns control promptly after analysis

**Output format:**

```text
✅ Passing: X tests
❌ Failing: Y tests

Failed Test 1: test_name (file:line)
Expected: [brief description]
Actual: [brief description]
Fix location: path/to/file.rb:line
Suggested approach: [one line]

Returning control for fixes.
```

```text
subagent(agent="test-runner", task="Run 'uv run pytest tests/ -v' and analyze any failures", cwd="/project", estimatedSeconds=15)
```

---

## Analysis and Planning Agents

### scout

| Property | Value |
|----------|-------|
| **Name** | `scout` |
| **Description** | Fast codebase reconnaissance. Finds relevant files, functions, and dependencies for a given task. |
| **Tools** | `read`, `bash` |
| **Model Override** | `claude-haiku-4-5` |
| **Async-Only** | No |

> **Note:** This is the only bundled agent with a model override. It uses `claude-haiku-4-5` for fast, low-cost codebase scanning.

**Key behaviors:**

- Uses `grep`, `find`, and `read` for rapid exploration
- Maps file dependencies and imports
- Identifies key functions, classes, and interfaces
- Notes relevant tests and configuration

**Output format:**

```text
## Relevant Files
- path/to/file.py — Description of what it contains

## Key Functions/Classes
- ClassName.method() in file.py:42 — What it does

## Dependencies
- file.py imports from other.py
- external: requests, fastapi

## Tests
- tests/test_file.py — Covers ClassName

## Notes
- Important observations about the codebase structure
```

```text
subagent(agent="scout", task="Find all files related to user authentication", cwd="/project", estimatedSeconds=10)
```

### planner

| Property | Value |
|----------|-------|
| **Name** | `planner` |
| **Description** | Creates detailed implementation plans from codebase context. Does not write code. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Creates plans detailed enough for a worker agent to implement without ambiguity
- Specifies file paths, function names, and line numbers
- Covers edge cases, testing scenarios, and risks
- Read-only — never modifies files

**Output format:**

```text
## Implementation Plan

### Overview
Brief description of what will be changed and why.

### Changes
#### 1. path/to/file.py
- **What:** Description of changes
- **Why:** Rationale
- **Details:** Specific functions/classes to modify
- **Lines:** Approximate line ranges affected

### Edge Cases
1. Edge case → How to handle

### Testing
1. Test scenario — Expected behavior

### Risks
- Potential issue → Mitigation
```

```text
subagent(agent="planner", task="Plan the implementation of rate limiting for the API", cwd="/project", estimatedSeconds=15)
```

### debugger

| Property | Value |
|----------|-------|
| **Name** | `debugger` |
| **Description** | Debugging specialist for errors, test failures, and unexpected behavior. Diagnoses only — does not modify files. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Root cause analysis only — never modifies files
- Follows systematic debugging: investigate → pattern analysis → hypothesis → implementation
- **Rule of Three:** After 3 failed fix attempts, stops and questions the architecture
- Provides fix recommendations with specific file/line references
- The orchestrator delegates actual fixes to the appropriate language specialist

```text
subagent(agent="debugger", task="Diagnose why test_create_user fails with ConnectionRefusedError", cwd="/project", estimatedSeconds=15)
```

---

## Documentation Agents

### technical-documentation-writer

| Property | Value |
|----------|-------|
| **Name** | `technical-documentation-writer` |
| **Description** | Comprehensive, user-focused technical documentation for projects, features, or systems. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- User-first writing — for readers, not developers
- Progressive disclosure: overview → details
- Supports Markdown, MkDocs, Docusaurus, Sphinx
- All code examples verified
- WCAG accessibility, SEO-friendly structure

```text
subagent(agent="technical-documentation-writer", task="Write getting started guide for the CLI tool", cwd="/project", estimatedSeconds=20)
```

### api-documenter

| Property | Value |
|----------|-------|
| **Name** | `api-documenter` |
| **Description** | Create OpenAPI/Swagger specs, generate SDKs, and write developer documentation. Handles versioning, examples, and interactive docs. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- OpenAPI 3.0/Swagger specification writing
- SDK generation and client library documentation
- Interactive documentation (Postman/Insomnia)
- Code examples in multiple languages
- Authentication, error codes, and rate limiting documentation

```text
subagent(agent="api-documenter", task="Generate OpenAPI 3.0 spec for the REST API in src/routes/", cwd="/project", estimatedSeconds=20)
```

### docs-fetcher

| Property | Value |
|----------|-------|
| **Name** | `docs-fetcher` |
| **Description** | Fetches current documentation for external libraries and frameworks. Prioritizes llms.txt when available, falls back to web parsing. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Tries `{base_url}/llms-full.txt` first, then `llms.txt`, then HTML parsing
- Uses official docs only — never blog posts or tutorials
- Extracts only relevant sections based on query
- Always cites source URL and content type

> **Warning:** The orchestrator must **never** fetch external documentation directly. All documentation fetching must be delegated to `docs-fetcher`. See [Understanding Agent Routing and Delegation](agent-routing.html).

**Output format:**

```text
## {Library} - {Topic}

**Source:** {url}
**Type:** llms-full.txt | llms.txt | web-parsed

### Relevant Documentation
{extracted content}

### Key Points
- {actionable takeaway}

### Related Links
- [{section name}]({url})
```

```text
subagent(agent="docs-fetcher", task="Fetch React hooks documentation for useEffect cleanup patterns", cwd="/project", estimatedSeconds=10)
```

---

## Security Agent

### security-auditor

| Property | Value |
|----------|-------|
| **Name** | `security-auditor` |
| **Description** | Audits external repositories for security risks before adoption — checks for malicious code, data exfiltration, supply chain risks, and trust signals. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Evaluates **external** third-party repos — not your own code
- Clones target repo to `${PROJECT_TMP_DIR}/` with `--depth 1`
- 8 audit categories: malicious code, data exfiltration, supply chain, filesystem access, network/permissions, trust signals, license compatibility, build integrity
- Reads actual source code — does not guess from file names
- Lists all network endpoints contacted
- Produces structured report with per-category risk levels and a final verdict: `✅ SAFE`, `⚠️ CAUTION`, or `❌ UNSAFE`

```text
subagent(agent="security-auditor", task="Audit https://github.com/example/some-library for security risks before we adopt it", cwd="/project", estimatedSeconds=25)
```

---

## General-Purpose Agents

### reviewer

| Property | Value |
|----------|-------|
| **Name** | `reviewer` |
| **Description** | General code review agent. Reviews code changes for quality, correctness, and style. |
| **Tools** | `read`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- General-purpose reviewer covering correctness, security, quality, performance, and style
- Less specialized than the three dedicated code reviewers
- Useful for quick, single-pass reviews outside the formal review loop

**Output format:**

```text
[SEVERITY] file:line — Description
  Suggestion: How to fix
```

Approval output: `"No issues found. Code approved. ✅"`

```text
subagent(agent="reviewer", task="Quick review of the changes in src/utils.py", cwd="/project", estimatedSeconds=10)
```

### worker

| Property | Value |
|----------|-------|
| **Name** | `worker` |
| **Description** | General-purpose agent for tasks that don't match any specialist. Full capabilities. |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model Override** | None (inherits parent) |
| **Async-Only** | No |

**Key behaviors:**

- Fallback agent when no specialist matches the task
- Full read/write/edit/bash capabilities
- Handles any file type, shell commands, general refactoring
- Reports tasks that would be better handled by a specialist

```text
subagent(agent="worker", task="Rename all occurrences of 'oldName' to 'newName' across the codebase", cwd="/project", estimatedSeconds=15)
```

---

## Agent Capabilities Summary

| Agent | `read` | `write` | `edit` | `bash` | Modifies Files | Model Override |
|-------|--------|---------|--------|--------|-----------------|----------------|
| `api-documenter` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `bash-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `code-reviewer-guidelines` | ✅ | ❌ | ❌ | ✅ | No | — |
| `code-reviewer-quality` | ✅ | ❌ | ❌ | ✅ | No | — |
| `code-reviewer-security` | ✅ | ❌ | ❌ | ✅ | No | — |
| `debugger` | ✅ | ❌ | ❌ | ✅ | No | — |
| `docker-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `docs-fetcher` | ✅ | ❌ | ❌ | ✅ | No | — |
| `git-expert` | ✅ | ❌ | ❌ | ✅ | No (git ops only) | — |
| `github-expert` | ✅ | ❌ | ❌ | ✅ | No (gh ops only) | — |
| `go-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `java-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `jenkins-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `kubernetes-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `planner` | ✅ | ❌ | ❌ | ✅ | No | — |
| `python-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `reviewer` | ✅ | ❌ | ❌ | ✅ | No | — |
| `scout` | ✅ | ❌ | ❌ | ✅ | No | `claude-haiku-4-5` |
| `security-auditor` | ✅ | ❌ | ❌ | ✅ | No | — |
| `technical-documentation-writer` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `test-automator` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `test-runner` | ✅ | ❌ | ❌ | ✅ | No | — |
| `ts-expert` | ✅ | ✅ | ✅ | ✅ | Yes | — |
| `worker` | ✅ | ✅ | ✅ | ✅ | Yes | — |

---

## Adding, Removing, and Overriding Agents

See [Customization and Extension Recipes](customization-recipes.html) for step-by-step instructions on creating custom agents.

### Adding an Agent

1. Create a `.md` file in `agents/` with the required frontmatter (`name`, `description`)
2. Add a routing entry in `rules/10-agent-routing.md`
3. Add the agent name to the list in `rules/50-agent-bug-reporting.md`

### Removing an Agent

1. Delete the agent file from `agents/`
2. Remove the routing entry from `rules/10-agent-routing.md`
3. Remove the agent from `rules/50-agent-bug-reporting.md`

### Overriding a Bundled Agent

Place a `.md` file with the same `name` in the higher-priority directory:

- `~/.pi/agent/agents/` overrides package-bundled agents for all projects
- `<project>/.pi/agents/` overrides both package and user agents for that project

The override completely replaces the original agent definition, including tools, model, and system prompt.

### Adding an Agent to the Async-Only List

Edit the `ASYNC_ONLY_AGENTS` set in `extensions/orchestrator/subagent-tool.ts`:

```typescript
const ASYNC_ONLY_AGENTS = new Set([
  "code-reviewer-quality",
  "code-reviewer-guidelines",
  "code-reviewer-security",
  "your-new-agent",  // add here
]);
```

---

## Related Pages

- [Understanding Agent Routing and Delegation](agent-routing.html) — How the orchestrator decides which agent to invoke
- [Running the Automated Code Review Loop](code-review-loop.html) — The 3-reviewer parallel review workflow
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) — Async agent execution and monitoring
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html) — How `subagent-tool.ts` and `agents.ts` work internally
- [Orchestrator Rules Reference](rules-reference.html) — Full reference for routing rules and orchestrator behavior
- [Command Safety Guards and Enforcement](command-enforcement.html) — Safety restrictions that apply to all agents

## Related Pages

- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)

---

Source: commands-reference.md

# Slash Commands and Extension Commands Reference

This page is the definitive reference for every slash command available in pi-config — both **prompt template commands** (defined in `prompts/`) and **extension commands** (registered by TypeScript extensions in `extensions/`).

For an introduction to how slash commands work and when to use them, see [Using Slash Commands and Prompt Templates](slash-commands.html). For the agents these commands delegate to, see [Specialist Agents Reference](agents-reference.html).

---

## Command Types

| Type | Source | How it works |
|------|--------|--------------|
| **Prompt template** | `prompts/*.md` | Loaded as system-prompt instructions; the AI executes the workflow |
| **Extension command** | `extensions/**/*.ts` | Runs TypeScript handler code directly — no AI roundtrip unless noted |

---

## Prompt Template Commands

### `/implement`

Scouts the codebase, plans, and implements a task using a 3-agent chain.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `task` | string | yes | Description of the task to implement |

**Agent chain:** `scout` → `planner` → `worker`

```text
/implement add pagination to the user list endpoint
```

---

### `/implement-and-review`

Implements a task, runs 3 parallel code reviewers, then fixes all findings.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `task` | string | yes | Description of the task to implement |

**Agent chain:** `worker` → `code-reviewer-quality` + `code-reviewer-guidelines` + `code-reviewer-security` (parallel) → `worker` (fix round)

```text
/implement-and-review refactor the auth middleware to use JWT
```

---

### `/scout-and-plan`

Explores the codebase and produces a detailed implementation plan without making any changes.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `task` | string | yes | Description of what to plan |

**Agent chain:** `scout` → `planner`

```text
/scout-and-plan migrate the database layer from SQLite to PostgreSQL
```

---

### `/pr-review`

Reviews a GitHub PR using 3 parallel review agents and posts inline comments.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `PR number or URL` | string | no | Auto-detect from current branch | The PR to review |

**Phases:** PR detection → clone & checkout → past review check → 3 parallel reviewers → merge findings → user selection → post comments → store comments → summary

**Prerequisites:** `myk-pi-tools`, `gh` CLI

```text
/pr-review
/pr-review 123
/pr-review https://github.com/owner/repo/pull/123
```

---

### `/review-local`

Reviews uncommitted changes or changes compared to a branch using 3 parallel review agents.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `base branch` | string | no | `HEAD` (uncommitted changes) | Branch to compare against |

```text
/review-local
/review-local main
/review-local feature/auth
```

---

### `/review-handler`

Processes all review sources (human, Qodo, CodeRabbit) from the current branch's PR.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `--autorabbit` | flag | no | Auto-fix CodeRabbit comments in a polling loop |
| `--autoqodo` | flag | no | Auto-fix Qodo comments in a polling loop |
| `PR URL` | string | no | Specific review URL to process |

**Phases:** Fetch reviews → user decisions → execute fixes → test → commit & push → post replies → auto polling loop (if `--autorabbit`/`--autoqodo`)

**Prerequisites:** `myk-pi-tools`, `gh` CLI

> **Note:** `--autorabbit` and `--autoqodo` are command-level flags. They are **never** passed to the `myk-pi-tools` CLI.

```text
/review-handler
/review-handler --autorabbit
/review-handler --autoqodo
/review-handler --autorabbit --autoqodo
/review-handler https://github.com/owner/repo/pull/123#pullrequestreview-456
```

---

### `/review-handler-status`

Shows live status of running review-handler agents (autorabbit/autoqodo).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

Finds running `reviews poll` agents via `/async-status`, then generates an HTML status report per PR.

```text
/review-handler-status
```

---

### `/release`

Creates a GitHub release with automatic changelog generation from conventional commits.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `version` | string | no | Auto-detect from commits | Explicit version (e.g., `1.17.1`) |
| `--dry-run` | flag | no | — | Preview without creating |
| `--prerelease` | flag | no | — | Mark as prerelease |
| `--draft` | flag | no | — | Create draft release |
| `--target` | string | no | Current branch | Target branch for the release |
| `--tag-match` | string | no | — | Filter tags by pattern |

**Phases:** Validation → version detection → changelog → user approval → version bump → create release → summary

**Prerequisites:** `myk-pi-tools`, `gh` CLI

```text
/release
/release 2.0.0
/release --dry-run
/release --prerelease
/release --draft
/release --target v2.10
/release --target main --tag-match "v2.*"
```

---

### `/external-ai`

Runs a prompt through an external AI CLI (Cursor, Claude, Gemini) via `ai-cli-runner`.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `agent` | string | no | Last saved agent | Provider name: `cursor`, `claude`, `gemini`, or comma-separated list |
| `--model` | string | no | Provider default | Model ID (e.g., `gpt-5.4-high`, `claude-4.6-opus-max-thinking`) |
| `--fix` | flag | no | — | Allow the agent to modify files |
| `--peer` | flag | no | — | AI-to-AI peer review loop |
| `--resume` | flag | no | — | Continue most recent session |
| `prompt` | string | yes | — | The prompt to send |

**Default models per provider:**

| Provider | Default Model |
|----------|---------------|
| `cursor` | `composer-2-fast` |
| `claude` | `claude-sonnet-4-6` |
| `gemini` | `gemini-2.5-flash` |

**Flag constraints:**

- `--fix` and `--peer` are mutually exclusive
- `--resume` and `--peer` are mutually exclusive
- `--fix` requires a single agent (not multi-agent)

**Prerequisites:** `myk-pi-tools`

> **Tip:** For providers not listed here (codex, copilot, droid, kiro, etc.), use `/acpx-prompt` instead.

```text
/external-ai cursor fix the tests
/external-ai claude --model claude-4.6-opus-max-thinking review this code
/external-ai cursor --fix fix the code quality issues
/external-ai cursor --peer review this code
/external-ai cursor,claude review this code
/external-ai cursor --resume explain the last change
/external-ai --peer review this
```

For details on external AI workflows, see [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html).

---

### `/refine-review`

Refines pending GitHub PR review comments with AI before submitting.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `PR URL` | string | yes | GitHub PR URL to refine pending comments for |

**Phases:** Fetch pending review → refine comments → side-by-side preview → user approval → update JSON → submit decision → execute → store comments → summary

**Prerequisites:** `myk-pi-tools`

```text
/refine-review https://github.com/owner/repo/pull/123
```

---

### `/query-db`

Queries the reviews database for analytics and insights about PR review history.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `query` | string | yes | Subcommand or SQL query |

**Subcommands:**

| Subcommand | Description |
|------------|-------------|
| `stats --by-source` | Address rate by source (human vs AI) |
| `stats --by-reviewer` | Statistics by individual reviewer |
| `patterns --min <N>` | Find recurring dismissed patterns (minimum N occurrences) |
| `dismissed --owner <X> --repo <Y>` | All dismissed comments for a repo |
| `query "<SQL>"` | Run a custom SELECT query |
| `find-similar` | Find similar dismissed comments (JSON via stdin) |

> **Note:** Only `SELECT` statements and CTEs are allowed — the database is read-only for analytics.

**Prerequisites:** `myk-pi-tools`

```text
/query-db stats --by-source
/query-db stats --by-reviewer
/query-db patterns --min 2
/query-db query "SELECT * FROM comments WHERE status='skipped' LIMIT 10"
```

---

### `/remember`

Saves a memory as a pinned entry for future sessions.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `what to remember` | string | yes | The memory to save |

The AI determines the best category (`lesson`, `decision`, `mistake`, `pattern`, `done`, `preference`) and saves it as a pinned memory via `myk-pi-tools memory add`.

```text
/remember always use ruff instead of flake8 for linting
/remember the API rate limit is 100 requests per minute
```

For details on the memory system, see [Working with Project Memory](memory-system.html).

---

### `/coderabbit-rate-limit`

Handles CodeRabbit rate limits by waiting for the cooldown period and re-triggering the review.

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `PR number or URL` | string | no | Auto-detect from current branch | The PR to handle |

**Prerequisites:** `myk-pi-tools`, `gh` CLI

```text
/coderabbit-rate-limit
/coderabbit-rate-limit 123
/coderabbit-rate-limit https://github.com/owner/repo/pull/123
```

---

### `/create-coms-feature-manager`

Generates a project-specific coms feature manager prompt from the template.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments — interactive workflow |

Creates `.pi/prompts/coms-feature-manager.md` customized for the current project. The feature manager coordinates between a manager agent (reviewer) and a coder agent (implementer) via coms.

```text
/create-coms-feature-manager
```

For details on coms, see [Communicating Between Pi Sessions](inter-agent-communication.html).

---

### `/create-skill`

Creates a reusable skill from a successful workflow in the current conversation.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `name` | string | no | Skill name (prompted if not provided) |

**Name format:** lowercase, hyphenated, max 64 characters (e.g., `debug-container-build`).

The AI asks whether to create the skill as **Global** (`~/.agents/skills/`) or **Project** (`.pi/skills/`) scoped.

```text
/create-skill debug-container-build
/create-skill
```

For details on customization, see [Customization and Extension Recipes](customization-recipes.html).

---

## Extension Commands

### `/btw`

Ask a quick side question without polluting conversation history. Uses a lightweight LLM call with no tool access — answers based on conversation context only.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `question` | string | yes | The side question to ask |

The answer displays in a scrollable overlay. Press `Esc`, `Space`, or `q` to dismiss. Use `↑`/`↓`/`j`/`k` to scroll, `PgUp`/`PgDn` for fast scroll.

```text
/btw what was the name of the function we changed earlier?
/btw which branch am I on?
```

---

### `/status`

Shows a unified session status snapshot. Direct handler — no AI roundtrip.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

**Displays:**

- Async agents (count and names)
- Cron tasks (count, schedule, last run)
- Git status (branch, changed files count)
- Container indicator (if running in Docker)
- Loaded resources (context files, skills, tools, guidelines)

```text
/status
```

---

### `/async-status`

Shows status of background async agents with a live output viewer.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

If agents are running, presents a selection list. Selecting an agent opens a live scrollable overlay showing the agent's output in real-time. Press `Esc` or `q` to close.

```text
/async-status
```

For details on async agents, see [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

---

### `/async-kill`

Kills running async agent(s) by name, ID, or all.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `target` | string | no | Agent name, ID, or `all`. If omitted, shows interactive selection |

Kills the entire process tree (parent + children) using `SIGKILL`.

```text
/async-kill
/async-kill all
/async-kill worker-abc123
```

---

### `/cron`

Schedules recurring tasks. Supports both natural language and structured subcommands.

| Subcommand | Description |
|------------|-------------|
| `list` | List scheduled tasks for this session |
| `list-all` | List cron tasks across all active pi sessions |
| `remove <id>` | Remove a task by ID (aliases: `rm`, `delete`, `kill`) |
| `<natural language>` | AI parses and creates a scheduled task |

**Subcommand: `list`**

```text
/cron list
```

**Subcommand: `list-all`**

```text
/cron list-all
```

**Subcommand: `remove`**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `id` | number | yes | Task ID(s) to remove (space-separated for multiple) |

```text
/cron remove 1
/cron remove 1 2 3
/cron kill 5
```

**Natural language scheduling:**

The AI parses the request and calls the `cron_manage` tool with structured parameters.

| Parameter (tool) | Type | Description |
|-------------------|------|-------------|
| `interval_seconds` | number | Run every N seconds (minimum: 10) |
| `at_hour` | number | Hour (0–23) for daily schedule |
| `at_minute` | number | Minute (0–59) for daily schedule |
| `task` | string | What to execute — a prompt or `/slash-command` |
| `description` | string | Human-readable description |

- Tasks starting with `/` execute as slash commands
- Other tasks run as async `worker` agents

```text
/cron every 30 minutes check for new issues
/cron at 09:00 run /review-handler --autorabbit
/cron every 2h run git fetch --all
```

> **Note:** Cron tasks are process-scoped — they survive `/reload` and `/new` but stop on pi exit. Not available in one-shot modes (`print`/`json`).

For details, see [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

---

### `/dream`

Triggers memory consolidation immediately as a background task.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

Spawns a fire-and-forget `worker` agent that reads session history, extracts durable knowledge, and writes topic files under `.pi/memory/topics/`.

```text
/dream
```

---

### `/dream-auto`

Toggles automatic memory dreaming (runs every 3 hours and on session end).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `on` or `off` | string | no | Enable or disable. If omitted, shows current status |

The dream interval is configurable via the `dream_interval_hours` project setting or `PI_DREAM_INTERVAL_HOURS` env var (range: 0.5–24 hours, default: 3).

```text
/dream-auto on
/dream-auto off
/dream-auto
```

For details on memory consolidation, see [Working with Project Memory](memory-system.html).

---

### `/coms`

Manages P2P agent communication between pi sessions.

| Subcommand | Description |
|------------|-------------|
| `start` | Start P2P communication |
| `stop` | Stop coms |
| `status` | Show coms status |

**Start options:**

| Flag | Type | Description |
|------|------|-------------|
| `--name` | string | Agent name |
| `--purpose` | string | Agent purpose description |
| `--project` | string | Project namespace (default: derived from cwd) |
| `--color` | string | Hex color `#RRGGBB` |
| `--explicit` | flag | Hide from auto-discovery |

```text
/coms start
/coms start --name reviewer --purpose "code review"
/coms stop
/coms status
```

---

### `/coms-net`

Manages networked agent communication with a hub server.

| Subcommand | Description |
|------------|-------------|
| `start` | Start local server and connect |
| `connect` | Connect to a running server |
| `disconnect` | Disconnect from server (keep server running) |
| `stop` | Stop coms-net and kill server |
| `status` | Show coms-net and server status |

**Start options:**

| Flag | Type | Description |
|------|------|-------------|
| `--name` | string | Agent name |
| `--purpose` | string | Agent purpose description |
| `--project` | string | Project namespace (default: derived from cwd) |
| `--color` | string | Hex color `#RRGGBB` |
| `--explicit` | flag | Hide from auto-discovery |
| `--port` | string | Server port (default: OS-assigned) |
| `--host` | string | Server bind address (e.g., `0.0.0.0` for LAN) |

**Connect options:**

| Flag | Type | Description |
|------|------|-------------|
| `--name` | string | Agent name |
| `--purpose` | string | Agent purpose description |
| `--project` | string | Project namespace |
| `--color` | string | Hex color `#RRGGBB` |
| `--explicit` | flag | Hide from auto-discovery |
| `--url` | string | Hub server URL |
| `--auth-token` | string | Bearer token for the hub |

> **Note:** `start` auto-manages the hub server (spawns via Bun if not already running). `connect` connects to an existing server without managing its lifecycle. Use `disconnect` when you didn't start the server; use `stop` when you did.

```text
/coms-net start
/coms-net start --name planner --port 8080
/coms-net connect --url http://192.168.1.5:8080 --auth-token mytoken
/coms-net disconnect
/coms-net stop
/coms-net status
```

For details on inter-agent communication, see [Communicating Between Pi Sessions](inter-agent-communication.html).

---

### `/pidash`

Manages the pidash web dashboard daemon.

| Subcommand | Description |
|------------|-------------|
| `start` | Start the pidash server |
| `stop` | Stop the pidash server |
| `restart` | Restart the pidash server |
| `status` | Show server status (default when no argument) |

**Default port:** `19190` (override with `PI_PIDASH_PORT` env var)

**Status output includes:** server running/stopped, port, extension connected/disconnected, URL.

> **Note:** Disable pidash entirely by setting `PI_PIDASH_ENABLE=false`.

```text
/pidash start
/pidash stop
/pidash restart
/pidash status
/pidash
```

For details on the web dashboard, see [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html).

---

### `/pidiff`

Manages the pidiff diff viewer daemon.

| Subcommand | Description |
|------------|-------------|
| `start` | Start the pidiff server |
| `stop` | Stop the pidiff server |
| `restart` | Restart the pidiff server |
| `status` | Show server status (default when no argument) |

**Default port:** `19290` (override with `PI_PIDIFF_PORT` env var)

> **Note:** Disable pidiff entirely by setting `PI_PIDIFF_ENABLE=false`.

```text
/pidiff start
/pidiff stop
/pidiff restart
/pidiff status
```

For details on the diff viewer, see [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html).

---

### `/repair`

Repairs a broken session by fixing orphaned tool calls that break API requests.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

Scans the session file for tool calls on the active branch that have no corresponding tool result. Injects synthetic `toolResult` entries with error messages to satisfy API requirements, then re-parents subsequent entries. Reports the number of orphans found and patched.

```text
/repair
```

---

### `/nvim-changed-files`

Sends git changed files to Neovim's quickfix list. Only available when running inside a Neovim terminal (`NVIM` env var is set).

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

Detects changed files relative to `origin/main` (or `HEAD` if on main) and opens the quickfix window in the parent Neovim instance.

```text
/nvim-changed-files
```

---

### `/external-ai-models-refresh`

Clears cached AI CLI model lists and re-fetches from all providers.

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| *(none)* | — | — | No arguments |

Refreshes the autocomplete model cache for `cursor`, `claude`, and `gemini` providers.

```text
/external-ai-models-refresh
```

---

## Quick Reference Table

| Command | Type | Arguments | Description |
|---------|------|-----------|-------------|
| `/implement` | Prompt | `<task>` | Scout → plan → implement |
| `/implement-and-review` | Prompt | `<task>` | Implement → review → fix |
| `/scout-and-plan` | Prompt | `<task>` | Scout → plan (no changes) |
| `/pr-review` | Prompt | `[PR#/URL]` | Review a GitHub PR |
| `/review-local` | Prompt | `[branch]` | Review local changes |
| `/review-handler` | Prompt | `[--autorabbit] [--autoqodo]` | Process PR review comments |
| `/review-handler-status` | Prompt | — | Status of running review handlers |
| `/release` | Prompt | `[version] [flags]` | Create GitHub release |
| `/external-ai` | Prompt | `<agent> [flags] <prompt>` | Route to external AI CLI |
| `/refine-review` | Prompt | `<PR URL>` | Polish pending review comments |
| `/query-db` | Prompt | `<query>` | Query review database |
| `/remember` | Prompt | `<memory>` | Save a pinned memory |
| `/coderabbit-rate-limit` | Prompt | `[PR#/URL]` | Handle CodeRabbit rate limits |
| `/create-coms-feature-manager` | Prompt | — | Generate coms feature manager |
| `/create-skill` | Prompt | `[name]` | Save workflow as reusable skill |
| `/btw` | Extension | `<question>` | Quick side question (no tools) |
| `/status` | Extension | — | Session status snapshot |
| `/async-status` | Extension | — | Background agent status |
| `/async-kill` | Extension | `[target]` | Kill async agent(s) |
| `/cron` | Extension | `<subcommand/text>` | Schedule recurring tasks |
| `/dream` | Extension | — | Trigger memory consolidation |
| `/dream-auto` | Extension | `[on/off]` | Toggle auto-dreaming |
| `/coms` | Extension | `start/stop/status` | P2P agent communication |
| `/coms-net` | Extension | `start/connect/...` | Networked agent communication |
| `/pidash` | Extension | `start/stop/restart/status` | Web dashboard daemon |
| `/pidiff` | Extension | `start/stop/restart/status` | Diff viewer daemon |
| `/repair` | Extension | — | Fix orphaned tool calls |
| `/nvim-changed-files` | Extension | — | Send changed files to Neovim |
| `/external-ai-models-refresh` | Extension | — | Refresh AI model cache |

## Related Pages

- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Specialist Agents Reference](agents-reference.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Communicating Between Pi Sessions](inter-agent-communication.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)

---

Source: cli-reference.md

# myk-pi-tools CLI Reference

`myk-pi-tools` is the Python CLI package that provides tooling for the pi orchestrator. It wraps GitHub API operations, review handling, release management, memory persistence, and external AI CLI integration.

**Version:** 3.9.1
**Install:** `pip install myk-pi-tools` (included in pi-config Docker image and native install)
**Entry point:** `myk-pi-tools`
**Requires:** Python ≥ 3.12, GitHub CLI (`gh`) for most commands

```bash
myk-pi-tools --version
myk-pi-tools --help
```

> **Note:** Most subcommands that interact with GitHub require the `gh` CLI to be installed and authenticated. See [Installing and Starting Your First Session](quickstart.html) for setup.

---

## Subcommand Overview

| Subcommand | Description |
|---|---|
| [`memory`](#memory) | Project memory commands — persistent per-repo learning |
| [`pr`](#pr) | PR review and management commands |
| [`release`](#release) | GitHub release commands |
| [`reviews`](#reviews) | Review handling commands (fetch, poll, post, store) |
| [`db`](#db) | Review database query commands |
| [`coderabbit`](#coderabbit) | CodeRabbit rate limit and trigger commands |
| [`ai-cli`](#ai-cli) | AI CLI commands (cursor, claude, gemini) |

---

## `memory`

Project memory commands — persistent per-repo learning. Stores entries as Markdown topic files under `.pi/memory/topics/`.

**Group option:**

| Option | Type | Default | Description |
|---|---|---|---|
| `--file-path` | string | `.pi/memory/topics/` (auto-detected from git root) | Path to memory topics directory |

See [Working with Project Memory](memory-system.html) for how memory integrates with the orchestrator.

### `memory add`

Add a memory entry to the appropriate topic file.

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `-c`, `--category` | choice | yes | — | Memory category: `lesson`, `decision`, `mistake`, `pattern`, `done`, `preference` |
| `-s`, `--summary` | string | yes | — | Short description (one line) |
| `--pinned` | flag | no | `false` | Add to Pinned section (protected from dreaming) |

**Category-to-file mapping:**

| Category | Topic File |
|---|---|
| `preference` | `preferences.md` |
| `lesson` | `lessons.md` |
| `pattern` | `patterns.md` |
| `decision` | `decisions.md` |
| `done` | `completions.md` |
| `mistake` | `mistakes.md` |

```bash
# Add a learned memory
myk-pi-tools memory add -c lesson -s "buildah chown -R skips target dir"

# Add a pinned memory (user-requested, never auto-removed)
myk-pi-tools memory add -c preference -s "Always use uv run" --pinned
```

**Effect:** Appends a line to the topic file. Pinned entries are marked with `*(pinned)*` and are protected from dreaming consolidation.

### `memory show`

Show all memory entries across all topic files.

```bash
myk-pi-tools memory show
```

**Output:** Combined contents of all `.md` files in the topics directory, sorted alphabetically, printed to stdout.

### `memory forget`

Remove a memory entry from its topic file and clean up the corresponding entry in `memory-scores.json`.

| Option | Type | Required | Description |
|---|---|---|---|
| `-c`, `--category` | choice | yes | Memory category: `lesson`, `decision`, `mistake`, `pattern`, `done`, `preference` |
| `-s`, `--summary` | string | yes | Entry text to forget (must match exactly) |

```bash
myk-pi-tools memory forget -c lesson -s "buildah chown -R skips target dir"
myk-pi-tools memory forget -c pattern -s "Container build monitor: old pattern"
```

**Effect:** Removes the matching line from the topic file. Also removes the corresponding hash entry from `.pi/memory/memory-scores.json` if present. Outputs confirmation or "Not found" to stderr.

### `memory migrate`

One-time migration from legacy SQLite database to topic files.

```bash
myk-pi-tools memory migrate
```

**Effect:** Reads all memories from `.pi/memory/memories.db`, writes them as learned entries to topic files, then deletes `memories.db`, `dreams.md`, and `dreams.lock`.

### `memory path`

Print the memory topics directory path.

```bash
myk-pi-tools memory path
# Output: /home/user/project/.pi/memory/topics
```

---

## `pr`

PR review and management commands. All subcommands accept PR references in multiple formats.

**Argument formats (shared across `pr diff` and `pr claude-md`):**

| Format | Example |
|---|---|
| `<owner/repo> <pr_number>` | `myk-org/pi-config 42` |
| `<github_url>` | `https://github.com/myk-org/pi-config/pull/42` |
| `<pr_number>` (auto-detect repo) | `42` |

> **Note:** The `<pr_number>` format requires running from within a git repository with `gh` configured.

### `pr diff`

Fetch PR diff and metadata. Outputs JSON to stdout.

```bash
myk-pi-tools pr diff myk-org/pi-config 42
myk-pi-tools pr diff https://github.com/myk-org/pi-config/pull/42
myk-pi-tools pr diff 42
```

**Output:** JSON object with structure:

```json
{
  "metadata": {
    "owner": "myk-org",
    "repo": "pi-config",
    "pr_number": "42",
    "head_sha": "abc123...",
    "base_ref": "main",
    "title": "PR title",
    "state": "open"
  },
  "diff": "...",
  "files": [
    {
      "path": "src/main.py",
      "status": "modified",
      "additions": 10,
      "deletions": 3,
      "patch": "..."
    }
  ]
}
```

### `pr claude-md`

Fetch `CLAUDE.md` and `AGENTS.md` content for a PR's repository.

Checks local files first (if current repo matches target), then falls back to GitHub API.

```bash
myk-pi-tools pr claude-md myk-org/pi-config 42
myk-pi-tools pr claude-md https://github.com/myk-org/pi-config/pull/42
```

**Files checked:**

| Local Path | Remote Path |
|---|---|
| `./CLAUDE.md` | `CLAUDE.md` |
| `./.claude/CLAUDE.md` | `.claude/CLAUDE.md` |
| `./AGENTS.md` | `AGENTS.md` |
| `./.agents/AGENTS.md` | `.agents/AGENTS.md` |

**Output:** Combined content of all found files to stdout. Empty string if none found.

### `pr store-pr-review`

Store posted PR review comments to the `pr-reviews.db` database. Tracks comments posted by `/pr-review` and `/refine-review` for past-cycle verification on subsequent runs.

| Argument | Type | Required | Description |
|---|---|---|---|
| `JSON_FILE` | string | yes | Path to JSON file with review data |

```bash
myk-pi-tools pr store-pr-review comments.json
```

**Input JSON format:**

```json
{
  "metadata": {
    "owner": "myk-org",
    "repo": "pi-config",
    "pr_number": 42,
    "head_sha": "abc123..."
  },
  "comments": [
    {
      "thread_id": "...",
      "comment_id": 123,
      "path": "file.py",
      "line": 42,
      "body": "Comment text",
      "severity": "WARNING",
      "posted_at": "2026-06-16T12:00:00Z"
    }
  ]
}
```

**Effect:** Inserts the review and all comments into `.pi/data/pr-reviews.db`. If `head_sha` is not provided in metadata, it is auto-detected from the local git HEAD.

**Database schema:** Two tables — `pr_reviews` (PR metadata with head SHA and timestamp) and `pr_comments` (individual comments with thread ID, path, line, body, severity, and posting timestamp).

### `pr post-comment`

Post inline comments to a PR as a single GitHub review with a summary table.

| Argument | Type | Required | Description |
|---|---|---|---|
| `OWNER_REPO` | string | yes | Repository in `owner/repo` format |
| `PR_NUMBER` | string | yes | Pull request number |
| `COMMIT_SHA` | string | yes | The 40-character SHA of the commit to comment on |
| `JSON_FILE` | string | yes | Path to JSON file with comments, or `"-"` for stdin |

```bash
myk-pi-tools pr post-comment myk-org/pi-config 42 abc123def456... comments.json
cat comments.json | myk-pi-tools pr post-comment myk-org/pi-config 42 abc123def456... -
```

**Input JSON format:**

```json
[
  {
    "path": "src/main.py",
    "line": 42,
    "body": "### [CRITICAL] SQL Injection\n\nDescription..."
  },
  {
    "path": "src/utils.py",
    "line": 15,
    "body": "### [WARNING] Missing error handling\n\nDescription..."
  }
]
```

**Severity markers:** The review summary table auto-categorizes comments by severity prefix in the `body`:

| Prefix | Severity |
|---|---|
| `### [CRITICAL]` | Critical issue |
| `### [WARNING]` | Warning |
| `### [SUGGESTION]` | Suggestion (default) |

**Output:** JSON result with `status`, `comment_count`, `posted`, and `failed` arrays.

> **Tip:** Only lines that were modified or added in the PR can receive inline comments. Comments on unchanged lines will fail.

---

## `release`

GitHub release commands. See [Common Workflow Recipes](workflow-recipes.html) for end-to-end release workflows.

### `release info`

Fetch release validation info and commits since last tag. Outputs JSON to stdout.

| Option | Type | Default | Description |
|---|---|---|---|
| `--repo` | string | auto-detected from git context | Repository in `owner/repo` format |
| `--target` | string | auto-detected default branch | Target branch for release |
| `--tag-match` | string | none | Glob pattern to filter tags (e.g., `v2.10.*`) |

```bash
# Auto-detect everything
myk-pi-tools release info

# Specify repo
myk-pi-tools release info --repo myk-org/pi-config

# Filter tags for a version branch
myk-pi-tools release info --target v2.10 --tag-match "v2.10.*"
```

**Validations performed:**
- On target branch check
- Clean working tree check
- Remote sync check (fetch, unpushed/behind counts)

**Version branch auto-detection:** If the current branch matches `vMAJOR.MINOR` (e.g., `v2.10`), the command automatically sets the target and tag-match pattern.

**Commit filtering:** Merge commits, "address review" commits, "chore: checkpoint/bump version" commits, and similar noise are automatically excluded from the output.

**Output:** JSON with `metadata`, `validations`, `last_tag`, `all_tags`, `commits`, `commit_count`, `is_first_release`, `target_branch`, and `tag_match`.

### `release create`

Create a GitHub release.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `OWNER_REPO` | argument | yes | — | Repository in `owner/repo` format |
| `TAG` | argument | yes | — | Release tag (e.g., `v1.3.0`) |
| `CHANGELOG_FILE` | argument | yes | — | Path to file containing release notes |
| `--prerelease` | flag | no | `false` | Mark as pre-release |
| `--draft` | flag | no | `false` | Create as draft |
| `--target` | string | no | — | Target branch for the release |
| `--title` | string | no | tag name | Release title |

```bash
myk-pi-tools release create myk-org/pi-config v1.3.0 CHANGELOG.md
myk-pi-tools release create myk-org/pi-config v2.0.0-rc1 notes.md --prerelease --draft
myk-pi-tools release create myk-org/pi-config v1.3.0 CHANGELOG.md --target main --title "Release 1.3.0"
```

**Output:** JSON with `status`, `tag`, `url`, `prerelease`, and `draft` on success. JSON with `status` and `error` on failure.

> **Warning:** Tags that don't follow semantic versioning (`vX.Y.Z`) trigger a warning but are still accepted.

### `release detect-versions`

Detect version files in the current repository. Scans for well-known version file patterns.

```bash
myk-pi-tools release detect-versions
```

**Supported file types:**

| File | Type Key | Parser |
|---|---|---|
| `pyproject.toml` | `pyproject` | `[project].version` |
| `package.json` | `package_json` | `version` field |
| `setup.cfg` | `setup_cfg` | `[metadata].version` |
| `Cargo.toml` | `cargo` | `[package].version` |
| `build.gradle` / `build.gradle.kts` | `gradle` | `version = "..."` |
| `*/__init__.py`, `*/version.py` | `python_version` | `__version__ = "..."` |

**Output:** JSON with `version_files` array (each with `path`, `current_version`, `type`) and `count`.

> **Note:** Directories like `.git`, `node_modules`, `.venv`, `__pycache__`, `dist`, `build`, and others are automatically excluded from scanning.

### `release bump-version`

Update version strings in detected version files. Does not perform any git operations.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `VERSION` | argument | yes | — | New version string (e.g., `1.2.0`) |
| `--files` | string (repeatable) | no | all detected | Specific files to update |

```bash
# Update all detected version files
myk-pi-tools release bump-version 1.3.0

# Update specific files only
myk-pi-tools release bump-version 1.3.0 --files pyproject.toml --files package.json
```

> **Warning:** The version must NOT start with `v` or `V`. Use `1.3.0`, not `v1.3.0`.

**Output:** JSON with `status`, `version`, `updated` array (with `path`, `old_version`, `new_version`), and `skipped` array.

**Effect:** Writes are atomic (temp file + rename) to prevent corruption.

---

## `reviews`

Review handling commands for the automated review workflow. See [Running the Automated Code Review Loop](code-review-loop.html) for the full workflow.

### `reviews fetch`

Fetch review threads from the current branch's PR.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `REVIEW_URL` | string | no | `""` | Specific review URL for context (e.g., `#pullrequestreview-XXX`) |
| `--include-resolved` | flag | no | `false` | Include resolved threads (adds `is_resolved` field to output) |
| `--user` | string | no | none | Filter threads by author username |
| `--output-dir` | string | yes | — | Directory for output JSON file |

```bash
myk-pi-tools reviews fetch --output-dir /tmp/pi-work
myk-pi-tools reviews fetch "#pullrequestreview-12345" --output-dir /tmp/pi-work
myk-pi-tools reviews fetch --include-resolved --output-dir /tmp/pi-work
myk-pi-tools reviews fetch --user coderabbitai --output-dir /tmp/pi-work
```

**Output:** JSON saved to `<output-dir>/pr-<number>-reviews.json` with structure:

```json
{
  "metadata": { "owner": "...", "repo": "...", "pr_number": "..." },
  "human": [ ... ],
  "qodo": [ ... ],
  "coderabbit": [ ... ]
}
```

Comments are auto-categorized by source based on author username. Each comment includes `thread_id`, `node_id`, `comment_id`, `path`, `line`, `body`, and `priority`.

**Exit codes:** `0` = success, non-zero = failure.

### `reviews poll`

Poll for reviews until new actionable comments appear. Loops internally — does not return on "no new comments."

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `REVIEW_URL` | string | no | `""` | Specific review URL for context |
| `--source` | choice | no | `coderabbit` | Which reviewer to poll for: `coderabbit` or `qodo` |
| `--output-dir` | string | yes | — | Directory for output JSON file |

```bash
myk-pi-tools reviews poll --output-dir /tmp/pi-work
myk-pi-tools reviews poll --source qodo --output-dir /tmp/pi-work
myk-pi-tools reviews poll "#pullrequestreview-12345" --source coderabbit --output-dir /tmp/pi-work
```

**Behavior by source:**

| Source | Behavior |
|---|---|
| `coderabbit` | Checks approval status, handles rate limits (auto-waits + re-triggers), polls until actionable comments appear |
| `qodo` | Fetches and checks for new Qodo comments (no rate limit handling) |

**Output:** Returns `{"approved": true}` if CodeRabbit approved the PR, otherwise returns the fetch JSON.

### `reviews post`

Post replies and resolve review threads from a processed JSON file.

| Argument | Type | Required | Description |
|---|---|---|---|
| `JSON_PATH` | string | yes | Path to JSON file with review data (created by `fetch`, processed by AI) |

```bash
myk-pi-tools reviews post /tmp/pi-work/pr-42-reviews.json
```

**Status handling:**

| Status | Action |
|---|---|
| `addressed` | Post reply and resolve thread |
| `not_addressed` | Post reply and resolve thread |
| `skipped` | Post reply with skip reason, resolve thread (bot sources only; human threads are not resolved) |
| `pending` | Skip (not processed yet) |
| `failed` | Retry posting |

**Effect:** Updates the JSON file with `posted_at` timestamps after successful posting.

### `reviews pending-fetch`

Fetch the authenticated user's pending (unsubmitted) review comments from a PR.

| Argument/Option | Type | Required | Description |
|---|---|---|---|
| `PR_URL` | string | yes | GitHub PR URL (e.g., `https://github.com/owner/repo/pull/123`) |
| `--output-dir` | string | yes | Directory for output JSON file |

```bash
myk-pi-tools reviews pending-fetch https://github.com/myk-org/pi-config/pull/42 --output-dir /tmp/pi-work
```

**Output:** JSON saved to `<output-dir>/pr-<owner>-<repo>-<number>-pending-review.json` with `metadata` and `comments` arrays.

### `reviews pending-update`

Update pending review comment bodies and optionally submit the review.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `JSON_PATH` | argument | yes | — | Path to JSON file with pending review data |
| `--submit` | flag | no | `false` | Submit the review after updating comments |

```bash
# Update comment bodies only
myk-pi-tools reviews pending-update /tmp/pi-work/pr-42-pending-review.json

# Update and submit
myk-pi-tools reviews pending-update /tmp/pi-work/pr-42-pending-review.json --submit
```

**Comment status handling:**
- `accepted`: Update comment body with `refined_body`
- Other statuses: Skip (no update)

**Submit action:** When `--submit` is set, uses the `submit_action` field from the JSON metadata (`COMMENT`, `APPROVE`, or `REQUEST_CHANGES`).

### `reviews status`

Show review status for the current PR. Queries the reviews database and displays all comments across all review cycles.

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `--pr` | integer | no | auto-detected from current branch | PR number |
| `--output-dir` | string | yes | — | Directory for output HTML report |

```bash
myk-pi-tools reviews status --output-dir /tmp/pi-work
myk-pi-tools reviews status --pr 42 --output-dir /tmp/pi-work
```

**Output:** TUI table to stdout and an HTML report saved to `<output-dir>/review-status-<pr>.html`.

### `reviews store`

Store a completed review JSON to the SQLite database for analytics.

| Argument | Type | Required | Description |
|---|---|---|---|
| `JSON_PATH` | string | yes | Path to the completed review JSON file |

```bash
myk-pi-tools reviews store /tmp/pi-work/pr-42-reviews.json
```

**Effect:** Inserts the review and all comments into `.pi/data/reviews.db`. The JSON file is deleted after successful storage.

**Database schema:** Two tables — `reviews` (PR metadata) and `comments` (individual review comments with source, status, reply, priority, timestamps).

---

## `db`

Review database query commands. Operates on the SQLite database at `<git-root>/.pi/data/reviews.db`.

All subcommands support `--db-path` to override the default database location and `--json` for JSON output.

### `db stats`

Get review statistics.

| Option | Type | Default | Description |
|---|---|---|---|
| `--by-source` | flag | `true` (default when neither flag set) | Group by source (human/qodo/coderabbit) |
| `--by-reviewer` | flag | `false` | Group by reviewer author |
| `--json` | flag | `false` | Output as JSON |
| `--db-path` | string | auto-detected | Path to database file |

```bash
myk-pi-tools db stats
myk-pi-tools db stats --by-reviewer
myk-pi-tools db stats --by-source --json
```

> **Warning:** `--by-source` and `--by-reviewer` are mutually exclusive.

**Output columns (by-source):** `source`, `total`, `addressed`, `not_addressed`, `skipped`, `addressed_rate`
**Output columns (by-reviewer):** `author`, `total`, `addressed`, `not_addressed`, `skipped`

### `db patterns`

Find recurring dismissed patterns. Identifies comments that appear multiple times with similar content.

| Option | Type | Default | Description |
|---|---|---|---|
| `--min` | integer | `2` | Minimum occurrences to report |
| `--json` | flag | `false` | Output as JSON |
| `--db-path` | string | auto-detected | Path to database file |

```bash
myk-pi-tools db patterns
myk-pi-tools db patterns --min 3
myk-pi-tools db patterns --json
```

**Output columns:** `path`, `occurrences`, `reason`, `body_sample`

### `db dismissed`

Get dismissed comments for a repository.

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `--owner` | string | yes | — | Repository owner (org or user) |
| `--repo` | string | yes | — | Repository name |
| `--json` | flag | no | `false` | Output as JSON |
| `--db-path` | string | no | auto-detected | Path to database file |

```bash
myk-pi-tools db dismissed --owner myk-org --repo pi-config
myk-pi-tools db dismissed --owner myk-org --repo pi-config --json
```

**Output columns:** `path`, `line`, `status`, `reply`, `author`

### `db query`

Run a raw SELECT query against the reviews database.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `SQL` | argument | yes | — | SQL SELECT statement |
| `--json` | flag | no | `false` | Output as JSON |
| `--db-path` | string | no | auto-detected | Path to database file |

> **Warning:** Only `SELECT` and `WITH` (CTE) statements are allowed. Other SQL statements are rejected. Multiple statements (separated by `;`) are also blocked.

```bash
myk-pi-tools db query "SELECT * FROM comments WHERE status = 'skipped'"
myk-pi-tools db query "SELECT status, COUNT(*) as cnt FROM comments GROUP BY status"
myk-pi-tools db query "WITH recent AS (SELECT * FROM comments ORDER BY posted_at DESC LIMIT 10) SELECT * FROM recent"
myk-pi-tools db query "SELECT * FROM comments LIMIT 5" --json
```

### `db find-similar`

Find a previously dismissed comment matching a path and body. Uses exact path match combined with body similarity (Jaccard word overlap). Reads JSON from stdin.

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `--owner` | string | yes | — | Repository owner |
| `--repo` | string | yes | — | Repository name |
| `--threshold` | float | no | `0.6` | Minimum similarity threshold (0.0–1.0) |
| `--json` | flag | no | `false` | Output as JSON |
| `--db-path` | string | no | auto-detected | Path to database file |

**Input:** JSON from stdin with `path` and `body` fields.

```bash
echo '{"path": "foo.py", "body": "Add error handling..."}' | \
    myk-pi-tools db find-similar --owner myk-org --repo pi-config --json
```

**Output:** Matching comment with `similarity` score, `path`, `line`, `status`, `reply`, and `body`; or "No similar comment found."

---

## `coderabbit`

CodeRabbit rate limit and review trigger commands.

### `coderabbit check`

Check if CodeRabbit is rate-limited on a PR.

| Argument | Type | Required | Description |
|---|---|---|---|
| `OWNER_REPO` | string | yes | Repository in `owner/repo` format |
| `PR_NUMBER` | integer | yes | Pull request number |

```bash
myk-pi-tools coderabbit check myk-org/pi-config 42
```

**Output:** JSON with rate limit status and wait time.

### `coderabbit trigger`

Wait and trigger a CodeRabbit review on a PR. Posts `@coderabbitai review` and polls until the review starts (max 10 minutes).

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `OWNER_REPO` | argument | yes | — | Repository in `owner/repo` format |
| `PR_NUMBER` | integer | yes | — | Pull request number |
| `--wait` | integer | no | `0` | Seconds to wait before posting review trigger |

```bash
myk-pi-tools coderabbit trigger myk-org/pi-config 42
myk-pi-tools coderabbit trigger myk-org/pi-config 42 --wait 120
```

**Effect:** Optionally waits the specified seconds, then posts a `@coderabbitai review` comment. Polls every 60 seconds (up to 10 attempts) until the review begins.

---

## `ai-cli`

AI CLI commands for routing prompts to external AI agents (Cursor, Claude, Gemini). Wraps the [`ai-cli-runner`](https://pypi.org/project/ai-cli-runner/) package. See [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html) for workflows.

### `ai-cli run`

Run a prompt via an external AI CLI provider.

| Argument/Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `PROMPT` | argument | yes | — | The prompt text to send |
| `-p`, `--provider` | choice | yes | — | AI provider: `cursor`, `claude`, `gemini` |
| `-m`, `--model` | string | no | provider default | Model name (e.g., `gpt-5.4-high`) |
| `--resume` | flag | no | `false` | Continue the most recent session |
| `--session-id` | string | no | — | Resume a specific session by ID |
| `--cwd` | string | no | current directory | Working directory |
| `--cli-flags` | string (repeatable) | no | — | Extra CLI flags (e.g., `--cli-flags=--trust`) |

**Default models per provider:**

| Provider | Default Model |
|---|---|
| `cursor` | `composer-2-fast` |
| `claude` | `claude-sonnet-4-6` |
| `gemini` | `gemini-2.5-flash` |

> **Warning:** `--session-id` and `--resume` are mutually exclusive.

```bash
myk-pi-tools ai-cli run "Review this code for bugs" -p claude
myk-pi-tools ai-cli run "Refactor the auth module" -p cursor -m gpt-5.4-high
myk-pi-tools ai-cli run "Continue the previous task" -p gemini --resume
myk-pi-tools ai-cli run "Fix tests" -p claude --session-id abc123
myk-pi-tools ai-cli run "Review code" -p cursor --cli-flags=--trust --cli-flags=--verbose
```

**Output:** JSON to stdout with `success`, `provider`, `model`, `text` (response), `session_id`, and `usage` (token counts, cost). On failure: `success: false` with `error` field.

### `ai-cli save-config`

Save agent/peer configuration for the `/external-ai` slash command. Persists to `.pi/external-ai-config.json`.

| Option | Type | Required | Default | Description |
|---|---|---|---|---|
| `--agents` | string | no* | — | Save `lastAgents` value (e.g., `cursor --model gpt-5.4-high`) |
| `--peers` | string | no* | — | Save `lastPeers` value (e.g., `cursor,claude`) |

*At least one of `--agents` or `--peers` must be provided.

```bash
myk-pi-tools ai-cli save-config --agents "cursor --model gpt-5.4-high"
myk-pi-tools ai-cli save-config --peers "cursor,claude"
myk-pi-tools ai-cli save-config --agents "gemini" --peers "cursor,claude"
```

**Effect:** Merges into `.pi/external-ai-config.json`. Each option updates only its field — the other is preserved. Outputs the saved config JSON to stdout.

### `ai-cli models`

List available models for a provider.

| Argument | Type | Required | Description |
|---|---|---|---|
| `PROVIDER` | choice | yes | AI provider: `cursor`, `claude`, `gemini` |

```bash
myk-pi-tools ai-cli models cursor
myk-pi-tools ai-cli models claude
myk-pi-tools ai-cli models gemini
```

**Output:** JSON array of model name strings to stdout.

---

## Exit Codes

All subcommands follow a consistent pattern:

| Code | Meaning |
|---|---|
| `0` | Success |
| `1` | Error (missing dependencies, invalid arguments, API failure) |

Commands that output JSON include a `status` or `success` field in the response that mirrors the exit code.

---

## Environment and Prerequisites

| Dependency | Required By | Purpose |
|---|---|---|
| `gh` (GitHub CLI) | `pr`, `release`, `reviews`, `coderabbit`, `db` | GitHub API access |
| `git` | `release info`, `memory`, `db` | Repository context detection |
| `ai-cli-runner` | `ai-cli` | External AI CLI abstraction |

> **Tip:** All dependencies are pre-installed in the pi-config Docker image. See [Running Pi in a Docker Container](docker-deployment.html) for details.

## Related Pages

- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Common Workflow Recipes](workflow-recipes.html)
- [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html)
- [Working with Project Memory](memory-system.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: configuration-reference.md

# Configuration and Environment Variables Reference

All configuration options for pi-config: project settings, environment variables, rules loading, and CodeRabbit setup.

For Docker-specific deployment configuration, see [Running Pi in a Docker Container](docker-deployment.html).
For agent definitions and routing, see [Specialist Agents Reference](agents-reference.html).
For rule content and behavior, see [Orchestrator Rules Reference](rules-reference.html).

---

## Project Settings File

**Location:** `.pi/pi-config-settings.json` (relative to project root)

Project-level settings override environment variables and defaults. The file is loaded once and cached for 30 seconds before re-checking for changes.

**Resolution order:** Project file → Environment variable → Default

### Settings Fields

| Field | Type | Default | Env Var Fallback | Description |
|---|---|---|---|---|
| `co_author` | `boolean` | `false` | `PI_CO_AUTHOR` | Appends a `Co-authored-by: PI (<model>) <noreply@pi.dev>` trailer to git commits |
| `use_worktrees` | `boolean` | `false` | `PI_USE_WORKTREES` | Blocks `git checkout` and `git switch`; forces worktree-only branching workflow |
| `dream_interval_hours` | `number` | `3` | `PI_DREAM_INTERVAL_HOURS` | Hours between automatic memory dreaming cycles. Clamped to range `0.5`–`24` |

### Example File

```json
{
  "co_author": true,
  "use_worktrees": false,
  "dream_interval_hours": 3
}
```

> **Note:** Unknown keys in the file are preserved during migration but ignored by the settings loader. Only the three fields above are read.

### Legacy Migration

If a `.pi-co-author` file exists in the project root, the settings module automatically migrates it to `pi-config-settings.json` with `co_author: true` on `session_start`, then deletes the legacy file. Symlink attacks are detected and skipped.

---

## Environment Variables

### Core Project Settings

These environment variables serve as fallbacks when the corresponding field is not set in `.pi/pi-config-settings.json`.

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_CO_AUTHOR` | `boolean` | `false` | Enable co-author trailers in git commits. Accepted values: `true`, `1`, `yes`, `on` (case-insensitive) |
| `PI_USE_WORKTREES` | `boolean` | `false` | Force worktree-only workflow, blocking `git checkout` and `git switch` |
| `PI_DREAM_INTERVAL_HOURS` | `number` | `3` | Hours between automatic dreaming cycles. Must be between `0.5` and `24` |

```bash
export PI_CO_AUTHOR=true
export PI_USE_WORKTREES=false
export PI_DREAM_INTERVAL_HOURS=3
```

### ACPX Provider

| Variable | Type | Default | Description |
|---|---|---|---|
| `ACPX_AGENTS` | `string` | `""` (empty) | Comma-separated list of ACPX agent names to register as LLM providers. Each agent appears as `acpx-<name>` in the model list |

```bash
# Single agent
export ACPX_AGENTS="cursor"

# Multiple agents
export ACPX_AGENTS="cursor,claude,gemini,copilot"
```

Agent names are validated against the pattern `/^[a-z0-9_-]+$/i`. Invalid names are silently filtered out. Each registered agent creates a provider named `acpx-<agent>` with models discovered at session start via the ACPX runtime library.

> **Note:** ACPX providers are skipped entirely in subagent processes (`PI_SUBAGENT_CHILD=1`). Subagents use the parent session's model via `--model` flag.

### Image Generation

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_IMAGE_MODEL` | `string` | — (required) | Gemini model name for image generation (e.g., `gemini-2.0-flash-exp`) |
| `GEMINI_API_KEY` | `string` | — | Google Gemini API key. Falls back to `GOOGLE_API_KEY` if unset |
| `GOOGLE_API_KEY` | `string` | — | Fallback API key for Gemini. Used only when `GEMINI_API_KEY` is not set |

```bash
export PI_IMAGE_MODEL="gemini-2.0-flash-exp"
export GEMINI_API_KEY="your-key-here"
```

> **Warning:** Both `PI_IMAGE_MODEL` and an API key (`GEMINI_API_KEY` or `GOOGLE_API_KEY`) must be set for the `generate_image` tool to function. Missing either variable returns an error message to the LLM.

### Dashboard and Diff Viewer

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_PIDASH_PORT` | `number` | `19190` | Port for the pidash web dashboard server |
| `PI_PIDASH_ENABLE` | `string` | — (enabled) | Set to `false`, `0`, `no`, or `off` to disable pidash entirely |
| `PI_PIDIFF_PORT` | `number` | `19290` | Port for the pidiff diff viewer server |
| `PI_PIDIFF_ENABLE` | `string` | — (enabled) | Set to `false`, `0`, `no`, or `off` to disable pidiff entirely |

```bash
export PI_PIDASH_PORT=19190
export PI_PIDIFF_PORT=19290

# Disable dashboards
export PI_PIDASH_ENABLE=false
export PI_PIDIFF_ENABLE=false
```

For more on dashboards, see [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html).

### Discord Bot Integration

These variables configure the Discord bot embedded in the pidash daemon server.

| Variable | Type | Default | Description |
|---|---|---|---|
| `DISCORD_BOT_TOKEN` | `string` | — | Discord bot token. If unset, the Discord bot is disabled entirely |
| `DISCORD_ALLOWED_USERS` | `string` | — (all users) | Comma-separated list of Discord user IDs allowed to interact with the bot |

```bash
export DISCORD_BOT_TOKEN="your-discord-bot-token"
export DISCORD_ALLOWED_USERS="123456789,987654321"
```

> **Warning:** If `DISCORD_ALLOWED_USERS` is not set, all DMs to the bot are accepted.

Alternatively, credentials can be placed in `~/.pi/discord.env` as `KEY=VALUE` lines (one per line). The pidash server reads this file at startup.

### P2P Communication (Coms)

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_COMS_DIR` | `string` | `~/.pi/coms` | Directory for P2P coms registry files |
| `PI_COMS_MAX_HOPS` | `number` | `5` | Maximum message relay hops |
| `PI_COMS_TIMEOUT_MS` | `number` | `1800000` (30 min) | Message delivery timeout in milliseconds |
| `PI_COMS_PING_INTERVAL_MS` | `number` | `10000` (10s) | Peer ping interval in milliseconds |

```bash
export PI_COMS_DIR="$HOME/.pi/coms"
export PI_COMS_MAX_HOPS=5
```

For more on inter-agent communication, see [Communicating Between Pi Sessions](inter-agent-communication.html).

### Networked Communication (Coms-Net)

#### Client Variables

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_COMS_NET_SERVER_URL` | `string` | — | Hub server URL for remote connections (auto-discovered from `server.json` for local) |
| `PI_COMS_NET_AUTH_TOKEN` | `string` | — | Authentication token for the hub server |
| `PI_COMS_NET_PROJECT` | `string` | `"default"` | Project namespace for agent grouping |
| `PI_COMS_NET_MAX_HOPS` | `number` | `5` | Maximum message relay hops |
| `PI_COMS_NET_HEARTBEAT_MS` | `number` | `10000` (10s) | Heartbeat interval in milliseconds |
| `PI_COMS_NET_MESSAGE_TTL_MS` | `number` | `1800000` (30 min) | Message time-to-live in milliseconds |

#### Server Variables

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_COMS_NET_HOST` | `string` | `"127.0.0.1"` | Bind address for the hub server |
| `PI_COMS_NET_PORT` | `number` | `0` (auto) | Listening port (`0` = OS-assigned) |
| `PI_COMS_NET_PUBLIC_URL` | `string` | — | Public URL for the server (used when behind a proxy) |
| `PI_COMS_NET_MAX_INBOX` | `number` | `100` | Maximum queued messages per agent |
| `PI_COMS_NET_STALE_AFTER_MS` | `number` | `30000` (30s) | Time without heartbeat before marking an agent stale |
| `PI_COMS_NET_OFFLINE_AFTER_MS` | `number` | `60000` (60s) | Time without heartbeat before marking an agent offline |
| `PI_COMS_NET_LOG_QUIET` | `string` | — | Set to `"1"` to suppress all log output except startup/shutdown |
| `PI_COMS_NET_LOG_HEARTBEAT` | `string` | — | Set to `"1"` to include heartbeat events in logs (very verbose) |

```bash
# Local auto-discovery (default)
# No env vars needed — client reads ~/.pi/coms-net/server.json

# Remote connection
export PI_COMS_NET_SERVER_URL="http://hub.example.com:8080"
export PI_COMS_NET_AUTH_TOKEN="your-auth-token"
export PI_COMS_NET_PROJECT="my-project"
```

### Container and Docker

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_HOST_USER` | `string` | `"node"` | Host username. Creates `/home/<user>` inside the container with symlinks so host-mounted paths resolve correctly |
| `AGENT_BROWSER_ARGS` | `string` | `"--no-sandbox,--disable-dev-shm-usage"` | Chromium flags for `agent-browser` (comma-separated). Set in Dockerfile |

```bash
export PI_HOST_USER=myakove
```

When `PI_HOST_USER` is set to a value other than `"node"`, the init entrypoint:

1. Creates `/home/<PI_HOST_USER>` with correct ownership
2. Symlinks container tool directories (`.npm-global`, `.cache`, `.local`, etc.) into the new HOME
3. Creates reverse symlinks in `/home/node` pointing to mounted content
4. Sets `HOME` and updates `PATH` to include the new home-based directories

### Git and SSH

| Variable | Type | Default | Description |
|---|---|---|---|
| `GIT_SSH_COMMAND` | `string` | `ssh -o ServerAliveInterval=15 -o ServerAliveCountMax=3 -o ConnectTimeout=10` | SSH command with keepalive and timeout settings. Set automatically by both `entrypoint.sh` and `utils.ts` if unset |

> **Note:** The SSH timeout configuration detects dead connections during git fetch/push/pull. The keepalive sends a probe every 15 seconds, gives up after 3 missed responses (45 seconds total), and fails connections that don't establish within 10 seconds.

### Debugging and Internal

| Variable | Type | Default | Description |
|---|---|---|---|
| `PI_ASYNC_DEBUG` | `boolean` | `false` | Enable debug logging for async agent infrastructure |
| `PI_SUBAGENT_CHILD` | `string` | — | Set to `"1"` internally when running as a subagent. Disables orchestrator-only features (dreaming, memory writes, autocomplete, ACPX providers, dashboard connections) |
| `PI_AGENT_NAME` | `string` | — | Internal. Set to the current agent's name. Used by enforcement to allow git commit/push only from `git-expert` |
| `PI_PIDASH_PORT` | `number` | `19190` | Also used by the async runner to connect to pidash for status updates |
| `NVIM` | `string` | — | Neovim socket path. Automatically set by Neovim when launching pi from within Neovim. Enables the nvim integration (quickfix, changed files) |
| `PI_GIT_BIN` | `string` | `"git"` | Custom git binary path for the pidiff server |

> **Warning:** Do not set `PI_SUBAGENT_CHILD` or `PI_AGENT_NAME` manually — they are managed internally by the subagent spawning system.

---

## Rules Loading Order

Orchestrator rules are auto-loaded from the `rules/` directory in **alphabetical order** on every `before_agent_start` event. Files must end in `.md`. Numeric prefixes control ordering.

| File | Priority | Domain |
|---|---|---|
| `00-orchestrator-core.md` | 0 | Core orchestrator behavior — delegation rules, forbidden actions |
| `05-issue-first-workflow.md` | 5 | Issue-first development workflow |
| `10-agent-routing.md` | 10 | Task → agent routing table |
| `15-mcp-launchpad.md` | 15 | MCP server discovery and connection |
| `20-code-review-loop.md` | 20 | 3-reviewer parallel code review system |
| `25-documentation-updates.md` | 25 | Documentation update requirements |
| `30-prompt-templates.md` | 30 | Slash command and prompt template handling |
| `35-memory.md` | 35 | Memory system usage rules |
| `40-critical-rules.md` | 40 | Critical safety and behavioral rules |
| `45-file-preview.md` | 45 | File preview via HTTP server |
| `50-agent-bug-reporting.md` | 50 | Bug reporting policy for agent errors |
| `55-coms-protocol.md` | 55 | Inter-agent communication protocol |
| `60-task-tracking.md` | 60 | Task tracking integration |

> **Note:** Rules are loaded into the orchestrator system prompt only — specialist agents (subagents) do not receive orchestrator rules. Subagents receive only the memory situation report.

For detailed rule content, see [Orchestrator Rules Reference](rules-reference.html).

### Adding a Custom Rule

Place a `.md` file in `rules/` with a numeric prefix to control ordering:

```bash
# Loads after agent routing but before code review loop
rules/12-my-custom-rule.md
```

Changes take effect on the **next pi session** — running sessions are not affected.

---

## Agent Discovery Order

Agents are discovered from three sources in priority order (later sources override earlier):

| Priority | Source | Path | Description |
|---|---|---|---|
| 1 (lowest) | Package | `<pi-config>/agents/` | Bundled agent definitions shipped with pi-config |
| 2 | User | `~/.pi/agent/agents/` | User-global custom agents |
| 3 (highest) | Project | `.pi/agents/` (searched up from cwd) | Project-specific agent overrides |

Agent files use Markdown with YAML frontmatter:

```markdown
---
name: my-agent
description: What this agent does
tools: read, write, edit, bash
model: optional-model-override
---

System prompt instructions here...
```

| Frontmatter Field | Type | Required | Description |
|---|---|---|---|
| `name` | `string` | Yes | Agent identifier (used in routing and subagent calls) |
| `description` | `string` | Yes | One-sentence description of the agent's purpose |
| `tools` | `string` | No | Comma-separated list of tools the agent can use |
| `model` | `string` | No | Override the default LLM model for this agent |

For the full list of bundled agents, see [Specialist Agents Reference](agents-reference.html).

### Async-Only Agents

The following agents are enforced to run with `async: true` only. Synchronous calls are automatically promoted to async by the subagent tool:

- `code-reviewer-quality`
- `code-reviewer-guidelines`
- `code-reviewer-security`

This list is defined in the `ASYNC_ONLY_AGENTS` set in `extensions/orchestrator/subagent-tool.ts`.

---

## CodeRabbit Configuration

**Location:** `.coderabbit.yaml` (project root)

Pi-config ships a CodeRabbit configuration for local AI code reviews via the CodeRabbit CLI (`cr` command).

```yaml
language: en-US
reviews:
  profile: assertive
  poem: false
  sequence_diagrams: false
  auto_review:
    enabled: false  # Uses CLI, not PR auto-review
```

### Enabled Linters

| Linter | Language/Purpose |
|---|---|
| `shellcheck` | Shell scripts |
| `ruff` | Python |
| `hadolint` | Dockerfiles |
| `actionlint` | GitHub Actions |
| `markdownlint` | Markdown |
| `eslint` | JavaScript/TypeScript |
| `biome` | JavaScript/TypeScript |
| `gitleaks` | Secret detection |
| `trufflehog` | Secret detection |

### Disabled Linters

PHP (`phpstan`, `phpmd`, `phpcs`), Ruby (`rubocop`), Swift (`swiftlint`), Kotlin (`detekt`), Java (`pmd`), Protobuf (`buf`), SQL (`sqlfluff`), Terraform (`tflint`), IaC (`checkov`), Rust (`clippy`).

### Knowledge Base

```yaml
knowledge_base:
  code_guidelines:
    enabled: true  # Auto-picks up AGENTS.md
```

---

## Memory System Files

The memory system uses several files under `.pi/memory/`. These are not directly edited but are referenced by configuration.

| Path | Description |
|---|---|
| `.pi/memory/topics/*.md` | Topic files — one per category (preferences, lessons, patterns, decisions, completions, mistakes) |
| `.pi/memory/memory-scores.json` | Stability scores for all memory entries |
| `.pi/memory/embeddings.json` | Vector embeddings for semantic memory search |
| `.pi/memory/.dream-watermark` | Timestamp of last dreaming cycle processed |
| `.pi/data/memory-telemetry.jsonl` | Retrieval telemetry log (capped at 500KB) |
| `.pi/data/session-search.json` | Past session summaries index for keyword search |
| `.pi/data/pr-reviews.db` | PR review comment tracking (SQLite database) |

> **Tip:** Add `.pi/memory/` to your global gitignore to prevent committing memory data. The container entrypoint does this automatically.

For memory system internals, see [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html).

---

## Temp Directory Structure

All runtime data lives under project-scoped temp directories.

**Base path:** `<project-root>/.pi/tmp/`

| Path | Description |
|---|---|
| `debug.log` | Async debug log |
| `cron-<pid>.json` | Cron task state (per-process) |
| `.repeat-<pid>.json` | Repeat command detection state |
| `async-results-pid-<pid>/` | Async agent completion results |
| `worker-<id>/` | Async agent working directory |
| `worker-<id>/status.json` | Agent state (`running` / `complete` / `failed`) |
| `worker-<id>/output.log` | Agent output |
| `worker-<id>/system-prompt.md` | Agent system prompt |

The helper function `getProjectTmpDir(cwd)` in `extensions/orchestrator/utils.ts` returns `<cwd>/.pi/tmp/`, creating the directory if it does not exist.

---

## Mode-Aware Feature Guards

Pi operates in four modes. Extensions use `ctx.mode` to conditionally enable features.

| Mode | Description |
|---|---|
| `"tui"` | Interactive terminal UI |
| `"rpc"` | Programmatic/API access |
| `"json"` | Structured JSON output (one-shot) |
| `"print"` | Plain text output (one-shot) |

| Feature | Active Modes | Guard |
|---|---|---|
| Daemon connections (pidash, pidiff) | `tui` only | `ctx.mode === "tui"` |
| Autocomplete providers | `tui` only | `ctx.mode === "tui"` |
| Cron scheduling | `tui`, `rpc` | `ctx.mode !== "print" && ctx.mode !== "json"` |
| Dreaming (auto timer) | `tui`, `rpc` | `ctx.mode !== "print" && ctx.mode !== "json"` |
| UI notifications | `tui`, `rpc` | `ctx.hasUI` |

---

## Extension Registration Order

The orchestrator extension (`extensions/orchestrator/index.ts`) registers modules in a specific order. Some modules depend on others being registered first.

1. `registerExtendedAutocomplete` — Must be first (wraps `registerCommand` for completions)
2. `registerAskUser` — `ask_user` tool
3. `registerAsyncAgents` — Background agent infrastructure (provides `spawnAsyncAgent`)
4. `registerSubagentTool` — Subagent tool (depends on async agents)
5. `registerProjectSettings` — Settings migration and cache
6. `registerEnforcement` — Command blocking rules
7. `registerRules` — Rule injection and memory loading (depends on async agent job list)
8. `registerStatusLine` — Git status, container indicator
9. `registerBtw` — `/btw` side questions
10. `registerDreaming` — Memory consolidation (depends on `spawnAsyncAgent`)
11. `registerCron` — Scheduled tasks (depends on `spawnAsyncAgent`)
12. `registerSessionValidation` — Tool checks, upgrade notifications
13. `registerGithubAutocomplete` — GitHub issue `#` autocomplete
14. `registerStatus` — `/status` command
15. `registerNvim` — Neovim integration
16. `registerPreferenceExtractor` — Auto-extract user preferences
17. `registerMemoryTools` — AI-accessible memory tools
18. `registerSessionSearch` — Session history keyword search

---

## Required and Optional CLI Tools

Checked on `session_start` by the session validation module.

### Required

| Tool | Purpose | Install |
|---|---|---|
| `uv` | Python package/runtime management | [docs.astral.sh/uv](https://docs.astral.sh/uv/) |

### Optional

| Tool | Purpose | Install | Condition |
|---|---|---|---|
| `gh` | GitHub CLI | [cli.github.com](https://cli.github.com/) | Always checked |
| `mcpl` | MCP Launchpad | [mcp-launchpad](https://github.com/kenneth-liao/mcp-launchpad) | Always checked |
| `myk-pi-tools` | PR/release/review CLI | `uv tool install git+https://github.com/myk-org/pi-config` | Always checked |
| `prek` | Pre-commit wrapper | [github.com/j178/prek](https://github.com/j178/prek) | Only if `.pre-commit-config.yaml` exists |
| `agent-browser` skill | Browser automation | `npx skills add vercel-labs/agent-browser@agent-browser -g -y` | Checks `~/.agents/skills/agent-browser/SKILL.md` or `~/.pi/agent/skills/agent-browser/SKILL.md` |

## Related Pages

- [Running Pi in a Docker Container](docker-deployment.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html)
- [Communicating Between Pi Sessions](inter-agent-communication.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)

---

Source: rules-reference.md

# Orchestrator Rules Reference

Orchestrator rules are markdown files in the `rules/` directory that define the orchestrator's behavior. They load automatically in **alphabetical order** (by numeric prefix) at the start of each pi session and are injected into the orchestrator's system prompt via the `before_agent_start` hook in `extensions/orchestrator/rules.ts`.

> **Note:** Rules apply to the **orchestrator only** — specialist agents ignore them. Each rule file begins with a scope declaration that enforces this boundary.

| Property | Value |
|----------|-------|
| Location | `rules/` directory |
| Format | Markdown (`.md`) |
| Load order | Alphabetical (numeric prefix) |
| Takes effect | Next pi session start |
| Injected via | `before_agent_start` hook in `extensions/orchestrator/rules.ts` |
| Target | Orchestrator only (not specialist agents) |

---

## Rule Loading Mechanism

The `registerRules()` function in `extensions/orchestrator/rules.ts` reads all `.md` files from the `rules/` directory, sorts them alphabetically, and concatenates their contents into the orchestrator's system prompt. This happens on every `before_agent_start` event.

```text
rules/
├── 00-orchestrator-core.md      # Loads first
├── 05-issue-first-workflow.md
├── 10-agent-routing.md
├── 15-mcp-launchpad.md
├── 20-code-review-loop.md
├── 25-documentation-updates.md
├── 30-prompt-templates.md
├── 35-memory.md
├── 40-critical-rules.md
├── 45-file-preview.md
├── 50-agent-bug-reporting.md
├── 55-coms-protocol.md
└── 60-task-tracking.md          # Loads last
```

> **Tip:** To add a new rule, create a file with a numeric prefix that places it in the desired load order. See [Customization and Extension Recipes](customization-recipes.html) for details.

---

## 00 — Orchestrator Core

**File:** `rules/00-orchestrator-core.md`

Defines the fundamental separation between the orchestrator (manager) and specialist agents (workers). The orchestrator delegates all implementation work and never directly modifies files.

### Forbidden Actions

| Action | Status | Alternative |
|--------|--------|-------------|
| `edit`, `write`, `bash` tools | ❌ Forbidden | Delegate to specialist agents via `subagent` |
| Delegating slash commands | ❌ Forbidden | Execute slash commands directly |
| Git commands | ❌ Forbidden | Delegate to `git-expert` |
| MCP tool execution | ❌ Forbidden | Delegate to specialist agents |
| Multi-file exploration | ❌ Forbidden | Delegate to `worker` agent |

### Allowed Direct Actions

| Action | Status |
|--------|--------|
| Read files (read tool) | ✅ Allowed |
| Run `mcpl` via bash for MCP discovery | ✅ Allowed |
| Ask clarifying questions | ✅ Allowed |
| Analyze and plan | ✅ Allowed |
| Route tasks to agents via `subagent` | ✅ Allowed |
| Execute slash commands and their internal operations | ✅ Allowed |

### Pre-Implementation Checklist

Before any code changes (when the issue-first workflow applies):

1. Root cause investigated? (read code, understand the problem)
2. GitHub issue created?
3. On issue branch (`feat/issue-N-...` or `fix/issue-N-...`)?

---

## 05 — Issue-First Workflow

**File:** `rules/05-issue-first-workflow.md`

Requires a GitHub issue and dedicated branch before starting code changes. Defines the full lifecycle from user request to issue closure.

### When to Apply

| Condition | Action |
|-----------|--------|
| New features or enhancements | **Use** workflow |
| Bug fixes requiring code changes | **Use** workflow |
| Refactoring tasks | **Use** workflow |
| Multi-file modifications | **Use** workflow |
| Trivial fixes (typos, single-line) | **Skip** workflow |
| Questions or explanations | **Skip** workflow |
| Exploration or research | **Skip** workflow |
| User says "just do it" / "quick fix" | **Skip** workflow |
| Urgent hotfixes | **Skip** workflow |

### Workflow Steps

1. Analyze and understand the request
2. Determine if workflow should be skipped
3. Investigate root cause — read source code, identify affected files and functions
4. Delegate to `github-expert` to create issue with type, description, root cause analysis, proposed fix, and deliverables checklist
5. Ask user: "Issue #N created. Do you want to work on it now?"
6. On confirmation, delegate to `git-expert` to fetch main and create issue branch
7. Implement changes, following the code review loop
8. Check off deliverables as completed
9. Close issue when all deliverables are done

### Branch Naming

| Type | Pattern | Example |
|------|---------|---------|
| Feature | `feat/issue-<N>-<description>` | `feat/issue-70-issue-first-workflow` |
| Fix | `fix/issue-<N>-<description>` | `fix/issue-42-memory-leak` |
| Refactor | `refactor/issue-<N>-<description>` | `refactor/issue-99-cleanup-utils` |
| Docs | `docs/issue-<N>-<description>` | `docs/issue-15-update-readme` |

### Issue Requirements

Every issue **must** include a `## Done` section with checkboxes:

```markdown
## Done

- [ ] Deliverable 1
- [ ] Deliverable 2
- [ ] Deliverable 3
```

> **Warning:** Issues must never be closed with unchecked deliverables. If a deliverable is no longer needed, remove it or mark as N/A before closing.

### Edge Cases

| Scenario | Behavior |
|----------|----------|
| User says "just fix it" | Skip workflow, do directly |
| Partial requirements | Ask clarifying questions, then create issue |
| Issue already exists | Ask if user wants to continue existing issue |
| Urgent/hotfix request | Skip workflow, note in commit message |
| Multiple unrelated requests | Create separate issues for each |

---

## 10 — Agent Routing

**File:** `rules/10-agent-routing.md`

Maps task domains to specialist agents. See [Specialist Agents Reference](agents-reference.html) for full agent specifications.

### Routing Table

| Domain | Agent |
|--------|-------|
| Python (`.py`) | `python-expert` |
| Go (`.go`) | `go-expert` |
| Frontend (JS/TS/React/Vue/Angular) | `ts-expert` |
| Java (`.java`) | `java-expert` |
| Shell scripts (`.sh`) | `bash-expert` |
| Markdown (`.md`) | `technical-documentation-writer` |
| Docker | `docker-expert` |
| Kubernetes/OpenShift | `kubernetes-expert` |
| Jenkins/CI/Groovy | `jenkins-expert` |
| Git operations (local) | `git-expert` |
| GitHub (PRs, issues, releases, workflows) | `github-expert` |
| Tests | `test-automator` |
| Debugging | `debugger` |
| API docs | `api-documenter` |
| External repo security audit | `security-auditor` |
| External AI agents | `/acpx-prompt` |
| External library/framework docs | `docs-fetcher` |
| No specialist match | `worker` (fallback) |

### Routing Principles

Route by **task intent**, not by tool:

| Task | Correct Route | Reasoning |
|------|---------------|-----------|
| Running Python tests | `python-expert` | Intent is Python, not shell |
| Editing Python files with sed/awk | `python-expert` | Intent is Python code modification |
| Creating a PR | `github-expert` | GitHub operation, not local git |
| Committing changes | `git-expert` | Local git operation |
| React documentation lookup | `docs-fetcher` | External library docs |

### docs-fetcher Routing

The orchestrator must **never** fetch external documentation directly. All external doc lookups go through `docs-fetcher`.

```text
# Correct — delegate to docs-fetcher
subagent(agent="docs-fetcher", task="Fetch React hooks documentation...")

# Wrong — orchestrator fetching directly
fetch_content(https://react.dev/...)
```

`docs-fetcher` tries `llms.txt` first (optimized for LLMs), then extracts only relevant sections.

---

## 15 — MCP Launchpad

**File:** `rules/15-mcp-launchpad.md`

Defines how to use the `mcpl` CLI for MCP (Model Context Protocol) server interactions. See [Slash Commands and Extension Commands Reference](commands-reference.html) for related commands.

### mcpl Commands

| Command | Purpose |
|---------|---------|
| `mcpl search "<query>"` | Search all tools (shows required params, 5 results) |
| `mcpl search "<query>" --limit N` | Search with custom result limit |
| `mcpl list` | List all MCP servers |
| `mcpl list <server>` | List tools for a specific server |
| `mcpl list --refresh` | Refresh and list all servers |
| `mcpl inspect <server> <tool>` | Get full tool schema |
| `mcpl inspect <server> <tool> --example` | Get schema + example call |
| `mcpl call <server> <tool> '{}'` | Execute tool with no arguments |
| `mcpl call <server> <tool> '{"param": "v"}'` | Execute tool with arguments |
| `mcpl verify` | Test all server connections |

### Workflow

```text
1. Search for the tool:    mcpl search "list projects"
2. Get an example call:    mcpl inspect sentry search_issues --example
3. Call with params:       mcpl call vercel list_projects '{"teamId": "team_xxx"}'
```

### Troubleshooting Commands

| Command | Purpose |
|---------|---------|
| `mcpl verify` | Test all server connections |
| `mcpl session status` | Check daemon and server connection status |
| `mcpl session stop` | Restart daemon |
| `mcpl config` | Show current configuration |
| `mcpl call <server> <tool> '{}' --no-daemon` | Bypass daemon for debugging |

### Role Separation

| Role | Can Do |
|------|--------|
| Orchestrator | `mcpl search` / `mcpl list` for discovery only |
| Specialist agents | Full `mcpl` workflow including `mcpl call` |

---

## 20 — Code Review Loop

**File:** `rules/20-code-review-loop.md`

Mandatory review process after every code change. Three reviewers run in parallel, and the loop repeats until all approve. See [Running the Automated Code Review Loop](code-review-loop.html) for a usage guide.

### Review Agents

| Agent | Focus Area |
|-------|------------|
| `code-reviewer-quality` | General code quality and maintainability |
| `code-reviewer-guidelines` | Project guidelines and style (AGENTS.md) |
| `code-reviewer-security` | Bugs, logic errors, security vulnerabilities |

> **Note:** All three reviewers are enforced as `async: true` by the `ASYNC_ONLY_AGENTS` set in `extensions/orchestrator/subagent-tool.ts`. Sync calls are automatically rejected.

### Standard Loop (Manual Reviews)

1. Specialist writes/fixes code
2. All 3 review agents dispatched **in parallel** (async)
3. Merge and deduplicate findings from all reviewers
4. If any reviewer has comments → fix code → go to step 2
5. Run `test-automator`
6. If tests fail → fix code:
   - Minor fix (test/config only) → re-run tests (step 5)
   - Substantive code change → full re-review (step 2)
7. Done when all reviewers approve **AND** tests pass

### Deduplication Criteria

| Condition | Action |
|-----------|--------|
| Same file/line range + same issue type or root cause | Keep most actionable version |
| Conflicting suggestions | Priority: security > correctness > performance > style |
| Complementary findings on same code (different issue types) | Keep both |

### Baseline Test Comparison

Before declaring test failures as blockers, compare against baseline:

1. Save all changes (staged + unstaged + untracked)
2. Reset to clean state (`git reset --hard HEAD`)
3. Run tests → record baseline failure count
4. Restore changes (`git apply`)
5. Run tests → record current failure count
6. Only **new failures** (current minus baseline) block the review

> **Note:** Pre-existing failures are noted in the review but do not block. If `git apply` and `git apply --3way` both fail, skip baseline comparison and note "baseline comparison unavailable."

### Staged Review Mode (Automated Workflows)

For automated review flows (autorabbit, autoqodo), use a two-stage order instead of parallel:

| Stage | Focus | Rationale |
|-------|-------|-----------|
| Stage 1 | Spec compliance — requirements met, all deliverables implemented, no scope creep | Don't polish code that doesn't meet spec |
| Stage 2 | Code quality, security, guidelines | Quality review on spec-compliant code |

Each stage loops independently until passed before advancing to the next.

---

## 25 — Documentation Updates

**File:** `rules/25-documentation-updates.md`

Mandatory documentation check after any code change. Maps change types to documentation files that must be reviewed and updated.

### Change-to-Documentation Map

| Change Type | Files to Check |
|-------------|----------------|
| New feature/command/tool | `README.md` (feature table, usage examples) |
| New or modified extension module | `AGENTS.md` (repository structure) |
| New agent added/removed | `AGENTS.md`, `rules/10-agent-routing.md`, `rules/50-agent-bug-reporting.md` |
| New prompt template | `README.md` (prompt templates table) |
| Docker/container changes | `README.md` (Docker section), `Dockerfile` |
| New CLI tool or dependency | `README.md` (tools table), `Dockerfile` |
| Dev workflow changes | `DEVELOPMENT.md` |

> **Warning:** Documentation drift is treated as a bug. This step must not be skipped.

---

## 30 — Prompt Templates

**File:** `rules/30-prompt-templates.md`

Governs how the orchestrator executes prompt templates (slash commands). See [Using Slash Commands and Prompt Templates](slash-commands.html) for usage details.

### Execution Rules

| Rule | Description |
|------|-------------|
| Prompt is the authority | Follow the template's instructions exactly |
| Never delegate the template itself | The orchestrator executes the prompt, not an agent |
| Prompt decides delegation | If the prompt says "delegate to X," delegate. If it says "run this bash command," run it. |
| Orchestrator maintains control | The orchestrator owns the prompt workflow |
| Template overrides general rules | When a prompt's instructions conflict with general delegation rules, the prompt wins |

```text
# Correct — orchestrator executes prompt, delegates sub-tasks as directed
/mycommand → orchestrator follows prompt → delegates sub-tasks per prompt instructions

# Wrong — delegating the entire prompt to an agent
/mycommand → delegate entire prompt to an agent
```

---

## 35 — Memory

**File:** `rules/35-memory.md`

Defines the scored memory system, memory tools, and per-turn self-improvement obligations. See [Working with Project Memory](memory-system.html) for a usage guide and [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html) for architecture details.

### Memory Tools

| Tool | Purpose | Mandatory? |
|------|---------|------------|
| `memory_search` | Search memories by keyword or category | Yes — before answering questions about prior sessions |
| `memory_reinforce` | Bump evidence count to prevent decay | Yes — when a memory is relevant to current task |
| `memory_add` | Add new memories (pinned or learned) | Yes — when learning something worth remembering |
| `memory_remove` | Remove outdated or incorrect memories | No |
| `memory_topics` | List topic files with hotness scores | No |
| `session_search` | Search past conversation summaries | No |

### Memory Categories

| Category | Storage File |
|----------|-------------|
| `preference` | `.pi/memory/topics/preferences.md` |
| `lesson` | `.pi/memory/topics/lessons.md` |
| `pattern` | `.pi/memory/topics/patterns.md` |
| `decision` | `.pi/memory/topics/decisions.md` |
| `done` | `.pi/memory/topics/completions.md` |
| `mistake` | `.pi/memory/topics/mistakes.md` |

### Auto-Injection Pipeline

Three mechanisms inject memories into the system prompt automatically:

| Mechanism | Source | Trigger |
|-----------|--------|---------|
| Situation Report | Token-budgeted summary of scored memories | Every `before_agent_start` |
| Contextual Memory Recall | Vector similarity search (threshold > 0.65) | Every `before_agent_start` (non-trivial messages) |
| Session History Recall | Keyword search over past conversation summaries | Every `before_agent_start` (non-trivial messages) |

> **Note:** Trivial messages ("ok", "thanks", "yes", emoji-only, messages < 6 chars) skip vector/session search via the social closer gate.

### Capacity Signal

The situation report header shows memory usage:

```text
# Project Memory [72% — 1,224/1,700 tokens]
```

| Usage | Action |
|-------|--------|
| Below 80% | Add memories freely |
| Above 80% | Consolidate first — merge related entries, remove outdated ones |

### Per-Turn Self-Improvement Triggers

| Event | Action |
|-------|--------|
| User corrected you | `memory_add(text: "...", category: "lesson")` |
| Something failed | `memory_add(text: "...", category: "mistake")` |
| User said "don't do X" / "always do Y" | `memory_add(text: "...", category: "preference")` |
| PR merged | `memory_add(text: "...", category: "done")` |
| Non-obvious pattern discovered | `memory_add(text: "...", category: "pattern")` |
| Technical decision made | `memory_add(text: "...", category: "decision")` |

### Memory Quality Rules

- One line only — max ~100 characters
- Specific and actionable — concrete "do X" or "don't do Y"
- No fluff — no context, background, or explanation

### CLI Interface

```bash
uv run myk-pi-tools memory add -c <category> -s "summary"           # Add to Learned
uv run myk-pi-tools memory add -c <category> -s "summary" --pinned  # Add to Pinned
uv run myk-pi-tools memory forget -c <category> -s "summary"        # Remove
uv run myk-pi-tools memory show                                     # Show memory file
uv run myk-pi-tools memory migrate                                  # DB→md migration
uv run myk-pi-tools memory path                                     # Print file path
```

See [myk-pi-tools CLI Reference](cli-reference.html) for complete CLI documentation.

### Dreaming (Background Consolidation)

Dreaming runs as an async fire-and-forget agent — never blocking the session.

| Trigger | Type |
|---------|------|
| `/dream` command | Manual |
| Session shutdown | Automatic |

Dreaming reads the session, extracts learnings, adds new entries, deduplicates, and removes stale entries. Pinned entries are never removed.

---

## 40 — Critical Rules

**File:** `rules/40-critical-rules.md`

Mandatory behavioral constraints that apply across all orchestrator actions. See [Command Safety Guards and Enforcement](command-enforcement.html) for enforcement details.

### Questions Are Not Instructions

When the user asks a question (contains `?`), the orchestrator must **only answer** — no file modifications, no state changes, no PRs, no issues.

| Allowed | Forbidden |
|---------|-----------|
| Read-only commands (read, grep, cat, ls) | Modify/create/delete files |
| `memory_search` | Run state-changing commands |
| Answer the question | Create branches, PRs, or issues |
| Ask for confirmation before acting | "Fix" something noticed while answering |

### Task Focus

During multi-step workflows, side questions do not end the current task. Answer the question, then immediately resume the workflow from the next pending step.

### Parallel Execution

| Rule | Description |
|------|-------------|
| Maximize parallelism | If operations have no dependencies, execute all in one message |
| Async by default | Use `async: true` for independent tasks (reviews, research, analysis) |
| Sync only when blocked | Use sync only when the very next step depends on the agent's output |
| Kill unused agents | Kill async agents immediately when their result is no longer needed |

### Sync Agent Time Estimates

| Mode | `estimatedSeconds` | Threshold |
|------|---------------------|-----------|
| Single sync | Required on top-level params | Must be < 30s |
| Parallel sync | Required on each task | Max must be < 30s |
| Chain sync | Required on each step | Sum must be < 30s |
| Async | Not required | — |

> **Warning:** Sync calls without `estimatedSeconds` or with values ≥ 30s are rejected by the subagent tool.

### Subagent cwd

Always pass `cwd` when delegating to subagents — in all modes (single, parallel, chain, async). Omitting `cwd` causes enforcement to check the wrong repository.

### Multi-PR / Multi-Branch Work

When working on multiple PRs simultaneously, use `git worktree` for each branch:

```bash
git worktree add .worktrees/pr-42 origin/fix/issue-42
git worktree add .worktrees/pr-43 origin/feat/issue-43
# Work in each directory independently
git worktree remove .worktrees/pr-42
```

> **Warning:** Never switch branches in the main worktree when other agents may be running — it corrupts parallel agent work.

### User Interaction

Always use the `ask_user` tool for user input (approvals, selections, confirmations). Never ask questions via plain text in the response.

### Technical Honesty

Evaluate user proposals critically. Present alternatives with tradeoffs before proceeding. Let the user make the final call.

### Web Access

| Tool | Use For |
|------|---------|
| `web_search` | Research and search queries |
| `fetch_content` | Extracting content from URLs, YouTube, GitHub repos |
| `agent-browser` | Interactive pages (clicks, forms, screenshots) |

> **Warning:** Never use `curl` for reading web pages. Never use SearXNG MCP.

### External Code Security Audit

Before adopting external code from untrusted sources, delegate a security audit to `security-auditor`.

| Source | Audit Approach |
|--------|----------------|
| Git repos | Clone to temp dir, run `security-auditor` |
| Pi skills | Clone source, run `security-auditor` |
| PyPI packages | Clone source repo, check install hooks |
| npm packages | Download source, check `postinstall` scripts |
| MCP servers | Audit server source code |
| Docker images | Inspect Dockerfile source |
| Remote scripts (`curl \| bash`) | **Always block** — download first, audit, then run |

Skip audits when: user says "skip audit", tool is previously approved, or package is well-known (e.g., `requests`, `react`, `lodash`).

### Temp Files

All temp files must go to `<cwd>/.pi/tmp/` via `getProjectTmpDir()`. The `.pi/` directory is already gitignored.

### Python Execution

Use `uv run --with <package>` syntax only. Never use `uv run pip install`.

```bash
# Correct
uv run --with requests script.py
uv run --with requests --with pandas script.py
```

### External Git Repository Exploration

Clone external repos to `${PROJECT_TMP_DIR}/` with `--depth 1` for shallow clones. Never use full clones or `fetch_content` to browse repository files.

---

## 45 — File Preview

**File:** `rules/45-file-preview.md`

Serves generated or modified browser-viewable files (HTML, frontend) via a built-in HTTP server.

### Preview Workflow

1. Save the file under `$PWD` or `${PROJECT_TMP_DIR}`
2. Find a free port and launch the server:

```bash
HTTPD=~/.pi/agent/git/github.com/myk-org/pi-config/scripts/httpd.py
PORT=$(uv run python3 $HTTPD --find-port)
nohup uv run python3 $HTTPD --port $PORT --dir /path/to/serve > ${PROJECT_TMP_DIR}/httpd-$PORT.log 2>&1 &
disown
sleep 0.5
if ! kill -0 $! 2>/dev/null; then echo "Server failed to start:"; cat ${PROJECT_TMP_DIR}/httpd-$PORT.log; fi
```

3. Tell the user: `http://localhost:<PORT>/<filename>`
4. Keep the server running until the user confirms they're done

| Parameter | Description |
|-----------|-------------|
| `--find-port` | Returns an available port number |
| `--port <N>` | Port to serve on |
| `--dir <path>` | Directory containing files to serve |

> **Note:** `nohup` + `disown` are required because `uv run` creates a parent process chain. Works in both containers (`--network host`) and native installs.

---

## 50 — Agent Bug Reporting

**File:** `rules/50-agent-bug-reporting.md`

Defines the process for reporting logic bugs discovered in specialist agent configurations. Applies only to agents defined in the `agents/` directory.

### Covered Agents

api-documenter, bash-expert, code-reviewer-quality, code-reviewer-guidelines, code-reviewer-security, debugger, docs-fetcher, docker-expert, ts-expert, git-expert, github-expert, go-expert, java-expert, jenkins-expert, kubernetes-expert, planner, python-expert, reviewer, scout, security-auditor, technical-documentation-writer, test-automator, test-runner, worker

> **Note:** Built-in pi agents and agents from other sources are **not** covered by this rule.

### Trigger Conditions

| Trigger | Not a Trigger |
|---------|---------------|
| Flawed logic in agent instructions | Runtime errors (network, missing files) |
| Agent producing incorrect results due to config | External tool failures |
| Behavior contradicting intended purpose | User code bugs |
| Instructions causing systematic errors | Expected behavior user disagrees with |

### Workflow

1. Orchestrator discovers agent logic bug
2. Asks user: "I found a logic bug in [agent]. Do you want me to create a GitHub issue for this?"
3. If user confirms → delegate to `github-expert` to create issue in `myk-org/pi-config`
4. Continue with original task

### Issue Format

| Field | Content |
|-------|---------|
| Title | `bug(agents): [agent-name] - brief description` |
| Repository | `myk-org/pi-config` |
| Body sections | Agent, Bug Description, Expected Behavior, Actual Behavior, Impact, Suggested Fix, Context |

---

## 55 — Coms Protocol

**File:** `rules/55-coms-protocol.md`

Inter-agent communication protocol for talking between pi sessions. See [Communicating Between Pi Sessions](inter-agent-communication.html) for a usage guide.

### Communication Systems

| System | Activation | Tool Prefix | Transport |
|--------|-----------|-------------|-----------|
| P2P | `/coms start` | `coms_` | Direct peer-to-peer |
| Networked | `/coms-net start` | `coms_net_` | Hub server relay |

Both systems can be active simultaneously. When listing peers or sending messages, try both systems.

### Tool Reference

| Action | P2P Tool | Networked Tool |
|--------|----------|----------------|
| List peers | `coms_list` | `coms_net_list` |
| Send message | `coms_send` | `coms_net_send` |
| Poll for response | `coms_get` | `coms_net_get` |
| Block until response | `coms_await` | `coms_net_await` |

### Inbound vs Outbound Messages

| Direction | How to Reply |
|-----------|-------------|
| **Inbound** (message received from peer) | Write your answer as normal assistant text — the `agent_end` hook automatically sends it back. **Do not** call any send tool. |
| **Outbound** (initiating a conversation) | Call `coms_send` / `coms_net_send`, then `coms_await` / `coms_net_await` for the response. |

### Outbound Example (P2P)

```text
1. coms_list                          # Find available peers
2. coms_send(peer="pi-2", msg="...")  # Send the question
3. coms_await                         # Wait for response (ESC to interrupt)
```

### Message Queue

Messages are processed in **FIFO order**. If multiple messages arrive while the peer is busy, they queue — nothing is dropped. Each message gets a dedicated turn and response.

### Structured Task Delegation

Send structured tasks with the `tasks` parameter:

```text
coms_send(target="coder", prompt="Implement these features", tasks=[
  {"subject": "Add auth middleware", "description": "JWT validation for all /api routes"},
  {"subject": "Write tests", "description": "Unit tests for auth middleware"}
])
```

---

## 60 — Task Tracking

**File:** `rules/60-task-tracking.md`

Mandatory task creation and tracking for multi-step workflows (3+ steps). Tasks persist across turns and provide automatic workflow resume after interruptions.

### When to Create Tasks

| Condition | Create Tasks? |
|-----------|---------------|
| Multi-step workflow (3+ steps) | Yes |
| Feature implementation | Yes |
| Bug fixes with multiple files | Yes |
| Issue-first or code-review workflows | Yes |
| Refactoring across multiple files | Yes |
| Single-step actions | No |
| Questions or explanations | No |
| `/btw` side questions | No |
| Trivial fixes | No |

### Task Lifecycle

1. **Create** all tasks before starting work (`TaskCreate`)
2. **Mark `in_progress`** via `TaskUpdate` before starting each task
3. **Mark `completed`** via `TaskUpdate` immediately after finishing each task
4. Work through tasks in order — do not skip
5. Do not start new work while unchecked tasks exist (unless user explicitly pivots)

### Task Granularity

Tasks must be **specific and actionable**, not high-level summaries:

```text
# Good — specific steps
- Investigate root cause in extensions/orchestrator/utils.ts
- Create GitHub issue with root cause analysis
- Create branch fix/issue-N-description from origin/main
- Edit extensions/orchestrator/utils.ts — add timeout parameter
- Run code review loop (3 async reviewers)
- Fix review findings (if any)
- Run test-automator
- Commit changes
- Push branch to origin
- Create PR with description
```

### Async Agent taskId

Every async agent call **must** include `taskId`. This is enforced by the subagent tool.

| Scenario | taskId Value | Behavior |
|----------|-------------|----------|
| Agent linked to a task | Task ID (e.g., `"5"`) | Task auto-completes on success |
| Agent not linked to a task | `"-1"` | No auto-completion |

```text
# Linked to task 5 — auto-completes on success
subagent(agent="code-reviewer-quality", task="...", cwd="...",
         async=true, name="Review Quality", taskId="5")

# Not linked to any task
subagent(agent="worker", task="...", cwd="...",
         async=true, name="Qodo Poll", taskId="-1")
```

> **Warning:** Async calls without `taskId` are rejected. Never manually `TaskUpdate` a task to `completed` if it has an async agent — the agent handles it automatically.

### Enforcement

The extension injects reminders if tasks are ignored for 4+ consecutive turns. Tasks persist in the task widget and are injected into every turn context.

## Related Pages

- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Specialist Agents Reference](agents-reference.html)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Working with Project Memory](memory-system.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)

---

Source: extension-architecture.md

# Extension Architecture and Lifecycle Hooks

Every feature in pi-config — from blocking dangerous git commands to auto-injecting memories into system prompts — is powered by the **extension system**. Understanding how extensions register tools, commands, and event hooks is essential whether you're modifying an existing module or building a new one. This page explains the architecture end-to-end: how extensions load, what APIs are available, and when each lifecycle hook fires during a session.

## Why This Matters

When you type a message in pi, dozens of extension hooks fire in sequence: validating your environment, injecting memories into the system prompt, intercepting bash commands, and updating the status bar. Each of these behaviors is a discrete module registered through the same `ExtensionAPI` interface. Knowing where to plug in means you can:

- Add a new tool the LLM can call (like `ask_user` or `generate_image`)
- Intercept and block dangerous commands before they execute
- Inject context into system prompts before each agent turn
- React to session events (start, shutdown, compaction) for housekeeping
- Register slash commands users invoke directly

## The Big Picture: Extension Loading

Pi discovers extensions through the `pi` field in `package.json`:

```json
{
  "pi": {
    "extensions": ["./extensions"],
    "prompts": ["./prompts"]
  }
}
```

Pi scans the `extensions/` directory and loads every subdirectory that contains an `index.ts` with a default export function. Each extension receives a single `ExtensionAPI` instance:

```typescript
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";

export default function (pi: ExtensionAPI) {
  // Register tools, commands, and event hooks here
}
```

### Extension Inventory

Pi-config ships seven extensions, each independently loadable:

| Extension | Entry Point | Purpose |
|-----------|-------------|---------|
| **orchestrator** | `extensions/orchestrator/index.ts` | Core brain — agent routing, enforcement, rules, memory, dreaming, async agents, cron, status line |
| **coms** | `extensions/coms/index.ts` | Inter-agent P2P and networked communication |
| **pidash** | `extensions/pidash/index.ts` | Live web dashboard connection |
| **pidiff** | `extensions/pidiff/index.ts` | Diff viewer with review comments |
| **image-gen** | `extensions/image-gen/index.ts` | Image generation via Gemini API |
| **acpx-provider** | `extensions/acpx-provider/index.ts` | Route LLM requests through external AI agents |
| **shared** | `extensions/shared/` | Utility library (not a standalone extension — imported by pidash/pidiff) |

> **Note:** Each extension loads in its own call. The orchestrator extension is the largest — it internally wires 18+ modules via dedicated `register*()` functions. Standalone extensions like `image-gen` can be as simple as a single `registerTool()` call.

### The Orchestrator's Internal Module System

The orchestrator extension doesn't put all logic in one file. Instead, `index.ts` imports specialized modules and calls their registration functions in a specific order:

```
registerExtendedAutocomplete(pi)    ← MUST be first (wraps registerCommand)
registerAskUser(pi, ...)
registerAsyncAgents(pi, ...)        ← returns spawnAsyncAgent, killAsyncAgent
registerSubagentTool(pi, ...)       ← receives async agent functions
registerProjectSettings(pi)
registerEnforcement(pi, ...)
registerRules(pi, ...)              ← receives getAsyncJobs for status injection
registerStatusLine(pi, ...)
registerBtw(pi)
registerDreaming(pi, ...)
registerCron(pi, ...)
registerSessionValidation(pi)
registerGithubAutocomplete(pi)
registerStatus(pi, ...)
registerNvim(pi)
registerPreferenceExtractor(pi)
registerMemoryTools(pi)
registerSessionSearch(pi)
```

> **Warning:** Order matters. `registerExtendedAutocomplete` wraps `pi.registerCommand` to inject argument completions, so it **must** run before any other module calls `registerCommand`. Similarly, `registerAsyncAgents` returns functions that `registerSubagentTool` and `registerDreaming` depend on.

## The Four Registration APIs

Extensions interact with pi through four primary registration methods on the `ExtensionAPI` object:

### 1. `pi.registerTool()` — LLM-Callable Tools

Tools are functions the AI can invoke during a conversation. Each tool has a schema, an async `execute` function, and optional rendering hooks for the TUI.

```typescript
pi.registerTool({
  name: "ask_user",
  label: "Ask User",
  description: "Present a question to the user with selectable options.",
  promptSnippet: "Ask the user a question with selectable options",
  promptGuidelines: [
    "Use ask_user when you need user input during a workflow.",
    "Do NOT ask users questions via plain text.",
  ],
  parameters: Type.Object({
    question: Type.String({ description: "The question to display" }),
    options: Type.Optional(Type.Array(Type.String())),
  }),
  async execute(_id, params, signal, onUpdate, ctx) {
    // Tool implementation — return { content: [...] }
  },
  renderCall(args, theme, context) { /* TUI display for tool invocation */ },
  renderResult(result, options, theme, context) { /* TUI display for result */ },
});
```

**Key properties:**

| Property | Required | Purpose |
|----------|----------|---------|
| `name` | Yes | Unique identifier the LLM calls |
| `description` | Yes | Tells the LLM when/how to use this tool |
| `promptSnippet` | No | Short description injected into the system prompt |
| `promptGuidelines` | No | Array of usage instructions injected into the system prompt |
| `parameters` | Yes | TypeBox schema defining the tool's input parameters |
| `execute` | Yes | Async function that runs when the LLM calls this tool |
| `renderCall` | No | Custom TUI rendering for the tool invocation |
| `renderResult` | No | Custom TUI rendering for the tool result |

**Registered tools in pi-config:** `subagent`, `ask_user`, `memory_search`, `memory_reinforce`, `memory_add`, `memory_remove`, `memory_edit`, `memory_reflect`, `memory_consolidate`, `memory_topics`, `session_search`, `cron_manage`, `generate_image`, plus coms tools.

### 2. `pi.registerCommand()` — Slash Commands

Commands are user-invoked actions triggered by typing `/command-name` in the input. They run directly — no LLM roundtrip needed.

```typescript
pi.registerCommand("btw", {
  description: "Ask a quick side question without polluting conversation history",
  getArgumentCompletions: (prefix: string) => { /* optional Tab completions */ },
  handler: async (args, ctx) => {
    // Command implementation
    ctx.ui.notify("Done!", "info");
  },
});
```

**Key properties:**

| Property | Required | Purpose |
|----------|----------|---------|
| `description` | Yes | Shown in command help/autocomplete |
| `handler` | Yes | Async function receiving `(args: string, ctx)` |
| `getArgumentCompletions` | No | Returns autocomplete suggestions for Tab |

**User-visible effect:** Users type `/btw what does this function do?` and get an instant response without the AI processing a full turn. See [Slash Commands and Extension Commands Reference](commands-reference.html) for all available commands.

> **Tip:** The orchestrator wraps `pi.registerCommand` to capture every command handler into a shared registry. This lets the pidash web dashboard execute commands remotely from the browser. If you register commands in a separate extension, use `pi.events` to bridge them (see the inter-extension communication section below).

### 3. `pi.on()` — Event Hooks

Event hooks are the backbone of the extension system. They let you react to (and modify) every phase of a pi session. Each hook receives an `event` object and a `ctx` context.

```typescript
pi.on("session_start", async (event, ctx) => {
  // Runs once when a session begins
});

pi.on("before_agent_start", async (event, ctx) => {
  // Runs before each LLM turn — can modify the system prompt
  return { systemPrompt: event.systemPrompt + "\n\nExtra instructions" };
});
```

The full lifecycle hook reference is in the next section.

### 4. `pi.registerProvider()` — Model Providers

Provider registration lets extensions add custom LLM backends. The ACPX provider extension uses this to route requests through external AI agents:

```typescript
pi.registerProvider(`acpx-${agent}`, {
  // Provider configuration for model discovery and request routing
});
```

This is an advanced API primarily used by the `acpx-provider` extension. Most extensions won't need it.

## Lifecycle Hooks in Detail

Hooks fire at specific points during a pi session. Some are informational (observe only), while others can **modify** behavior by returning values.

### Hook Execution Timeline

Here is the order hooks fire during a typical session:

1. **`session_start`** — Session begins (or resumes)
2. **`input`** — User types a message
3. **`before_agent_start`** — Just before the LLM processes the message
4. **`agent_start`** — LLM turn begins
5. **`tool_call`** — LLM requests a tool execution *(can block)*
6. **`tool_result`** / **`tool_execution_end`** — Tool finishes
7. **`turn_end`** — One LLM turn completes (may loop back to step 5 for multi-turn)
8. **`agent_end`** — Full agent response complete
9. *(repeat steps 2–8 for each user message)*
10. **`session_compact`** — Session history compacted (summarized)
11. **`session_shutdown`** — Session ends

### Hook Reference

| Hook | Can Modify? | Event Data | When It Fires |
|------|:-----------:|------------|---------------|
| `session_start` | No | `event`, `ctx` (with `ctx.cwd`, `ctx.hasUI`, `ctx.mode`) | Once when session opens or resumes |
| `input` | No | `event.text` — the user's raw message | Every user message, before LLM processing |
| `before_agent_start` | **Yes** | `event.systemPrompt`, `event.prompt` | Before each LLM turn; return `{ systemPrompt }` to modify |
| `tool_call` | **Yes** | `event.input` (tool parameters), tool name via `isToolCallEventType()` | Before a tool executes; return `{ block: true, reason }` to prevent |
| `tool_result` | No | Tool output data | After a tool completes |
| `tool_execution_end` | No | Tool execution metadata | After tool execution fully finishes |
| `turn_end` | No | `event.response`, `event.toolResults` | After one LLM turn completes |
| `agent_start` | No | — | When the LLM begins processing |
| `agent_end` | No | — | When the full agent response is done |
| `model_select` | No | Model selection data | When the user switches models |
| `session_compact` | No | Compaction/summary data | When session history is summarized |
| `session_shutdown` | No | — | When the session is ending |

### How Each Hook Is Used

**`session_start`** — Initialization and environment validation:
- Check for required CLI tools (`uv`, `gh`, `mcpl`) and notify about missing ones
- Bootstrap vector embeddings for semantic memory search
- Rebuild and reorganize memory scores
- Connect to daemons (pidash, pidiff)
- Start background pollers (git status every 5s, timestamp updates every 30s)
- Clean up zombie async agents from dead parent processes
- Restore persisted cron tasks

**`input`** — Passive observation of user messages:
- Extract user preferences ("I prefer...", "always use...", "never...") and write them to memory automatically
- Track session keywords for session search indexing

**`before_agent_start`** — System prompt augmentation (the most powerful hook):
- Prepend the **situation report** (scored, token-budgeted memory summary)
- Run **vector search** against the user's message and inject contextually relevant memories
- Inject **past session summaries** matching the current topic
- Append all **orchestrator rules** (from `rules/*.md` files)
- Append **async agent status** so the LLM knows what's running in the background

> **Note:** The `before_agent_start` hook is what makes memory, rules, and context injection work. Without it, the LLM would have no knowledge of your preferences, past decisions, or orchestrator rules. See [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html) for the injection pipeline details.

**`tool_call`** — Command enforcement (the gatekeeper):
- Block `python`/`pip` (require `uv` wrapper)
- Block `git commit`/`push` outside the `git-expert` agent
- Block commits to protected branches
- Block `git add .` (require specific file staging)
- Block remote script execution (`curl | sh`)
- Block dangerous commands (require user confirmation)
- Block repeated identical commands (anti-polling-spam)
- Inject co-author trailers into git commits
- Strip timeouts from long-running poll commands

> **Note:** This is a representative sample. The full enforcement ruleset — including blocking sleep loops, direct docker/podman CLI in containers, memory writes from subagents, and git hooks bypass — is documented in [Command Safety Guards and Enforcement](command-enforcement.html).

**`turn_end`** — Post-turn analysis:
- Update git status in the status bar
- Check modified files against memory for contextual reminders
- Track retrieval telemetry (were injected memories used in the response?)

**`session_shutdown`** — Cleanup:
- Index session summary for future keyword search
- Trigger a final dream (memory consolidation) if enabled
- Disconnect from daemons
- Stop cron tasks and pollers
- Clean up temp files

### The Social Closer Gate

Not every message deserves expensive processing. The `before_agent_start` hook skips vector search and session history injection for trivial messages like "ok", "thanks", "👍", or short emoji-only messages. This is the **social closer gate** — it prevents wasted computation on messages that don't need contextual memory:

```
"ok", "yes", "no", "thanks", "thank you", "got it", "sure",
"right", "correct", "agreed", "nice", "cool", "great", "perfect",
"👍", "🙏", "✅", "👌", "🎉", "💯", "🚀"
```

## Inter-Extension Communication

Extensions are loaded independently, but they often need to coordinate. Pi-config uses the **`pi.events` bus** — a typed event emitter shared across all extensions — for cross-extension communication.

### Common Event Patterns

| Event | Emitter | Listener | Purpose |
|-------|---------|----------|---------|
| `pidash:register-command` | orchestrator | pidash | Share command handlers for browser execution |
| `pidash:request-commands` | pidash | orchestrator | Request replay of all registered commands |
| `pidash:command-ctx` | orchestrator | pidash | Share the latest command context |
| `pidash:ui-request` | orchestrator (ask_user) | pidash | Forward user prompts to browser |
| `pidash:ui-response` | pidash | orchestrator (ask_user) | Return browser answers to TUI |
| `pidash:async-status` | orchestrator | pidash | Forward async agent status updates |
| `pidash:async-kill` | pidash | orchestrator | Kill async agents from browser |
| `diff-viewer:port` | pidiff | pidash | Share the diff viewer port |

This pattern solves the **extension load order problem**: pidash may load before or after the orchestrator, but the event replay mechanism ensures command handlers are always available.

```typescript
// Orchestrator: emit on registration
pi.events.emit("pidash:register-command", { name, handler });

// Pidash: listen and request replay
pi.events.on("pidash:register-command", (data) => { /* store handler */ });
pi.events.emit("pidash:request-commands"); // trigger replay of all handlers
```

## Mode-Aware Guards

Pi runs in four modes, and not all extension features make sense in every mode. Use `ctx.mode` to conditionally enable features:

| Mode | Description | Available Features |
|------|-------------|--------------------|
| `"tui"` | Interactive terminal session | Everything — full UI, daemons, autocomplete |
| `"rpc"` | Programmatic API access | Tools, hooks, notifications — no autocomplete |
| `"json"` | Structured output (one-shot) | Tools and hooks only — no timers, daemons |
| `"print"` | Single response (one-shot) | Tools and hooks only — no timers, daemons |

Use `ctx.hasUI` when you just need to know whether UI methods (`notify`, `select`, `confirm`) are available — this returns `true` for both `tui` and `rpc` modes.

```typescript
// Only connect to daemons in interactive mode
if (ctx.mode === "tui") { connectToDaemon(); }

// Only show notifications when UI is available (tui or rpc)
if (ctx.hasUI) { ctx.ui.notify("Task completed", "info"); }

// Skip timers in one-shot modes
if (ctx.mode !== "print" && ctx.mode !== "json") { startCronScheduler(); }
```

## Subagent Isolation

When the orchestrator delegates to a specialist agent, the child process runs with `PI_SUBAGENT_CHILD=1` in its environment. Many extension modules check this flag to avoid duplicate behavior:

```typescript
// Only the orchestrator registers memory tools
if (process.env.PI_SUBAGENT_CHILD === "1") return;
```

**Modules that skip registration in subagents:**
- Memory tools (read-only access via rules injection)
- Preference extractor
- Dreaming
- Async agent infrastructure
- Autocomplete providers
- Session search
- Cron scheduling
- Pidash/pidiff connections

**What subagents DO get:**
- Enforcement rules (tool_call blocking)
- The situation report (injected via `before_agent_start` with a "do NOT write to memory" instruction)
- Status line updates

## Writing a New Extension Module

To add a new module to the orchestrator extension:

1. **Create the module file** in `extensions/orchestrator/`:
   ```typescript
   import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";

   export function registerMyFeature(pi: ExtensionAPI): void {
     if (process.env.PI_SUBAGENT_CHILD === "1") return; // if orchestrator-only

     pi.on("session_start", (_event, ctx) => {
       // Initialize on session start
     });

     pi.registerCommand("my-command", {
       description: "Does something useful",
       handler: async (args, ctx) => { /* ... */ },
     });
   }
   ```

2. **Import and wire it** in `extensions/orchestrator/index.ts`:
   ```typescript
   import { registerMyFeature } from "./my-feature.js";
   // ... inside the default export function:
   registerMyFeature(pi);
   ```

3. **Consider ordering** — if your module wraps `registerCommand` or depends on functions returned by another module, place it at the right point in the registration sequence.

To create a **standalone extension** (separate from the orchestrator):

1. Create a new directory under `extensions/` with an `index.ts`:
   ```typescript
   import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";

   export default function (pi: ExtensionAPI) {
     pi.registerTool({ /* ... */ });
   }
   ```

2. Pi will auto-discover and load it alongside the other extensions.

> **Tip:** Keep standalone extensions independent — they should work even if the orchestrator extension isn't loaded. Use `pi.events` for optional coordination with other extensions.

## Related Pages

- [Orchestrator Rules Reference](rules-reference.html) — the rules files loaded by the `before_agent_start` hook
- [Specialist Agents Reference](agents-reference.html) — how agents are discovered and routed by the subagent tool
- [Slash Commands and Extension Commands Reference](commands-reference.html) — all registered commands
- [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html) — the memory injection pipeline in `before_agent_start`
- [Configuration and Environment Variables Reference](configuration-reference.html) — settings that control extension behavior (`PI_PIDASH_ENABLE`, `PI_DREAM_INTERVAL_HOURS`, etc.)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) — how `registerAsyncAgents` and `registerCron` work from the user's perspective
- [Command Safety Guards and Enforcement](command-enforcement.html) — full enforcement ruleset applied by the `tool_call` hook
- [Customization and Extension Recipes](customization-recipes.html) — step-by-step guides for adding agents, commands, and project settings

## Related Pages

- [Orchestrator Rules Reference](rules-reference.html)
- [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html)
- [Specialist Agents Reference](agents-reference.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: memory-internals.md

# Memory Scoring, Embeddings, and Situation Reports

Pi's memory system doesn't just store facts — it *forgets* them. Like biological memory, entries that aren't reinforced fade over time, while frequently referenced knowledge becomes stronger. This means the context injected into every conversation is always relevant, concise, and current — without any manual curation.

This page explains the internal mechanics: how scores are calculated, how vector embeddings power semantic recall, how topic files organize knowledge, and how the situation report compresses it all into a token budget for every system prompt.

> **Note:** For hands-on usage — adding memories, searching, dreaming, and capacity management — see [Working with Project Memory](memory-system.html). This page covers the *engine underneath*.

## Architecture Overview

The memory system is a four-layer pipeline. Each layer has a distinct job:

| Layer | Module | Responsibility |
|-------|--------|----------------|
| **1. Scored Memory** | `memory-scoring.ts` | Stability formula, decay, evidence counting, lifecycle states |
| **2. Topic Tree** | `memory-tree.ts` | Markdown topic files — the source of truth for all entries |
| **3. Vector Embeddings** | `memory-embeddings.ts` | Semantic search via in-process ONNX model (bge-small-en-v1.5) |
| **4. Situation Report** | `situation-report.ts` | Token-budgeted, priority-ordered context block for system prompts |

These layers feed into an **auto-injection pipeline** (`rules.ts`) that runs on every turn — inserting the right memories at the right time without any user action.

### Data Flow: From Entry to System Prompt

1. A memory is added (via `memory_add` tool, preference auto-extraction, or dreaming)
2. A vector similarity check runs against existing entries in the same category (≥ 0.85 = near-duplicate → reinforce instead of adding)
3. If not a duplicate, the entry is written to the appropriate topic file under `.pi/memory/topics/`
4. A stability score is computed and stored in `memory-scores.json`
5. The entry is embedded as a 384-dim vector and stored in `embeddings.json`
5. On each turn, `before_agent_start` fires:
   - The situation report selects scored entries within a token budget
   - A vector search finds contextually relevant memories for the current message
   - Past session summaries are keyword-searched for additional context
6. All three blocks are prepended to the system prompt

## Layer 1: Stability-Based Scoring

Every memory entry has a **stability score** that decays exponentially over time. The score determines whether an entry stays active, gets demoted, or is dropped entirely.

### The Stability Formula

```
stability = cue_weight × exp(-Δt / half_life) × ln(1 + evidence_count)
```

| Component | What It Measures | Effect |
|-----------|-----------------|--------|
| `cue_weight` | How the memory was produced | Explicit (user-stated) memories start stronger |
| `exp(-Δt / half_life)` | Time since last reinforcement | Exponential decay — old, unreinforced memories fade |
| `ln(1 + evidence_count)` | How many times it's been reinforced | Logarithmic boost — first few reinforcements matter most |

Two special cases override the formula:

- **Pinned entries** → score is always `9999` (never decay)
- **Forgotten entries** → score is always `0` (always dropped)

### Cue Weights

Not all evidence is equal. The source of the memory affects its initial strength:

| Cue Type | Weight | When Used |
|----------|--------|-----------|
| `explicit` | 1.0 | User explicitly said "remember this", or added via `memory_add` |
| `structural` | 0.9 | Derived from project structure or configuration |
| `behavioral` | 0.7 | Observed from user behavior patterns (auto-extracted) |
| `recurrence` | 0.6 | Detected from recurring patterns across sessions |

### Decay Half-Lives

Each memory category decays at a different rate, reflecting how long that type of knowledge typically stays relevant:

| Category | Half-Life | Rationale |
|----------|-----------|-----------|
| `preference` | 90 days | Personal preferences change slowly |
| `lesson` | 60 days | Learned knowledge stays relevant for weeks |
| `pattern` | 30 days | Code patterns can shift with refactors |
| `decision` | 30 days | Architectural decisions may be revisited |
| `done` | 14 days | Completed work becomes irrelevant quickly |
| `mistake` | 14 days | Mistakes are worth remembering briefly, then usually resolved |

> **Tip:** Calling `memory_reinforce` on an entry resets its decay clock and bumps the evidence count. This is the primary mechanism for keeping important memories alive. The orchestrator is instructed to do this automatically whenever it notices a memory is relevant to the current task.

### Lifecycle States

Based on its stability score, every entry is assigned a lifecycle state:

| State | Score Threshold | Meaning |
|-------|----------------|---------|
| `active` | ≥ 1.5 | Included in the situation report |
| `provisional` | ≥ 0.7 | Overflow — included if budget allows |
| `candidate` | ≥ 0.4 | At risk of being dropped |
| `dropped` | < 0.4 | Not injected, may be archived |

The lifecycle state is recalculated during **rebuild cycles** which happen:
- On every `session_start`
- Every 30 minutes (cheap, no LLM call — just rescores existing entries)
- After dreaming completes

### Budget Caps

To prevent any single category from dominating the context window, per-category budget caps limit how many entries can be `active`:

| Category | Max Active Entries |
|----------|--------------------|
| `preference` | 8 |
| `lesson` | 8 |
| `pattern` | 6 |
| `decision` | 4 |
| `done` | 4 |
| `mistake` | 4 |

Entries that exceed their category budget are demoted to `provisional`. A cross-category **overflow pool** of 6 slots holds the highest-scoring provisional entries. The **total cap** across all categories is 40 active entries.

## Layer 2: Topic Tree Organization

All memory entries live in Markdown files under `.pi/memory/topics/`. These files are the **source of truth** — the scoring layer reads from them, not the other way around.

```
.pi/memory/
├── memory-scores.json       # Stability scores (auto-managed)
├── embeddings.json           # Vector embeddings (auto-managed)
└── topics/
    ├── preferences.md        # [preference] entries
    ├── lessons.md            # [lesson] entries
    ├── patterns.md           # [pattern] entries
    ├── decisions.md          # [decision] entries
    ├── completions.md        # [done] entries
    └── mistakes.md           # [mistake] entries
```

Each topic file uses a simple format:

```markdown
# Preferences

- [preference] Always use --admin for gate-blocked PRs *(pinned)*
- [preference] User prefers concise responses
- [preference] Use conventional commits for commit messages
```

### Size Limits

Each topic file is capped at **~12,000 characters** (roughly 3,000 tokens). When a topic file would exceed this limit, `memory_add` refuses the write and instructs the LLM to consolidate or remove entries first.

### Topic Hotness

Each topic has a **hotness score** — the sum of stability scores for all entries in the topic. Hotter topics are prioritized in the situation report. Topics that go cold (no reinforcement for 2× the category's half-life) are automatically archived (deleted), unless they contain pinned entries.

### Category-to-Topic Mapping

| Category | Topic File |
|----------|------------|
| `preference` | `preferences.md` |
| `lesson` | `lessons.md` |
| `pattern` | `patterns.md` |
| `decision` | `decisions.md` |
| `done` | `completions.md` |
| `mistake` | `mistakes.md` |

## Layer 3: Vector Embeddings

Vector embeddings enable **semantic search** — finding memories that are conceptually related to a query even when they don't share any keywords. This powers both the `memory_search` tool and the automatic contextual injection on every turn.

### Model Details

| Property | Value |
|----------|-------|
| Model | `Xenova/bge-small-en-v1.5` |
| Dimensions | 384 |
| Runtime | ONNX via `@huggingface/transformers` (in-process, no Python) |
| Download size | ~50 MB (first run only) |
| Init time | ~2.7 seconds (first call per session) |
| Search latency | ~2.5 ms per query |
| API keys | None — runs entirely locally |

### How It Works

1. **Embed on write:** When `memory_add` creates an entry, it's immediately embedded and the vector is stored in `.pi/memory/embeddings.json`
2. **Dedup on write:** Before inserting a new entry, `memory_add` computes vector similarity against all existing entries in the same category. If a near-duplicate is found (similarity ≥ 0.85), the existing entry is **reinforced** instead of creating a duplicate. This catches semantically equivalent memories even when worded differently (e.g., "use conventional commits" vs. "always write conventional commit messages"). If the vector check is unavailable, the system falls back to exact text matching.
3. **Embed on first search:** If any existing entries lack embeddings (e.g., after upgrading from a pre-embedding version), the first `memory_search` call batch-embeds all missing entries
4. **Search:** The query is embedded, then cosine similarity is computed against all stored vectors
5. **Hybrid results:** Vector search results are merged with keyword search results, deduplicated, and ranked by a combined score (similarity × 100 + stability score)

### Embedding Key Format

Each embedding is keyed by a truncated SHA-256 hash of `[category] text` — this prevents cross-category collisions where the same text appears in different categories.

### Near-Duplicate Detection Threshold

The dedup similarity threshold is **0.85** (cosine similarity). This value balances precision and recall:

| Similarity | Behavior |
|------------|----------|
| ≥ 0.85 | Treated as near-duplicate — existing entry is reinforced, new entry is not added |
| 0.65–0.84 | Treated as contextually relevant (used for search recall), but distinct enough to store separately |
| < 0.65 | Not related — no match |

> **Note:** If the dedup check reinforces an existing entry, the just-embedded vector for the new text is removed from the store to keep embeddings clean.

### Graceful Fallback

If the `@huggingface/transformers` package is unavailable or the model fails to load, the system falls back to **keyword-only search** and **exact-match dedup**. No errors are thrown — callers always get results.

> **Note:** Embeddings are stored per-project in `.pi/memory/embeddings.json`. The model is loaded once per process and cached for the session lifetime.

## Layer 4: Situation Reports

The situation report is the final output of the memory system — a structured, priority-ordered Markdown block injected into the system prompt on every turn. It replaces a raw dump of all memories with a curated, token-budgeted summary.

### Token Budget

The default budget is **1,700 tokens**. The actual budget is dynamically adjusted based on the size of the system prompt (rules, skills, context files):

```
available_memory_budget = min(1700, 8000 - system_prompt_tokens)
```

If the system prompt already consumes the entire 8,000-token budget, memory injection is skipped entirely.

### Section Priority

The report is built section-by-section in priority order. Higher-priority sections are always included; lower-priority sections are truncated or dropped when the budget runs out:

| Priority | Section | Token Budget | Filter |
|----------|---------|--------------|--------|
| — | **Pinned** | Unlimited | All pinned entries (always first) |
| 1 | Active Preferences | 400 | `preference` entries |
| 2 | Active Lessons | 400 | `lesson` entries |
| 3 | Vetoes & Mistakes | 200 | `mistake` entries |
| 4 | Patterns | 200 | `pattern` entries |
| 5 | Recent Decisions | 200 | `decision` entries from last 7 days |
| 6 | Recent Completions | 200 | `done` entries from last 3 days |

Within each section, entries are sorted by stability score (highest first). If a section exceeds its token budget, lower-scored entries are omitted with a count indicator (e.g., "... 3 more (lower priority, omitted for context budget)").

### Capacity Signal

The report header displays current usage as a percentage:

```
# Project Memory [72% — 1,224/1,700 tokens]
```

When usage exceeds **80%**, a consolidation warning is injected:

```
> ⚠️ Memory above 80% capacity. Before adding new entries, consolidate or
> remove existing ones using memory_remove.
```

This warning is visible to the LLM, which then knows to consolidate before adding more entries.

### Ground Truth Instruction

Every situation report includes a Ground Truth instruction:

> **Ground Truth:** Memories above and contextually relevant memories injected below are authoritative. Use them directly — do not re-discover or re-verify information already in your context window.

This prevents the LLM from wasting tokens re-verifying facts it already has in context.

## The Auto-Injection Pipeline

The `rules.ts` module orchestrates all memory injection through lifecycle hooks. Here's what happens on each turn:

### On `session_start`

1. Run `rebuildAndOrganize()` — rescore all entries from topic files
2. Bootstrap vector embeddings — embed any entries missing from the store
3. Reset dream state and start timers (rebuild every 30 min, dream every 3 hours)

### On `before_agent_start` (every turn)

This is the main injection point. The system prompt is constructed in this order:

1. **Situation report** — scored, token-budgeted memory summary
2. **Contextual memory recall** — vector search against the user's current message (top 5, similarity > 0.65)
3. **Session history recall** — keyword search against past conversation summaries (top 3)
4. **Original system prompt** — the agent's base instructions
5. **Orchestrator rules** — all `rules/*.md` files (orchestrator only)
6. **Async agent status** — what background agents are currently running

> **Note:** The social closer gate skips vector and session search for trivial messages ("ok", "thanks", "yes", emoji-only). This avoids wasting computation on messages that don't need contextual recall.

### On `turn_end`

After each response, two things happen:

1. **Retrieval telemetry** — logs whether injected memories were actually referenced in the LLM's response (written to `.pi/data/memory-telemetry.jsonl`)
2. **File-change memory reminder** — if the LLM modified files during the turn, a vector search runs against the modified file paths. Relevant memories (similarity > 0.70) are surfaced as a follow-up reminder

### On `input` (Preference Auto-Extraction)

The preference extractor (`preference-extractor.ts`) listens to every user message and pattern-matches for preference signals:

| Pattern | Example |
|---------|---------|
| "I prefer..." | "I prefer tabs over spaces" |
| "Always use..." | "Always use conventional commits" |
| "Never use..." | "Never use sudo in containers" |
| "From now on..." | "From now on, run tests before committing" |
| "My timezone..." | "My timezone is UTC+2" |

Detected preferences are automatically added to `preferences.md` with `cue: explicit` scoring. If the preference already exists, it's reinforced instead. A 1-hour cooldown prevents the same preference from being re-extracted repeatedly.

### On `session_shutdown`

1. Accumulated user messages are indexed into the session search store (`.pi/data/session-search.json`, max 500 entries)
2. If auto-dreaming is enabled, a background dream is fired (detached process — survives session exit)

## Retrieval Telemetry

Every auto-injection is logged to `.pi/data/memory-telemetry.jsonl` with:

- **Injection events** — what memories were injected, the truncated prompt that triggered them
- **Usage events** — whether the LLM actually referenced injected memories in its response, with a usage rate (`usedCount / injectedCount`)
- **Session injection events** — when past session summaries are injected

The file is capped at 500 KB (older entries trimmed to the last 200 lines).

> **Tip:** This telemetry helps you understand which memories are being used and which are being ignored — useful for tuning memory quality over time.

## Storage File Reference

| File | Format | Purpose |
|------|--------|---------|
| `.pi/memory/topics/*.md` | Markdown | Source of truth — all memory entries |
| `.pi/memory/memory-scores.json` | JSON | Stability scores, evidence counts, lifecycle states |
| `.pi/memory/embeddings.json` | JSON | Vector embeddings (384-dim float arrays keyed by SHA-256 hash) |
| `.pi/data/session-search.json` | JSON | Past conversation summaries for keyword search |
| `.pi/data/memory-telemetry.jsonl` | JSONL | Retrieval telemetry logs |
| `.pi/memory/.dream-watermark` | Plaintext | Timestamp of last dream — prevents reprocessing |

## Extension Points

If you're modifying the memory system or building on top of it, here are the key functions and hooks:

### Scoring Functions (`memory-scoring.ts`)

| Function | Signature | Purpose |
|----------|-----------|---------|
| `calculateStability()` | `(cue, evidenceCount, lastReinforcedAt, nowMs, category, userState) → number` | Core scoring formula |
| `lifecycleFromScore()` | `(score, userState) → LifecycleState` | Map score to lifecycle state |
| `rebuild()` | `(cwd, entries) → RebuildResult` | Full rebuild cycle: score all entries, apply budgets |
| `reinforce()` | `(cwd, entryLine) → boolean` | Bump evidence count for an entry |
| `getActiveEntries()` | `(cwd) → {hash, entry}[]` | Get all active/provisional entries, sorted by score |
| `entryHash()` | `(text) → string` | FNV-1a hash for entry keys |
| `extractPreferences()` | `(text) → string[]` | Pattern-match preference statements from text |

### Embedding Functions (`memory-embeddings.ts`)

| Function | Signature | Purpose |
|----------|-----------|---------|
| `initEmbeddings()` | `() → Promise<boolean>` | Initialize the ONNX model (lazy, cached) |
| `embedEntry()` | `(cwd, text, category?) → Promise<void>` | Embed and store a single entry |
| `removeEmbedding()` | `(cwd, text, category?) → void` | Remove an entry's embedding |
| `vectorSearch()` | `(cwd, query, entries, topK?) → Promise<results[]>` | Semantic search by cosine similarity |
| `embedMissing()` | `(cwd, entries) → Promise<number>` | Batch-embed entries without existing embeddings |

### Situation Report Functions (`situation-report.ts`)

| Function | Signature | Purpose |
|----------|-----------|---------|
| `buildSituationReport()` | `(cwd, tokenBudget?) → string` | Build the token-budgeted Markdown report |
| `rebuildAndOrganize()` | `(cwd) → void` | Rescore all entries from topic files |
| `estimateMemoryBudget()` | `(systemPromptLength, totalBudget?) → number` | Dynamic budget based on system prompt size |

### Lifecycle Hooks

| Hook | When | What the memory system does |
|------|------|-----------------------------|
| `session_start` | Session begins | Rebuild scores, bootstrap embeddings, start timers |
| `before_agent_start` | Every turn | Inject situation report + contextual memories + session history |
| `turn_end` | After each response | Log retrieval telemetry, file-change memory reminders |
| `input` | User types a message | Auto-extract preferences |
| `session_compact` | Context compaction | Index compacted summary for session search |
| `session_shutdown` | Session ends | Index accumulated messages, trigger background dream |

## Related Pages

- [Working with Project Memory](memory-system.html) — hands-on guide to using the memory system: adding, searching, dreaming, and managing capacity
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html) — how hooks like `before_agent_start` and `turn_end` work in the extension system
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) — how dreaming runs as an async background agent
- [Configuration and Environment Variables Reference](configuration-reference.html) — `PI_DREAM_INTERVAL_HOURS` and other memory-related settings
- [Orchestrator Rules Reference](rules-reference.html) — the `35-memory.md` rule that governs LLM memory behavior

## Related Pages

- [Working with Project Memory](memory-system.html)
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Orchestrator Rules Reference](rules-reference.html)

---

Source: acpx-provider.md

# Using ACPX Provider for External Agent Models

Route pi's LLM requests through external coding agents like Cursor, Codex, Gemini, or Copilot — so you can use their exclusive models (e.g., Cursor's GPT-5.4, Codex's o3-pro) as if they were native pi models. This lets you switch between providers mid-session without leaving pi.

## Prerequisites

- **acpx** installed globally: `npm install -g acpx@latest`
- The external agent's CLI installed and authenticated (e.g., Cursor CLI with a valid `auth.json`)
- The `ACPX_AGENTS` environment variable set with the agents you want to use

## Quick Start

Set the environment variable and start pi:

```bash
export ACPX_AGENTS=cursor
pi
```

Pi discovers all models available through Cursor and registers them as selectable models. Switch to a Cursor model using pi's model selector, and all subsequent LLM requests flow through Cursor's backend.

## Step-by-Step Setup

### 1. Install acpx

```bash
npm install -g acpx@latest
```

> **Tip:** The native installer (`scripts/install.py`) includes acpx in its Node.js tools checklist and will offer to install it for you.

### 2. Install and authenticate the target agent

Each agent requires its own CLI to be installed and authenticated. For example, for Cursor you need the Cursor CLI agent installed with a valid authentication token.

### 3. Configure ACPX_AGENTS

Set the `ACPX_AGENTS` environment variable to a comma-separated list of agents:

```bash
# Single agent
export ACPX_AGENTS=cursor

# Multiple agents
export ACPX_AGENTS=cursor,gemini,copilot
```

Agent names must be lowercase alphanumeric (with hyphens and underscores allowed). Invalid names are silently ignored.

**In Docker**, add this to your `.env` file:

```env
ACPX_AGENTS=cursor
```

And mount the agent's auth file. For Cursor:

```bash
-v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro
```

See [Running Pi in a Docker Container](docker-deployment.html) for the full Docker setup.

### 4. Start a pi session

```bash
pi
```

On session start, you'll see a notification for each configured agent:

```
acpx-cursor: 12 models discovered
```

The discovered models are now available in pi's model selector. Each model is named with the pattern `Model Name (agent)` — for example, `Gpt 5.4 (cursor)`.

### 5. Select an ACPX model

Use pi's model switching to pick an ACPX model. Model IDs follow the format `agent:model-id` — for example, `cursor:gpt-5.4` or `gemini:gemini-2.5-pro`.

Once selected, all pi LLM requests — including orchestrator reasoning, agent delegation, and tool calls — are routed through that external agent.

## How It Works

When you select an ACPX model, pi creates a persistent session with the external agent. The key behaviors:

- **Persistent sessions** — each agent maintains its own conversation history on its side. Pi sends only the latest user message per turn, not the full conversation.
- **System prompt** — pi's system prompt is sent once at session creation time, instructing the external agent to act as a backend LLM.
- **Per-model sessions** — switching between models on the same agent creates separate sessions, so each model gets its own conversation context.
- **Automatic cleanup** — all ACPX sessions are gracefully closed when your pi session ends.

## ACPX Provider vs /external-ai vs /acpx-prompt

Pi offers three ways to use external agents. Each serves a different purpose:

| Feature | ACPX Provider | `/external-ai` | `/acpx-prompt` |
|---------|--------------|----------------|----------------|
| **What it does** | Routes pi's LLM backend through an external agent | Sends a one-off prompt via ai-cli-runner subprocess | Sends a prompt to any ACP-compatible agent via acpx |
| **Model integration** | Full — model appears in pi's model selector | None — runs as a CLI subprocess | None — runs as a slash command |
| **Conversation context** | Maintains persistent session with external agent | Stateless by default (supports `--resume`) | Stateless by default (supports `--resume`) |
| **Supported agents** | Any agent in `ACPX_AGENTS` | cursor, claude, gemini only | All ACP agents (codex, copilot, droid, kiro, etc.) |
| **File modification** | Yes (through pi's normal tools) | Only with `--fix` flag | Only with `--fix` flag |
| **Peer review** | No | Yes (`--peer`) | Yes (`--peer`) |
| **Use case** | Use an external model as pi's brain | Get a second opinion, run a code review | Delegate tasks to any ACP-compatible agent |

**When to use which:**

- **ACPX Provider** — you want pi to *think* using Cursor's GPT-5.4 or another exclusive model for all interactions
- **`/external-ai`** — you want to send a quick prompt to cursor, claude, or gemini and get a response back (see [Using Slash Commands and Prompt Templates](slash-commands.html))
- **`/acpx-prompt`** — you want to delegate a task to any ACP-compatible agent, including ones like codex, copilot, or droid (see [Using Slash Commands and Prompt Templates](slash-commands.html))

## Advanced Usage

### Multiple agents

Register several agents to access models from different providers simultaneously:

```env
ACPX_AGENTS=cursor,gemini,copilot
```

Each agent gets its own provider (`acpx-cursor`, `acpx-gemini`, `acpx-copilot`) and its own set of discovered models. You can switch between them at any time during a session.

### Default model

Every registered agent always has a `agent:default` model (e.g., `cursor:default`). This uses whatever model the agent considers its default — no explicit model selection on the agent side.

### Model naming

ACPX model IDs include capability metadata in brackets. For example, a model might be listed internally as `gpt-5.4[context=272k,supports=vision]`. In pi's model selector, this appears with a cleaned-up display name like `Gpt 5.4 (cursor)`, but the full ID with brackets is used when communicating with the agent.

### Non-blocking startup

Model discovery runs in the background after session start. If you switch to an ACPX model before discovery completes, pi waits for it to finish before sending the first request. This means your session starts instantly — no delay from agent handshakes.

### Subagent behavior

ACPX providers are only loaded in the parent pi session. Subagents (specialist agents spawned by the orchestrator) use the parent's model via the `--model` flag and do not spawn their own ACPX runtimes. This avoids unnecessary agent connections and prevents nested session conflicts.

## Troubleshooting

### "no models discovered" warning

This means pi connected to the agent but couldn't retrieve its model list.

- Verify the agent CLI is installed and authenticated
- Check that the agent is running and responsive
- For Cursor in Docker, ensure `auth.json` is mounted correctly:
  ```bash
  -v "$HOME/.config/cursor/auth.json":"$HOME/.config/cursor/auth.json":ro
  ```

### "runtime init failed" in debug output

The ACPX runtime couldn't start for the given agent.

- Ensure `acpx` is installed: `npm install -g acpx@latest`
- The `acpx` npm package must also be in pi-config's dependencies (it is by default)
- Check that the agent name in `ACPX_AGENTS` is spelled correctly (lowercase, alphanumeric only)

### "Unknown acpx agent" error during streaming

This happens if you try to use a model ID for an agent that wasn't in `ACPX_AGENTS` at session start. Restart your pi session with the correct `ACPX_AGENTS` value.

### Model discovery is slow

Discovery creates a temporary session with each agent to query available models. If an agent CLI is slow to initialize, this can take several seconds. Since discovery runs in the background, it won't block your session — but model completions won't appear in the selector until discovery finishes.

### Session state directory

ACPX sessions store state files under `~/.acpx/pi-<pid>/`. These are cleaned up automatically on session shutdown. If pi exits unexpectedly, stale state files may remain — they are safe to delete:

```bash
rm -rf ~/.acpx/pi-*
```

> **Note:** For full environment variable documentation including `ACPX_AGENTS`, see [Configuration and Environment Variables Reference](configuration-reference.html).

## Related Pages

- [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)

---

Source: discord-bot.md

# Controlling Pi Sessions from Discord

Send prompts, answer agent questions, and monitor your pi sessions from anywhere — including your phone — by connecting a Discord bot to the pidash server.

## Prerequisites

- A running pidash server (see [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html))
- A Discord account with a server you control
- `discord.js` installed (included in pi-config's dependencies by default)

## Quick Start

```bash
# Create the Discord configuration file
cat > ~/.pi/discord.env << 'EOF'
DISCORD_BOT_TOKEN=your-bot-token-here
DISCORD_ALLOWED_USERS=your-discord-user-id
EOF

# Restart the pidash server to pick up the new config
/pidash restart
```

Once connected, open a DM with your bot in Discord and type `/sessions` to see your active pi sessions.

## Step-by-Step Setup

### 1. Create a Discord Bot

1. Go to the [Discord Developer Portal](https://discord.com/developers/applications)
2. Click **New Application** → name it (e.g., "pi-agent")
3. Go to **Bot** → click **Reset Token** → copy the token
4. Enable **Message Content Intent** under **Privileged Gateway Intents**
5. Go to **OAuth2 > URL Generator** → select scope `bot` → select these permissions:
   - Send Messages
   - Read Message History
   - Add Reactions
   - View Channels
6. Open the generated URL in your browser → add the bot to your server

### 2. Find Your Discord User ID

1. In Discord, go to **Settings > Advanced** and turn on **Developer Mode**
2. Right-click your own username anywhere in Discord
3. Click **Copy User ID**

### 3. Configure the Bot

Create `~/.pi/discord.env` with your bot token and user ID:

```bash
cat > ~/.pi/discord.env << 'EOF'
DISCORD_BOT_TOKEN=MTIz...your-bot-token
DISCORD_ALLOWED_USERS=123456789012345678
EOF
```

To allow multiple users, separate IDs with commas:

```
DISCORD_ALLOWED_USERS=123456789012345678,987654321098765432
```

> **Note:** These variables can also be set in your regular environment instead of `~/.pi/discord.env`. The pidash server reads the env file at startup and loads any variables not already set in the environment.

### 4. Start the Bot

Restart the pidash server so it picks up the new configuration:

```
/pidash restart
```

The bot logs in automatically. Check the pidash log for confirmation:

```
[discord] bot connected as pi-agent#1234
[discord] allowed users: 123456789012345678
```

## Using Discord Slash Commands

The bot registers three slash commands in every Discord server it joins. These are available immediately — no propagation delay.

| Command | Description |
|---------|-------------|
| `/sessions` | List all active pi sessions with interactive buttons |
| `/status` | Show details of the session you're currently watching |
| `/stop` | Interrupt the current agent (equivalent to pressing Esc in the terminal) |

### Listing and Watching Sessions

Type `/sessions` in any channel where the bot is present. The bot responds with a list of all active sessions and a button for each one:

- **Blue buttons** — active, idle sessions
- **Green button** — the session you're currently watching
- **Red "Disconnect" button** — stop watching all sessions

Tap a session button to start watching it. The bot's activity status updates to show the session name and model.

### Checking Session Status

Use `/status` to see details about the session you're watching:

- Project name and working directory
- Current model
- Git branch
- Active/idle status
- Whether it's running in a container

## Sending Prompts via DM

Once you're watching a session, open a DM with the bot. Any text you send is forwarded directly to the watched pi session as a user prompt — exactly as if you typed it in the terminal.

```
Refactor the auth middleware to use JWT tokens instead of session cookies
```

The bot shows a typing indicator while pi is processing your prompt. When the assistant responds, the full response text is forwarded back to your DM.

> **Tip:** User messages sent from the TUI terminal also appear in your Discord DM (prefixed with `▶ USER:`), so you can follow along from Discord even when someone else is typing in the terminal.

### Sending Images

Attach an image to your DM message. The bot downloads it, converts it to base64, and forwards it to the pi session alongside any text you include. This works for screenshots, diagrams, or any visual context pi's model can interpret.

### Sending Text Files

Attach text files (`.txt`, `.md`, `.json`, `.py`, `.ts`, `.go`, `.yaml`, `.sh`, and many more) to your DM. The bot reads files under 100KB and appends their contents to your prompt. Binary files or files over 100KB are mentioned but not included.

### Using /stop in DMs

Type `/stop` as a plain DM message to interrupt the current agent. This works the same as the `/stop` slash command.

## Receiving ask_user Prompts

When pi's `ask_user` tool presents a question (approvals, selections, confirmations), the bot forwards it to your DM. You see:

- The question text in bold
- Numbered options (if applicable)
- A prompt to reply with your choice

Reply with the option number or type a free-text response. Your answer is sent back to the pi session, resolving the dialog.

> **Note:** The `ask_user` dialog races between the TUI and Discord — whichever responds first wins. If someone answers in the terminal, the Discord prompt becomes stale.

## Advanced Usage

### Multiple Users

Each Discord user has independent state — they can watch different sessions simultaneously. User state includes:

- Which session they're watching
- Their DM channel for responses
- Any pending `ask_user` dialog

State persists across pidash restarts (stored in `~/.pi/discord-state.json`), so you don't lose your watched session if the daemon restarts.

### Bot Activity Display

The bot's Discord "activity" shows the name and model of the currently watched session (displayed as "Watching project-name (model-name)"). This gives you an at-a-glance view of what the bot is connected to.

### How Events Flow

The Discord bot runs inside the pidash server daemon — no separate process, no extra ports to open:

1. **Discord app** (phone/desktop) connects outbound to Discord's cloud API
2. **Discord cloud** routes messages to the pidash server's bot client
3. **Pidash server** has direct access to all connected pi sessions
4. **Pi sessions** send events back through the same path

No inbound ports need to be opened. The bot initiates all connections to Discord's API.

### Echo Suppression

When you send a prompt from Discord, the bot suppresses the echo of your own message that would normally appear when pi receives it. You only see the assistant's response, not a duplicate of what you typed.

### Forwarded Event Types

The bot forwards these events from your watched session to your Discord DM:

| Event | What You See |
|-------|-------------|
| User message (from TUI) | `▶ USER: <message text>` |
| Assistant response complete | Full response text (chunked to fit Discord's 2000-char limit) |
| `ask_user` dialog | Question + numbered options |
| Agent working | Typing indicator in DM |

## Security Considerations

> **Warning:** If you omit `DISCORD_ALLOWED_USERS`, the bot accepts DMs from **anyone** who can message it. Always set this variable, especially in shared environments.

- **`DISCORD_ALLOWED_USERS`** is checked on every interaction — slash commands, button clicks, and DM messages. Unauthorized users receive a "Not authorized" response.
- The bot token grants full control over your pi sessions to allowed users — treat it like a password.
- Store `~/.pi/discord.env` with restrictive file permissions (`chmod 600`).
- Slash commands are registered per-guild (Discord server), so they only appear in servers the bot has joined.
- The bot only processes DMs (`d.guild_id` is checked) — messages in server channels are ignored for prompt forwarding.

```bash
# Lock down the config file
chmod 600 ~/.pi/discord.env
```

## Troubleshooting

**Bot doesn't connect:**
- Check `~/.pi/pidash-debug.log` for `[discord]` entries
- Verify `DISCORD_BOT_TOKEN` is correct in `~/.pi/discord.env`
- Confirm `discord.js` is installed (`npm list discord.js` in the pi-config package directory)

**Slash commands don't appear:**
- The bot registers commands per-guild on startup. If you added the bot to a new server, restart pidash: `/pidash restart`
- Guild-scoped commands are available immediately (no propagation delay unlike global commands)

**"Not authorized" on every interaction:**
- Double-check your Discord user ID in `DISCORD_ALLOWED_USERS` — it should be a numeric snowflake ID, not your username
- Make sure there are no extra spaces or quotes around the ID

**Messages not forwarded to DM:**
- You must be watching a session first — use `/sessions` and tap a button
- The watched session must be active and connected to pidash

**Bot shows "Watched session is disconnected":**
- The pi session you were watching has ended. Use `/sessions` to pick a new one

For pidash server management, see [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html). For all Discord-related environment variables, see [Configuration and Environment Variables Reference](configuration-reference.html).

## Related Pages

- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)

---

Source: neovim-integration.md

# Neovim Integration and Quickfix Support

When you run pi inside a Neovim `:terminal` buffer, it automatically detects the parent Neovim instance and unlocks the ability to send file lists directly to Neovim's quickfix window — letting you jump between changed files without leaving your editor.

## Prerequisites

- Neovim 0.5+ with the `--remote-expr` server feature (included in all modern builds)
- Pi must be started from a Neovim `:terminal` buffer (not an external terminal)
- A git repository with changed files (for `/nvim-changed-files`)

## Quick Example

Open a terminal inside Neovim and start pi:

```vim
:terminal pi
```

Then, inside the pi session, run:

```
/nvim-changed-files
```

Your quickfix window opens instantly with every file changed on your branch. Press `Enter` on any entry to jump to that file.

## How Automatic Detection Works

Pi checks for the `NVIM` environment variable, which Neovim sets automatically in every `:terminal` buffer. If `NVIM` is present, pi registers the Neovim integration commands. If it's absent (you're running pi in a regular terminal), the commands simply don't appear — no configuration needed.

> **Note:** The integration only activates for the main pi session, not for background subagents. This prevents background tasks from interfering with your quickfix list.

## Sending Changed Files to Quickfix

The `/nvim-changed-files` command collects all files that differ from the default branch and sends them to your quickfix list.

### What It Detects

| Scenario | Files Shown |
|----------|-------------|
| On a feature branch | All committed changes vs `origin/main` (or `origin/master`) **plus** any uncommitted working tree changes |
| On `main` or `master` | Uncommitted changes only (working tree diff against `HEAD`) |

Each quickfix entry shows the file path and its git status — `modified`, `added`, `deleted`, `renamed`, or `copied`.

### Navigating the Quickfix List

Once `/nvim-changed-files` populates the quickfix window, use standard Neovim quickfix commands:

| Command | Action |
|---------|--------|
| `:cnext` / `:cprev` | Jump to the next / previous file |
| `:cfirst` / `:clast` | Jump to the first / last file |
| `:copen` | Reopen the quickfix window if you closed it |
| `:cclose` | Close the quickfix window |
| `Enter` (in quickfix window) | Open the file under the cursor |

> **Tip:** Map `:cnext` and `:cprev` to convenient keybindings for fast navigation. For example, add to your Neovim config:
> ```vim
> nnoremap ]q :cnext<CR>
> nnoremap [q :cprev<CR>
> ```

## Typical Workflow

1. Start pi in a Neovim terminal: `:terminal pi`
2. Ask pi to implement a feature or fix a bug.
3. Run `/nvim-changed-files` to see which files were modified.
4. Navigate the quickfix list to review each change in your editor.
5. Make manual adjustments if needed, then return to the pi terminal buffer to continue.

This is especially useful after pi completes a multi-file change — you get an instant overview of every touched file without running `git diff --name-only` yourself.

## How Pi Communicates with Neovim

Pi communicates with the parent Neovim instance using Neovim's built-in RPC mechanism. The `NVIM` environment variable contains the path to Neovim's Unix domain socket. Pi uses `nvim --server <socket> --remote-expr` to execute Lua code in the parent Neovim process, which populates the quickfix list via `vim.fn.setqflist()` and opens it with `vim.cmd("copen")`.

All file paths are resolved to absolute paths before being sent, so quickfix entries work correctly regardless of your working directory.

> **Note:** The RPC call has a 5-second timeout. If Neovim is unresponsive (e.g., running a blocking plugin), pi displays a warning notification and continues without interruption.

## Advanced Usage

### Combining with Code Reviews

After running a code review with pi's review system, use `/nvim-changed-files` to load all modified files into quickfix. This gives you a checklist-style workflow — open each changed file, review pi's modifications, and move to the next one.

For details on the review system, see [Running the Automated Code Review Loop](code-review-loop.html).

### Using with Background Agents

Background agents (spawned via async delegation) do not interact with your Neovim quickfix list — only the main session has access. After a background agent completes its work, you can run `/nvim-changed-files` from the main session to see what changed.

For more on background agents, see [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

### Running Pi Outside Neovim

If you run pi in a standalone terminal (outside Neovim), the `/nvim-changed-files` command is not registered. Pi gracefully skips all Neovim integration when the `NVIM` environment variable is absent — no errors, no warnings, no performance impact.

## Troubleshooting

| Problem | Solution |
|---------|----------|
| `/nvim-changed-files` doesn't appear as a command | Verify you started pi from inside a Neovim `:terminal`. Check that `echo $NVIM` prints a socket path in your terminal. |
| "No changed files found" notification | You're on the default branch with no uncommitted changes, or git can't detect a diff base. Ensure you're on a feature branch with committed or staged changes. |
| "Failed to send quickfix to nvim" warning | The Neovim RPC call timed out or failed. Check that the parent Neovim instance is still running and responsive. Restarting Neovim and pi resolves most cases. |
| Quickfix shows files but paths are wrong | Make sure pi's working directory matches your project root. Pi resolves all paths to absolute paths, but a mismatched `cwd` can produce unexpected results. |

## Related Pages

- [Running the Automated Code Review Loop](code-review-loop.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Your First Coding Workflow](first-workflow.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: image-generation.md

# Generating Images with the generate_image Tool

Create AI-generated images directly from your pi session using natural language or structured parameters, powered by Google's Gemini API.

## Prerequisites

- A **Google Gemini API key** — get one from [Google AI Studio](https://aistudio.google.com/apikey)
- A Gemini model that supports image generation (e.g., `gemini-2.0-flash-exp` or `gemini-3-pro-image`)

## Quick Example

Set the required environment variables, then ask pi to generate an image:

```bash
export GEMINI_API_KEY="AIzaSy..."
export PI_IMAGE_MODEL="gemini-3-pro-image"
```

Then in your pi session:

```
Generate an image of a golden retriever playing fetch on a beach at sunset
```

Pi calls the `generate_image` tool, saves the resulting image to `.pi/tmp/` in your project directory, and returns the file path.

## Setup

Both environment variables are required — without them, `generate_image` returns an error.

| Variable | Description |
|----------|-------------|
| `PI_IMAGE_MODEL` | Gemini model name (e.g., `gemini-3-pro-image`). No default — must be set explicitly. |
| `GEMINI_API_KEY` or `GOOGLE_API_KEY` | Your Google Gemini API key. Either variable name works. |

**For Docker containers**, add both to your `.env` file:

```env
GEMINI_API_KEY=AIzaSy...
PI_IMAGE_MODEL=gemini-3-pro-image
```

Then pass the file with `--env-file /path/to/.env` in your `docker run` command. See [Running Pi in a Docker Container](docker-deployment.html) for the full container setup.

> **Note:** Changes to environment variables require restarting your pi session to take effect.

## Using the Tool

You can ask for images conversationally — pi translates your request into structured parameters automatically. You can also specify parameters explicitly for more control.

### Parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `subject` | **Yes** | Main subject of the image |
| `action` | No | What the subject is doing |
| `scene` | No | Location or environment |
| `composition` | No | Camera angle and framing |
| `lighting` | No | Lighting setup |
| `style` | No | Artistic style (e.g., photorealistic, watercolor, pixel art) |
| `text` | No | Text to render inside the image |
| `aspect_ratio` | No | Image dimensions ratio (defaults to model default) |

### Supported Aspect Ratios

| Ratio | Use Case |
|-------|----------|
| `1:1` | Square — social media avatars, icons |
| `3:4` | Portrait — mobile wallpapers |
| `4:3` | Landscape — presentations |
| `9:16` | Tall portrait — phone screens, stories |
| `16:9` | Widescreen — desktop wallpapers, banners |

## Example Prompts

Here are different ways to ask pi for images, demonstrating the range of styles and parameters:

**Simple request:**
```
Generate an image of a mountain landscape
```

**With style and lighting:**
```
Generate an image of a cat sitting on a windowsill, watercolor style, warm afternoon lighting
```

**With composition and scene:**
```
Generate an image: subject is a vintage typewriter, scene is a cluttered writer's desk,
composition is close-up overhead shot, lighting is soft lamp light, style is photorealistic
```

**With text overlay:**
```
Generate an image of a coffee mug on a table, text "Good Morning", style is minimalist flat design
```

**Specific aspect ratio for a phone wallpaper:**
```
Generate a 9:16 image of a starry night sky over a forest, style is digital painting
```

**Pixel art style:**
```
Generate a 1:1 image of a knight fighting a dragon, pixel art style
```

## Advanced Usage

### How Images Are Saved

Generated images are saved to `.pi/tmp/` inside your project directory with auto-generated filenames. Pi reports the full file path in its response, so you can open, copy, or move the file.

### Automatic HTTP Preview in Containers

When running pi inside a Docker container, you can't open local file paths directly in your browser. Pi detects the container environment automatically and spins up an HTTP server to serve the generated image.

After generating an image in a container, pi returns both the file path and a preview URL:

```
Generated 1 image(s):
  /tmp/pi-work/my-project/pi-image-1717123456-a1b2c3.png
  Preview: http://localhost:38291/pi-image-1717123456-a1b2c3.png
```

Open the preview URL in your browser to view the image.

> **Note:** The preview server requires `--network host` on your container. This is already included in the standard Docker run command. See [Running Pi in a Docker Container](docker-deployment.html) for details.

On native (non-container) installs, no HTTP server is started — you can open the saved file directly.

### Request Timeout

Image generation requests time out after **3 minutes**. Complex prompts with detailed parameters may take longer than simple ones, but should complete well within this limit.

## Troubleshooting

**"Error: PI_IMAGE_MODEL environment variable is not set"**
- Set `PI_IMAGE_MODEL` to a valid Gemini image model name and restart pi.

**"Error: No API key found"**
- Set either `GEMINI_API_KEY` or `GOOGLE_API_KEY` and restart pi.

**"Image generation blocked by safety filter"**
- The prompt triggered Gemini's content safety filters. Rephrase your request to avoid restricted content.

**"No image data returned from Gemini"**
- The model processed the request but didn't produce an image. Try rephrasing or simplifying the prompt. Verify your model name supports image generation.

**Preview URL not working in Docker**
- Ensure your container was started with `--network host` so the preview server is accessible from the host browser.

## Related Pages

- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)

---

Source: command-enforcement.md

# Command Safety Guards and Enforcement

Pi operates with full access to your shell, file system, and git history. That power requires guardrails. The enforcement system is a set of runtime checks that intercept every `bash` command before it executes — blocking dangerous patterns, protecting git branches, and preventing common mistakes that could damage your environment or waste resources.

You don't need to configure enforcement — it's always active. But understanding what it blocks (and why) helps you work with the guardrails instead of fighting them.

## How Enforcement Works

Every time pi (or any specialist agent) calls the `bash` tool, the command passes through a chain of checks in `enforcement.ts`. Each check can:

- **Allow** the command (no interference)
- **Block** the command with an error message explaining what to do instead
- **Prompt for confirmation** (dangerous commands only, when a UI is available)
- **Silently modify** the command (co-author trailers, timeout stripping — rare cases)

Checks run in order. The first check that returns a block stops execution immediately — the command never reaches your shell.

## Blocked Commands

### Python and pip

| Blocked | Use Instead |
|---------|-------------|
| `python script.py` | `uv run script.py` |
| `python3 -m pytest` | `uv run python3 -m pytest` |
| `pip install requests` | `uv add requests` or `uv run --with requests script.py` |
| `pip3 freeze` | `uv pip freeze` |

Pi enforces the use of `uv` for all Python execution. This keeps dependencies managed per-execution without polluting the environment. The check catches `python` and `pip` (and their `3` variants) at the start of a command or after pipe/semicolon/`&&` operators.

> **Note:** Commands that already start with `uv` or `uvx` are not affected — the check only targets bare `python`/`pip` invocations.

### Pre-commit

| Blocked | Use Instead |
|---------|-------------|
| `pre-commit run --all-files` | `prek run --all-files` |

Direct `pre-commit` invocations are blocked. Use the `prek` wrapper instead.

### Remote Script Execution

Pi blocks all forms of piping remote content into a shell or interpreter:

| Pattern | Example |
|---------|---------|
| Pipe to shell | `curl https://example.com/install.sh \| bash` |
| Pipe to interpreter | `wget https://example.com/setup.py \| python3` |
| Process substitution | `bash <(curl https://example.com/install.sh)` |
| Command substitution | `sh -c "$(curl https://example.com/install.sh)"` |
| Eval with download | `` eval `curl https://example.com/config` `` |

**What to do instead:** Download the script first, have the `security-auditor` agent review it, then run it manually if it's safe.

> **Tip:** The check is smart about heredocs — if a `curl | bash` pattern appears inside heredoc content (like documentation examples), it won't trigger a false positive.

### Staging All Files

| Blocked | Use Instead |
|---------|-------------|
| `git add .` | `git add src/main.py src/utils.py` |
| `git add --all` | `git add src/main.py src/utils.py` |
| `git add -A` | `git add src/main.py src/utils.py` |

Pi requires staging specific files to prevent accidentally committing generated files, secrets, or unrelated changes.

### Staging Gitignored Files

If you try to `git add` a file that matches a pattern in `.gitignore`, the command is blocked. Pi runs `git check-ignore` on each file in the `git add` command to catch this.

### Bypassing Git Hooks

| Blocked | Why |
|---------|-----|
| `git commit --no-verify` | Pre-commit hooks must always run |
| `git -c core.hooksPath=/dev/null commit ...` | Disabling hooks via config is not allowed |

### Sleep and Polling Loops

| Blocked | Use Instead |
|---------|-------------|
| `while true; do check; sleep 10; done` | Spawn an async subagent for polling |
| `sleep 120` (standalone, > 30s) | Spawn an async subagent |

Blocking the session with long sleeps or polling loops wastes resources. Pi's async agent system is designed for exactly these cases — see [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

> **Note:** `sleep` commands of 30 seconds or less outside of loops are allowed. Inside loops, the threshold is 5 seconds.

### Temp File Location

| Blocked | Use Instead |
|---------|-------------|
| `mktemp /tmp/foo.XXXXXX` | `mktemp ${PROJECT_TMP_DIR}/foo.XXXXXX` |

All temp files must go to the project-scoped temp directory (`.pi/tmp/`), which is already gitignored. This prevents cluttering system-level `/tmp/` and ensures cleanup on session end.

## Git Branch Protection

Pi enforces a branch-based workflow to prevent accidental changes to production code.

### Protected Branches

For GitHub repositories, pi queries the GitHub API to discover branches marked as protected and always includes `main` and `master`. For non-GitHub repos, only `main` and `master` are protected.

The following operations are blocked on protected branches:

| Operation | Error |
|-----------|-------|
| `git commit` on a protected branch | "Cannot commit to 'main' (protected). Create a feature branch." |
| `git push` while on a protected branch | "Cannot push to 'main' (protected). Create a feature branch." |
| `git push origin main` (explicit target) | "Cannot push to 'main' (protected). Create a feature branch." |

> **Tip:** Protected branch information is cached per session — it's fetched once from the GitHub API and reused for all subsequent checks.

### Detached HEAD Detection

If you're in a detached HEAD state (not on any branch), commits are blocked. Create a branch first:

```
git checkout -b my-feature-branch
```

### Merged Branch Detection

Pi detects two kinds of "already merged" situations:

1. **PR already merged** — If a GitHub PR for the current branch has been merged, further commits and pushes are blocked. Create a new branch from the main branch instead.
2. **Branch merged locally** — If the current branch has been merged into the main branch (checked via `git merge-base --is-ancestor`), commits and pushes are blocked.

Both checks prevent the common mistake of continuing to work on a branch after its PR has been merged.

### Git Commit and Push Agent Restriction

Only the `git-expert` specialist agent is allowed to run `git commit` and `git push`. If any other agent (or the orchestrator) attempts these commands, they are blocked with a message directing the work to `git-expert`.

## Worktree Enforcement

When `use_worktrees` is enabled in your project settings (`.pi/pi-config-settings.json`) or via the `PI_USE_WORKTREES` environment variable, pi blocks branch switching commands:

| Blocked | Use Instead |
|---------|-------------|
| `git checkout feature-branch` | `git worktree add .worktrees/feature-branch -b feature-branch main` |
| `git switch feature-branch` | `git worktree add .worktrees/feature-branch -b feature-branch main` |

> **Note:** `git checkout -- file.txt` (restoring a file, not switching branches) is still allowed — the check looks for the `--` separator.

This prevents branch switching when multiple agents may be working in the same worktree simultaneously. See [Configuration and Environment Variables Reference](configuration-reference.html) for how to enable this setting.

## Dangerous Command Confirmation

Some commands are not blocked outright but require explicit user confirmation before running. These are matched by pattern:

| Pattern | Example Commands |
|---------|-----------------|
| `rm -rf` / `rm --recursive` | `rm -rf /path/to/dir` |
| `sudo` | `sudo apt install ...` |
| `chmod 777` / `chown 777` | `chmod 777 /var/www` |
| `mkfs` | `mkfs.ext4 /dev/sda1` |
| `dd of=/dev/` | `dd if=image.iso of=/dev/sdb` |

When pi detects one of these patterns, it shows a confirmation prompt:

```
⚠️ Dangerous command:

  rm -rf /path/to/old-builds

Allow? [Yes / No]
```

If no UI is available (e.g., running in JSON or print mode), the command is blocked entirely — there's no way to confirm.

## Docker-Safe Wrapper

When pi runs inside a Docker or Podman container, direct `docker` and `podman` CLI commands are blocked. Instead, pi uses the `docker-safe` wrapper script, which only allows read-only inspection commands:

| Allowed via docker-safe | Blocked |
|------------------------|---------|
| `ps`, `logs`, `inspect` | `exec`, `run`, `rm` |
| `top`, `stats`, `port` | `cp`, `build`, `pull` |
| `diff`, `images` | `stop`, `start`, `kill` |
| `version`, `info` | Everything else |

Usage:

```bash
docker-safe ps -a
docker-safe logs my-container --tail 50
docker-safe --runtime podman inspect my-container
```

The runtime defaults to `docker` but can be switched to `podman` via the `--runtime` flag or the `DOCKER_SAFE_RUNTIME` environment variable.

> **Note:** This restriction only applies when pi is running inside a container. Native installations are not affected.

## Memory Write Restrictions

Specialist agents (subagents) cannot write to the project memory system. Only the orchestrator — the top-level pi session — is allowed to add or delete memories.

| Agent Type | `memory add` | `memory search` |
|------------|-------------|----------------|
| Orchestrator | ✅ Allowed | ✅ Allowed |
| Specialist agent | ❌ Blocked | ✅ Allowed |

This prevents specialist agents from creating conflicting or redundant memory entries. Specialists can read memories to inform their work, but any learned insights must be surfaced to the orchestrator for storage. See [Working with Project Memory](memory-system.html) for how memory works.

## Repeat Command Detection

Pi tracks consecutive identical bash commands at the orchestrator level. If the same command is executed **3 or more times in a row**, it's blocked:

```
⛔ Same command executed 3 times in a row.
Use a subagent with async: true for polling/monitoring instead of repeating the command.
```

This catches runaway loops where the LLM keeps retrying a failing command. The detection normalizes commands by stripping `cd` prefixes and whitespace, so `cd /tmp && ls` and `cd /tmp  &&  ls` are treated as the same command.

Repeat state is stored per session in a temp file (`.pi/tmp/.repeat-<pid>.json`) and only applies to the orchestrator — specialist agents are not tracked.

## Async-Only Agent Enforcement

Certain long-running agents are enforced to always run asynchronously. If you (or the LLM) try to dispatch them synchronously, the system automatically promotes the call to `async: true`:

- `code-reviewer-quality`
- `code-reviewer-guidelines`
- `code-reviewer-security`

These agents cannot be used in chain mode either — they must be dispatched as independent async tasks.

This prevents the session from blocking while waiting for code reviews, which can take minutes. See [Running the Automated Code Review Loop](code-review-loop.html) for how reviews work in practice.

## Co-Author Trailer Injection

While not a safety guard, the enforcement system also handles co-author trailers. When `co_author` is enabled in project settings, pi automatically appends a `Co-authored-by:` line to git commit messages. This is a transparent modification — the command runs with the trailer added, and the user sees the full commit message.

## What to Do When a Command Is Blocked

Every block message includes:

1. **What was blocked** — the exact command or pattern
2. **Why it was blocked** — a brief explanation
3. **What to do instead** — the correct alternative command or approach

In most cases, the LLM adjusts automatically after receiving the block message. If you're running commands manually and encounter a block:

- **Read the suggestion** — the error message always provides an alternative
- **Use the correct tool** — `uv run` instead of `python`, `docker-safe` instead of `docker`, specific file paths instead of `git add .`
- **Delegate to the right agent** — `git-expert` for commits, async subagents for polling
- **Ask pi for help** — describe what you're trying to do and let it route to the appropriate approach

> **Warning:** These guardrails exist to protect your environment. While the enforcement system can't cover every possible dangerous command, it catches the most common patterns that lead to accidental damage, security issues, or wasted resources.

## Related Pages

- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) — how async agents work as an alternative to polling loops and long sleeps
- [Running the Automated Code Review Loop](code-review-loop.html) — the async-only review agents in practice
- [Running Pi in a Docker Container](docker-deployment.html) — container setup and the docker-safe wrapper
- [Configuration and Environment Variables Reference](configuration-reference.html) — project settings like `use_worktrees` and `co_author`
- [Working with Project Memory](memory-system.html) — memory tools and the orchestrator-only write restriction
- [Orchestrator Rules Reference](rules-reference.html) — the full set of rules that govern orchestrator behavior

## Related Pages

- [Specialist Agents Reference](agents-reference.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)
- [Running Pi in a Docker Container](docker-deployment.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Orchestrator Rules Reference](rules-reference.html)

---
