# 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 running so you can start delegating coding tasks to an orchestrator backed by 24 specialist agents. Choose between Docker (sandboxed, all dependencies included) or native installation on your own machine.

## Prerequisites

- **Node.js 22+** — required by pi itself ([download](https://nodejs.org) or `nvm install 22`)
- **Git** — version control (`apt install git` / `brew install git`)
- **pi** — the coding agent that pi-config extends (`npm install -g @earendil-works/pi-coding-agent`)
- **An LLM provider** — pi needs an API key for at least one provider (Anthropic, Google Vertex AI, etc.). See [Configuration and Environment Variables Reference](configuration-reference.html) for all supported providers.

## Quick Start (Docker)

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

docker run --rm -it \
  --name "pi-session" \
  --network host \
  -e ANTHROPIC_API_KEY="sk-ant-..." \
  -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. The container installs pi, pulls pi-config, and drops you into an interactive session. Type a task and the orchestrator takes over.

## Installation Methods

### Option A: Docker Container (Recommended)

The Docker image ships with every tool pre-installed — GitHub CLI, Python (uv), Go, kubectl, browser automation, and more. Your host filesystem is protected; the agent can only access mounted directories.

**1. Pull the image:**

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

**2. Create an environment file** at `~/.pi/.env`:

```env
# Timezone
TZ=America/New_York

# Host username — maps container home to /home/<user> so host paths resolve
PI_HOST_USER=your-username

# LLM provider (at least one required)
# Option A: Anthropic direct
ANTHROPIC_API_KEY=sk-ant-xxx

# Option B: Google Cloud / Vertex AI
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=us-east5
GOOGLE_APPLICATION_CREDENTIALS=/home/your-username/.config/gcloud/application_default_credentials.json

# GitHub (required for PR/issue workflows)
GITHUB_TOKEN=ghp_xxx
GH_CONFIG_DIR=/home/your-username/.config/gh
```

> **Note:** Use your actual home path in the env file — the `PI_HOST_USER` setting creates a symlink inside the container so these paths resolve correctly.

**3. Run the container:**

```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 \
  -v /tmp/pi-work:/tmp/pi-work:rw \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

On first start, the entrypoint automatically:

1. Installs/updates pi to the latest version
2. Installs pi-config (orchestrator, agents, prompts)
3. Installs companion packages (pi-web-access, pi-tasks)
4. Installs the myk-pi-tools CLI
5. Configures the global gitignore for memory and worktree directories
6. Starts an interactive pi session

> **Tip:** A `WARNING` on stderr about packages already being cached is normal. If pi doesn't start, check your network connectivity.

For a permanent shell alias, see [Running Pi in a Docker Container](docker-deployment.html).

### Option B: Native Installation

For running pi directly on your machine without Docker.

**1. Install prerequisites:**

```bash
# Node.js 22+
nvm install 22

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

# uv (Python package manager — required for Python tools)
curl -LsSf https://astral.sh/uv/install.sh | sh
```

**2. Run the interactive installer:**

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

The installer walks you through five steps with multi-select checkboxes:

| Step | What it installs |
|------|-----------------|
| Pi Packages | pi-config, pi-vertex-claude, pi-web-access, pi-tasks, myk-pi-tools, bun |
| Python Tools | mcp-launchpad (mcpl), prek |
| npm Packages | acpx, agent-browser |
| Browser Automation | Playwright + Chromium |
| Environment Setup | Adds `.pi/memory/`, `.worktrees/`, `.pi/tasks/` to global gitignore |

Select only what you need — each tool shows whether it's already installed.

> **Tip:** For non-interactive CI environments, run `uv run scripts/install.py --all` to install everything without prompts.

**3. Start a session:**

```bash
cd your-project
pi
```

## Configuring Prerequisites

### GitHub CLI (gh)

The GitHub CLI is required for PR reviews, issue creation, and release workflows. It's pre-installed in the Docker image.

**Native installation:**

```bash
# macOS
brew install gh

# Linux (Debian/Ubuntu)
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \
  | sudo gpg --dearmor -o /usr/share/keyrings/githubcli-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \
  | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
sudo apt update && sudo apt install gh
```

**Authenticate:**

```bash
gh auth login
```

For Docker, mount your gh config directory: `-v "$HOME/.config/gh":"$HOME/.config/gh":ro`

### API Keys

Pi needs credentials for at least one LLM provider. Pass them as environment variables:

| Provider | Environment Variable |
|----------|---------------------|
| Anthropic (direct) | `ANTHROPIC_API_KEY` |
| Google Vertex AI | `GOOGLE_CLOUD_PROJECT`, `GOOGLE_CLOUD_LOCATION`, `GOOGLE_APPLICATION_CREDENTIALS` |
| Gemini (image generation) | `GEMINI_API_KEY` or `GOOGLE_API_KEY` |
| GitHub (for PR/issue workflows) | `GITHUB_TOKEN` |

For Docker, put these in your `~/.pi/.env` file and pass with `--env-file`. For native, export them in your shell profile.

See [Configuration and Environment Variables Reference](configuration-reference.html) for the full list of supported variables.

### MCP Launchpad (Optional)

MCP Launchpad (`mcpl`) lets pi access external tools from MCP servers (Sentry, Vercel, Jenkins, etc.). It's pre-installed in the Docker image.

**Native installation:**

```bash
uv tool install mcp-launchpad --from "mcp-launchpad @ git+https://github.com/kenneth-liao/mcp-launchpad.git"
```

**Docker mount** for your MCP config:

```bash
-v "$HOME/.config/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json":ro
```

## Running Your First Session

**1. Navigate to your project and start pi:**

```bash
cd ~/my-project
pi     # or use the Docker command/alias
```

**2. On startup, pi validates your environment.** You'll see notifications about any missing tools — critical ones (like `uv`) get a warning, optional ones (like `gh`, `mcpl`) are informational.

**3. Try a simple task:**

```
Add a docstring to every public function in src/utils.py
```

The orchestrator reads the request, identifies it as Python work, and delegates to the `python-expert` agent. You'll see the delegation happen in real time.

**4. Try a workflow command:**

```
/implement add retry logic to the HTTP client
```

This runs the full scout → planner → worker pipeline: a scout agent explores the codebase, a planner creates a step-by-step plan, and a worker implements it.

**5. Check session status anytime:**

```
/status
```

This shows async agents, cron tasks, git branch, and session info at a glance.

> **Tip:** The orchestrator never edits files directly — it always delegates to the right specialist agent. See [Understanding Agent Routing and Delegation](agent-routing.html) for how routing decisions work.

## Project-Level Configuration

Create `.pi/pi-config-settings.json` in any project to customize behavior:

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

| Setting | What it does | Default |
|---------|-------------|---------|
| `co_author` | Add co-author trailer to git commits | `false` |
| `use_worktrees` | Force git worktree workflow for branches | `false` |
| `dream_interval_hours` | How often memory consolidation runs | `3` |

Settings resolve in order: project file → environment variable → default. See [Configuration and Environment Variables Reference](configuration-reference.html) for details.

## Updating

### Docker

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

The container runs `pi update` automatically on every start, so you always get the latest pi-config and agents.

### Native

```bash
pi update                       # Updates pi-config and all pi packages
uv tool upgrade myk-pi-tools    # Updates the CLI tool
```

After updating, run `/reload` inside a running pi session or restart pi to pick up changes.

## Advanced Usage

### Building the Docker Image from Source

If you want to customize the image or run on a different architecture:

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

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

### Docker Socket Access

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

```bash
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--group-add $(stat -c '%g' /var/run/docker.sock)
```

The `docker-safe` wrapper only allows read-only operations: `ps`, `logs`, `inspect`, `top`, `stats`.

### Additional Docker Mounts

| Mount | Purpose |
|-------|---------|
| `-v "$HOME/.config/gcloud/application_default_credentials.json":"$HOME/.config/gcloud/application_default_credentials.json":ro` | Google Cloud ADC for Vertex AI |
| `-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 review data |
| `-v "$HOME/.agents":"$HOME/.agents":rw` | User-level skills for agent-browser |
| `-v "$HOME/screenshots":"$HOME/screenshots":ro` | Share screenshots/images with the agent |

### ACPX Provider (External Agent Models)

Access models from external agents (Cursor, Claude, Gemini, Copilot) as native pi models by setting `ACPX_AGENTS`:

```env
ACPX_AGENTS=cursor
```

This registers all models available through the Cursor agent as selectable pi models.

### Disabling Bundled Features

| Feature | Environment Variable | Default |
|---------|---------------------|---------|
| Pidash web dashboard | `PI_PIDASH_ENABLE=false` | enabled |
| Pidiff diff viewer | `PI_PIDIFF_ENABLE=false` | enabled |
| Pidash custom port | `PI_PIDASH_PORT=9999` | `19190` |
| Pidiff custom port | `PI_PIDIFF_PORT=9999` | `19290` |

### Native Gitignore Setup

The Docker container automatically configures the global gitignore. For native installations, the installer handles this too, but you can verify manually:

```bash
echo '.pi/memory/' >> ~/.gitignore-global
echo '.worktrees/' >> ~/.gitignore-global
echo '.pi/tasks/' >> ~/.gitignore-global
git config --global core.excludesFile ~/.gitignore-global
```

## Troubleshooting

**Pi won't start in Docker — "permission denied" errors:**
The container runs as user `node` (UID 1000). If your project files are owned by a different UID, set `PI_HOST_USER=your-username` in the env file so the container maps home directories correctly.

**"uv not found" warning on session start:**
`uv` is required for Python execution. In Docker it's pre-installed. For native, install with `curl -LsSf https://astral.sh/uv/install.sh | sh`.

**"gh not found" notification:**
GitHub CLI is optional but needed for PR/issue workflows. Install it or mount your existing config into the container.

**Container exits immediately:**
Ensure you're passing `-it` (interactive + TTY). Without it, pi has no terminal to attach to.

**Slow first start:**
The first run downloads pi-config, companion packages, and npm dependencies. Subsequent starts use cached packages and are much faster. Mount `/tmp/pi-work:/tmp/pi-work:rw` to persist temp files across container restarts.

## 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)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Understanding Agent Routing and Delegation](agent-routing.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, specialist agents, and automated code review. This guide walks you through the complete cycle so you can see every stage in action.

## Prerequisites

- A running pi session connected to a Git repository (see [Installing and Starting Your First Session](quickstart.html))
- GitHub CLI (`gh`) authenticated — pi's `github-expert` agent uses it for issues and PRs
- At least one commit on a `main` branch pushed to a remote

## Quick Example

The fastest way to implement a feature end-to-end:

```text
You: Add a --verbose flag to the export command
```

That single sentence triggers the full workflow: the orchestrator investigates the code, creates a GitHub issue, branches, delegates to the right specialist agent, runs three parallel code reviewers, fixes findings, runs tests, commits, pushes, and opens a PR — all automatically.

## Step-by-Step: The Full Feature Workflow

### Step 1 — Describe what you want

Tell pi what to build in plain language:

```text
You: Add rate limiting to the /api/users endpoint — max 100 requests per minute per IP
```

The orchestrator reads your request and begins the **issue-first workflow**. It will not start writing code immediately.

### Step 2 — Root cause investigation

Before creating anything, the orchestrator reads the relevant source code to understand what exists. It identifies the files, functions, and dependencies involved. This prevents issues based on misunderstandings and ensures the implementation plan is grounded in reality.

You'll see it delegate to a **scout** agent to explore the codebase:

```text
 scout  Exploring codebase for rate limiting context...
```

### Step 3 — Issue creation

The orchestrator delegates to the `github-expert` agent to create a tracked GitHub issue with:

- A clear title (`feat: add rate limiting to /api/users`)
- Problem description and requirements
- A **Done** checklist — the contract for when the issue can be closed

```text
 github-expert  Creating issue...
```

Once created, pi asks for confirmation:

```text
Issue #42 created: feat: add rate limiting to /api/users
URL: https://github.com/your-org/your-repo/issues/42

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

### Step 4 — Branch creation

After you confirm, the orchestrator delegates to the `git-expert` to create an issue branch:

```text
 git-expert  git fetch origin main
 git-expert  git checkout -b feat/issue-42-rate-limiting origin/main
```

Branch names follow the convention `<type>/issue-<number>-<short-description>`:

| Change type | Branch prefix |
|-------------|---------------|
| New feature | `feat/issue-42-...` |
| Bug fix | `fix/issue-42-...` |
| Refactoring | `refactor/issue-42-...` |
| Documentation | `docs/issue-42-...` |

### Step 5 — Implementation

The orchestrator routes the task to the appropriate **specialist agent** based on the files involved. You don't choose the agent — routing is automatic.

| File type | Agent selected |
|-----------|----------------|
| Python (`.py`) | `python-expert` |
| TypeScript/JavaScript | `ts-expert` |
| Go (`.go`) | `go-expert` |
| Shell scripts (`.sh`) | `bash-expert` |
| Dockerfile | `docker-expert` |
| Markdown (`.md`) | `technical-documentation-writer` |

If no specialist matches, the `worker` agent handles it. See [Understanding Agent Routing and Delegation](agent-routing.html) for the full routing table.

```text
 python-expert  Adding rate limiter middleware to api/users.py...
```

The specialist agent writes code directly — it doesn't explain what it will do first. Agents follow an "execute first, explain after" philosophy.

### Step 6 — Automated code review (3 reviewers in parallel)

After implementation, the orchestrator launches **three code review agents simultaneously** as background (async) tasks:

| Reviewer | Focus area |
|----------|------------|
| `code-reviewer-quality` | Clean code, DRY, readability, proper abstractions |
| `code-reviewer-guidelines` | Project conventions, AGENTS.md compliance, documentation updates |
| `code-reviewer-security` | Bugs, logic errors, edge cases, security vulnerabilities |

```text
 code-reviewer-quality       Reviewing changes (async)...
 code-reviewer-guidelines    Reviewing changes (async)...
 code-reviewer-security      Reviewing changes (async)...
```

All three run as async agents — they don't block your session. You can continue chatting while they work. Results surface automatically when each reviewer finishes.

Each reviewer produces findings with severity levels:

```text
[CRITICAL] api/users.py:45 — Rate limit key uses X-Forwarded-For without validation
  Risk: Attacker can bypass rate limiting by spoofing the header
  Suggestion: Validate and sanitize the forwarded IP, fall back to connection IP

[WARNING] api/users.py:62 — Missing error handling for Redis connection failure
  Suggestion: Add try/except with fallback to in-memory counter

[SUGGESTION] api/users.py:30 — Magic number 100 should be a named constant
  Suggestion: Extract to RATE_LIMIT_MAX_REQUESTS = 100
```

### Step 7 — Fix-and-review loop

If **any** reviewer has findings, the orchestrator delegates fixes to the specialist agent and sends the code through all three reviewers again. This loop continues until every reviewer approves:

```text
Code change → 3 reviewers in parallel → findings? → fix → 3 reviewers again → approved ✅
```

The orchestrator deduplicates findings across reviewers automatically. If two reviewers flag the same issue, only the most actionable version is kept.

> **Note:** The review loop is mandatory — it cannot be skipped. Code is not considered ready until all three reviewers report "approved."

### Step 8 — Test execution

Once reviewers approve, the orchestrator delegates to the `test-automator` agent:

```text
 test-automator  Running test suite...
```

The test agent compares results against a **baseline** (tests on the branch before your changes). Only **new failures** introduced by your code block the workflow. Pre-existing failures are noted but don't block.

If tests fail:
- Minor test/config fixes → re-run tests only (skip re-review)
- Substantive code changes → full re-review from step 6

### Step 9 — Commit and push

With reviews approved and tests passing, the orchestrator delegates to `git-expert`:

```text
 git-expert  git add api/users.py api/middleware.py tests/test_rate_limit.py
 git-expert  git commit -F - (feat: add rate limiting to /api/users endpoint)
 git-expert  git push -u origin feat/issue-42-rate-limiting
```

Commits follow these conventions:
- Specific files are staged individually (never `git add .`)
- Commit messages use conventional format (`feat:`, `fix:`, `refactor:`)
- No AI attribution in commit messages

### Step 10 — Pull request creation

The orchestrator delegates to `github-expert` to create the PR:

```text
 github-expert  gh pr create --title "feat: add rate limiting to /api/users" --body "..."
```

The PR links back to issue #42. When the PR merges, the issue's Done checklist items are checked off and the issue is closed.

## Using Slash Commands

For common workflows, slash commands provide structured shortcuts instead of free-form prompts.

### `/implement` — Scout, plan, and build

```text
/implement add rate limiting to the /api/users endpoint
```

This runs a three-agent chain automatically:
1. **scout** — finds relevant files and dependencies
2. **planner** — creates a detailed implementation plan
3. **worker** — implements the plan

### `/implement-and-review` — Build with automatic review

```text
/implement-and-review add rate limiting to the /api/users endpoint
```

Same as `/implement`, but adds the three parallel reviewers plus a fix pass — the entire code review loop in one command.

### `/review-local` — Review before committing

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

Reviews your uncommitted changes (or changes vs. a branch) using all three reviewers in parallel. Use this to catch issues before pushing.

### `/scout-and-plan` — Explore without changing anything

```text
/scout-and-plan add rate limiting to the /api/users endpoint
```

Runs only the scout and planner agents — no code is written. Use this when you want to understand the codebase and see a plan before committing to implementation.

See [Using Slash Commands and Prompt Templates](slash-commands.html) for the full command reference.

## Monitoring Progress

### Task tracking

For multi-step workflows, the orchestrator creates a task list that persists across turns. You can see exactly where you are:

```text
✅ Investigate root cause in api/users.py
✅ Create GitHub issue with root cause analysis
✅ Create branch feat/issue-42-rate-limiting from origin/main
✅ Implement rate limiting middleware
⏳ Run code review loop (3 async reviewers)
⬚ Fix review findings (if any)
⬚ Run test-automator
⬚ Commit and push changes
⬚ Create PR with description
```

If you ask a side question mid-workflow ("What's the Redis connection timeout?"), the orchestrator answers and then **immediately resumes** from the next unchecked task.

### `/status` — Session snapshot

```text
/status
```

Shows async agents currently running, cron tasks, git branch, and session context in one view.

### `/async-status` — Background agent details

```text
/async-status
```

Shows all background agents with elapsed time and task descriptions.

## Advanced Usage

### Skipping the issue-first workflow

For quick fixes where tracking overhead isn't needed, tell pi to skip the workflow:

```text
You: Just fix the typo in README.md — "recieve" should be "receive"
```

The orchestrator recognizes signals like "just do it", "quick fix", or single-line trivial changes and skips issue creation, going directly to implementation.

### Working on an existing issue

```text
You: Work on issue #42
```

The orchestrator picks up the existing issue, creates a branch (if one doesn't exist), and starts working through the Done checklist.

### Reviewing a GitHub PR

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

Reviews an existing PR and optionally posts inline comments. See [Running the Automated Code Review Loop](code-review-loop.html) for details.

### Handling review comments from external reviewers

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

Processes comments from human reviewers, CodeRabbit, and Qodo on the current PR. The `--autorabbit` and `--autoqodo` flags enter a fully automated polling loop that fixes comments, pushes, and re-polls until the reviewer approves.

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

### Creating a release after merging

```text
/release
/release 2.1.0
```

Generates a changelog from conventional commits, optionally bumps version files, and creates a GitHub release. See [Common Workflow Recipes](workflow-recipes.html) for release patterns.

### Multi-PR parallel work

When handling multiple PRs simultaneously, pi uses git worktrees to avoid branch-switching conflicts:

```text
You: Handle reviews for PR #42 and PR #43
```

Each PR gets its own isolated worktree directory under `.worktrees/`. Agents working on PR #42 never interfere with agents working on PR #43.

### Teaching pi your preferences

Pi remembers your preferences across sessions. State them naturally and they're auto-extracted:

```text
You: I always want tests before implementation
You: Never use print statements for debugging — always use the logging module
You: I prefer functional style over classes when possible
```

These become part of pi's memory and influence future workflows. See [Working with Project Memory](memory-system.html) for details.

## Troubleshooting

**The orchestrator is writing code directly instead of delegating.**
The orchestrator should never use `edit`, `write`, or `bash` (except for `mcpl`). If this happens, it's a routing issue. Mention the expected agent: "Delegate this to the python-expert."

**Reviews are taking too long.**
All three reviewers run as async background agents. Check their status with `/async-status`. If a reviewer is stuck, you can kill it and re-trigger the review.

**Tests fail but they were already failing before my changes.**
The test runner compares against a baseline. Only **new** failures block the workflow. If you're seeing pre-existing failures blocking, mention it and the orchestrator will re-run the baseline comparison.

**The wrong specialist agent was chosen.**
Routing is based on task intent, not just file type. If the orchestrator routes incorrectly, tell it directly: "Use the python-expert for this." See [Understanding Agent Routing and Delegation](agent-routing.html) for routing details.

**Side question made pi forget what it was doing.**
Task tracking prevents this — the task list is injected every turn. If tasks exist, the orchestrator resumes automatically after answering. If it doesn't, say "continue with the tasks" to nudge it back.

## 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

# Understanding Agent Routing and Delegation

Route your tasks to the right specialist agent automatically, or take control of routing when the defaults don't fit. This page explains how the orchestrator decides which agent handles your work and how to customize that behavior.

## Prerequisites

- Pi is installed and running — see [Installing and Starting Your First Session](quickstart.html)
- You've seen the orchestrator delegate at least once — see [Your First Coding Workflow](first-workflow.html)

## Quick Example

Ask pi to fix a bug in a Python file:

```
Fix the off-by-one error in the pagination logic in utils.py
```

The orchestrator automatically:
1. Identifies this as Python work (`.py` file)
2. Delegates to `python-expert`
3. Returns the result to you

You never need to name the agent — routing happens based on what you ask for.

## How Routing Works

The orchestrator does not write code, run git commands, or modify files directly. Instead, it reads your request, matches it against a routing table, and delegates to the appropriate specialist agent via the `subagent` tool.

### The Routing Table

| Domain | Agent | When to use |
|--------|-------|-------------|
| **Python** (`.py`) | `python-expert` | Writing, modifying, or debugging Python code |
| **Go** (`.go`) | `go-expert` | Go code, modules, goroutines |
| **TypeScript/JavaScript** (`.ts`, `.js`, React, Vue) | `ts-expert` | Frontend and Node.js development |
| **Java** (`.java`) | `java-expert` | Spring Boot, Maven, Gradle, enterprise Java |
| **Shell scripts** (`.sh`) | `bash-expert` | Bash/shell script creation and modification |
| **Markdown** (`.md`) | `technical-documentation-writer` | Writing technical documentation |
| **Docker** | `docker-expert` | Dockerfiles, container workflows, image optimization |
| **Kubernetes/OpenShift** | `kubernetes-expert` | K8s manifests, Helm charts, cluster management |
| **Jenkins/CI** | `jenkins-expert` | Jenkinsfiles, Groovy, CI/CD pipelines |
| **Git** (local) | `git-expert` | Commits, branches, merges, rebases, stash |
| **GitHub** (platform) | `github-expert` | PRs, issues, releases, GitHub workflows |
| **Tests** | `test-automator` | Creating test suites, test infrastructure |
| **Debugging** | `debugger` | Root cause analysis of errors and failures |
| **API docs** | `api-documenter` | OpenAPI specs, SDK docs, API references |
| **External docs** | `docs-fetcher` | Fetching React, FastAPI, Django docs, etc. |
| **Security audit** | `security-auditor` | Auditing external repos before adoption |
| **Everything else** | `worker` | General-purpose fallback agent |

### Intent-Based Routing, Not Tool-Based

The orchestrator routes based on **what you're trying to accomplish**, not which tool happens to be involved:

| Task | Routed to | Why |
|------|-----------|-----|
| Run Python tests | `python-expert` | Testing *Python code*, not running a shell command |
| Edit a Python file with sed | `python-expert` | Modifying *Python code*, regardless of the tool |
| Create a PR | `github-expert` | GitHub platform operation, not local git |
| Commit changes | `git-expert` | Local git operation |
| Write a shell script | `bash-expert` | Creating a *shell script* |
| Look up React hooks docs | `docs-fetcher` | External library documentation |

> **Tip:** If you're unsure which agent will handle your request, just describe what you want. The orchestrator almost always picks the right one.

## Execution Modes

The orchestrator delegates work in three modes depending on the task structure.

### Single Agent

One agent, one task. The most common mode:

```
Add type hints to the User class in models.py
```

The orchestrator sends this to `python-expert` and waits for the result.

### Parallel Agents

Independent tasks that can run simultaneously:

```
Refactor the auth module in auth.py and update the API docs in docs/api.md
```

The orchestrator dispatches `python-expert` and `technical-documentation-writer` at the same time, up to 4 concurrent agents and 8 total tasks.

### Chain Mode

Sequential tasks where each step depends on the previous one:

```
Scout the codebase for all database queries, then create an optimization plan
```

The orchestrator runs `scout` first, then feeds its output to `planner` via a `{previous}` placeholder.

## Sync vs Async Agents

By default, the orchestrator runs agents synchronously — it waits for the result before responding. But for long-running or independent tasks, it uses async mode.

### When Async Is Used

- **Code reviews** — always async (the three review agents are enforced as async-only)
- **Independent research or analysis** — no need to block the session
- **Any task estimated at 30+ seconds** — the orchestrator must use async mode

### Async-Only Agents

Three agents are **always** dispatched asynchronously, even if the orchestrator tries to run them synchronously:

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

This prevents the session from blocking while waiting for code reviews. Results appear automatically when the reviews complete.

> **Note:** For details on monitoring async agents and managing background tasks, see [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html).

## Special-Purpose Agents

Some agents serve specific roles beyond language routing.

| Agent | Purpose | Key difference |
|-------|---------|---------------|
| `scout` | Fast codebase reconnaissance | Uses a lighter model (`claude-haiku-4-5`) for speed. Read-only — finds files and maps dependencies. |
| `planner` | Creates implementation plans | Read-only — never writes code. Produces structured plans for other agents. |
| `debugger` | Root cause analysis | Diagnoses issues but does not fix them. Returns analysis for the orchestrator to act on. |
| `test-runner` | Execute tests and report | Runs tests and analyzes failures without making fixes. |
| `reviewer` | General code review | Lightweight single-reviewer alternative to the 3-reviewer loop. |
| `docs-fetcher` | External documentation | Tries `llms.txt` first (AI-optimized), falls back to web parsing. The orchestrator never fetches docs directly. |

## The Code Review Loop

After any code change, the orchestrator triggers a mandatory 3-reviewer parallel code review. This is a core part of the routing system — you don't need to request it.

1. Specialist writes or fixes code
2. All 3 review agents run **in parallel** (always async)
3. Findings are merged and deduplicated
4. If any reviewer has comments → fix and re-review
5. Once approved → run `test-automator`
6. Tests pass → done

> **Note:** For the full review workflow, see [Running the Automated Code Review Loop](code-review-loop.html).

## Advanced Usage

### Agent Discovery and Override Layers

Agents are loaded from three directories in priority order (later overrides earlier by name):

1. **Package agents** — the 24 built-in agents shipped with pi-config (always loaded)
2. **User agents** — your personal agents at `~/.pi/agent/agents/`
3. **Project agents** — project-specific agents at `.pi/agents/` in your repo

To override a built-in agent, create a file with the same `name:` in your user or project agents directory. For example, to customize `python-expert` for your project:

```markdown
---
name: python-expert
description: Python expert with our team's conventions.
tools: read, write, edit, bash
---

You are a Python expert for the Acme project.
Always use our internal `acme.utils` library.
Follow PEP 8 and use type hints on all functions.
```

Save this as `.pi/agents/python-expert.md` in your repository root.

> **Warning:** When project-level agents are used, pi prompts for confirmation before running them. This is a security measure — project agents execute with the same tools as built-in agents.

### Controlling Agent Scope

The `subagent` tool accepts an `agentScope` parameter that controls which agent directories are searched:

| Scope | Loads from |
|-------|------------|
| `"user"` (default) | Package + user agents |
| `"project"` | Package + project agents |
| `"both"` | Package + user + project agents |

The orchestrator uses `"user"` scope by default. Switch to `"project"` or `"both"` when you have project-specific agents defined.

### Creating Custom Agents

Create a `.md` file in `~/.pi/agent/agents/` (for personal agents) or `.pi/agents/` in your repo (for project agents). Every agent file needs YAML frontmatter:

```markdown
---
name: my-custom-agent
description: One-sentence description of what this agent does.
tools: read, write, edit, bash
---

Agent instructions go here. Be specific about what the agent should
and should not do.
```

The required frontmatter fields:

| Field | Required | Description |
|-------|----------|-------------|
| `name` | Yes | Agent identifier — used in routing and delegation |
| `description` | Yes | One-sentence summary — helps the orchestrator choose the right agent |
| `tools` | No | Comma-separated list of tools the agent can use (`read`, `write`, `edit`, `bash`) |
| `model` | No | Override the default model (e.g., `claude-haiku-4-5` for faster, cheaper agents) |

The body after the frontmatter becomes the agent's system prompt.

> **Tip:** For a full walkthrough of creating and registering a custom agent, see [Customization and Extension Recipes](customization-recipes.html).

### Model Overrides

Any agent can specify a `model:` in its frontmatter to use a different model than the session default. The built-in `scout` agent uses this to run on `claude-haiku-4-5` for faster, cheaper codebase reconnaissance.

If no `model:` is specified, the agent inherits the parent session's model.

### Time Estimation and Enforcement

Sync agents require a time estimate (`estimatedSeconds`). If the estimated duration is **30 seconds or more**, the orchestrator must use async mode instead. This prevents long-running agents from blocking your session.

- **Single sync agent**: estimate must be under 30s
- **Parallel sync agents**: the longest task must be under 30s
- **Chain sync agents**: the sum of all steps must be under 30s
- **Async agents**: no estimate required

### Forcing a Specific Agent

If the orchestrator routes to the wrong agent, you can explicitly request one:

```
Use the bash-expert to write a systemd service file
```

```
Have the go-expert review this migration script
```

The orchestrator respects explicit agent requests in your message.

## Troubleshooting

**The orchestrator picked the wrong agent**
- Be more specific about the task intent. "Fix the Python test" is better than "fix the test."
- Explicitly name the agent: "Use `python-expert` to fix the test in `test_auth.py`."

**"Unknown agent" error**
- Check the agent name matches exactly (including hyphens). Run a session and ask pi to list available agents.
- If using project agents, make sure the file is in `.pi/agents/` and has valid frontmatter with `name:` and `description:`.

**Agent seems to lack the right tools**
- Check the `tools:` field in the agent's frontmatter. An agent without `write` and `edit` can't modify files. An agent without `bash` can't run shell commands.

**Code review never finishes**
- The three review agents are async-only. Their results appear automatically. Use `/async-status` to check progress. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for details.

**Project agents aren't being picked up**
- Ensure the agents directory is at `.pi/agents/` relative to your project root (not `agents/`).
- The `agentScope` must be set to `"project"` or `"both"` — the default `"user"` scope does not load project agents.

## 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)
- [Customization and Extension Recipes](customization-recipes.html)
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html)

---

Source: code-review-loop.md

# Running the Automated Code Review Loop

Run your code changes through pi's 3-reviewer parallel code review system to catch quality issues, guideline violations, and security bugs before they land — and iterate until every reviewer approves.

## Prerequisites

- A working pi session with the orchestrator (see [Installing and Starting Your First Session](quickstart.html))
- Code changes ready for review (staged, unstaged, or on a branch)
- Familiarity with how the orchestrator delegates to agents (see [Understanding Agent Routing and Delegation](agent-routing.html))

## Quick Example

Ask pi to review your uncommitted changes:

```
/review-local
```

Or review changes compared to a specific branch:

```
/review-local main
```

Pi spawns three review agents in parallel, merges the findings, and presents them grouped by severity. That's the review loop in action.

## The Three Reviewers

Every code review dispatches three specialist agents simultaneously. Each focuses on a different dimension:

| Reviewer | Focus Area | What It Checks |
|----------|-----------|----------------|
| `code-reviewer-quality` | Code quality & maintainability | Readability, DRY violations, complexity, error handling, dead code, observability anti-patterns |
| `code-reviewer-guidelines` | Project guidelines & style | AGENTS.md compliance, documentation updates, naming conventions, file structure consistency |
| `code-reviewer-security` | Bugs, logic errors & security | Logic errors, null references, race conditions, injection flaws, resource leaks, edge cases |

The overlapping scope is intentional — multiple reviewers examining similar areas reduces the chance of missed issues. Duplicate findings are merged automatically.

> **Note:** All three reviewers are read-only agents. They use `read` and `bash` tools to inspect your code but never modify files.

## How the Loop Works

The review loop follows a strict cycle that repeats until all three reviewers approve:

1. **Code is written or modified** by a specialist agent (or you)
2. **All 3 reviewers run in parallel** as async background agents
3. **Findings are merged and deduplicated** across all reviewers
4. **If any reviewer has comments** → fix the code, go back to step 2
5. **All reviewers approve** → run tests via `test-automator`
6. **Tests pass** → done. Tests fail → fix and determine whether to re-review or just re-test

> **Tip:** Minor fixes that only touch test files or configuration can skip the full re-review and go directly back to testing. Substantive code changes require a full re-review from step 2.

## Reviewing Local Changes

### Uncommitted Changes

Review everything that's changed since your last commit:

```
/review-local
```

This runs `git diff HEAD` to collect your changes and sends them to all three reviewers.

### Changes Against a Branch

Compare your current branch against another branch:

```
/review-local main
```

```
/review-local develop
```

This runs `git diff <branch>...HEAD` to compute the diff.

### What You Get Back

Findings are presented grouped by severity:

```text
## Critical issues (must fix)
[CRITICAL] src/auth.py:42 — SQL injection via unsanitized user input
  Risk: Attacker can execute arbitrary SQL queries
  Suggestion: Use parameterized queries

## Warnings (should fix)
[WARNING] src/utils.py:15 — Empty catch block swallows errors silently
  Suggestion: Log the exception at minimum

## Suggestions (nice to have)
[SUGGESTION] src/config.py:8 — Unused import 'os'
  Suggestion: Remove unused import
```

## Implement-and-Review in One Command

To implement a change and automatically run the review loop:

```
/implement-and-review Add rate limiting to the /api/login endpoint
```

This chains three steps together:

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

## Reviewing a GitHub PR

To review a pull request and post inline comments on GitHub:

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

This fetches the PR diff, sends it to all three reviewers in parallel, lets you select which findings to post, and submits them as GitHub review comments. See [Using Slash Commands and Prompt Templates](slash-commands.html) for the full list of review-related commands.

## How Reviewers Run in the Background

All three code reviewers are enforced as **async-only agents**. When the orchestrator dispatches them, they automatically run as background agents — the session stays interactive while reviews happen.

When reviews finish, results surface automatically in your conversation with a notification:

```text
## Async Agent Result: code-reviewer-quality ✅ completed

Task: Review the changes for code quality
Duration: 45s

No quality issues found. Code approved.
```

You can check the status of running reviewers at any time:

```
/async-status
```

This shows all background agents with their elapsed time and task description. Select one to view its live output as it runs.

> **Tip:** If you need to cancel a running review, use `/async-kill` and select the agent to stop, or `/async-kill all` to stop everything.

## How Findings Are Deduplicated

When findings come back from all three reviewers, they're merged using these rules:

| Scenario | Action |
|----------|--------|
| Same file/line range + same issue type or root cause | Keep the most actionable version |
| Conflicting suggestions | Priority order: security > correctness > performance > style |
| Complementary findings on the same code (different issue types) | Keep both |
| Still ambiguous after priority ordering | Escalate to the user |

## Handling Review Feedback from External Reviewers

When your PR receives reviews from external tools (CodeRabbit, Qodo) or human reviewers on GitHub, use the review handler:

```
/review-handler
```

This fetches all review comments from the current PR — human, CodeRabbit, and Qodo — and walks you through addressing each one.

### Automated Review Loops

For fully automated handling of external reviewer comments:

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

In auto mode, the handler enters a polling loop: it fixes comments, pushes changes, waits for the reviewer to re-evaluate, and repeats until the reviewer approves. The session stays interactive while the loop runs.

See [Common Workflow Recipes](workflow-recipes.html) for copy-paste patterns covering autorabbit and autoqodo workflows.

## Advanced Usage

### Baseline Test Comparison

When the review loop reaches the testing phase, it compares test results against the baseline (the state before your changes). Only **new** test failures block the review — pre-existing failures are noted but don't block.

The baseline comparison works by:

1. Saving your changes as a patch
2. Resetting to a clean state and running tests
3. Restoring your changes and running tests again
4. Comparing the two results — only new failures count

> **Note:** If the baseline comparison fails (patch can't be applied), it's skipped with a note. Tests still run, but all failures are reported without filtering.

### Staged Review Mode

For automated workflows (`--autorabbit`, `--autoqodo`), reviews use a **two-stage order** instead of running all three reviewers in parallel:

| Stage | Focus | Purpose |
|-------|-------|---------|
| **Stage 1** | Spec compliance | Does the code meet requirements? All deliverables implemented? No scope creep? |
| **Stage 2** | Code quality | Quality, security, guidelines (runs only after Stage 1 passes) |

The staged approach avoids polishing code that doesn't meet spec — saving review cycles.

### Each Reviewer's Output Format

All three reviewers use a consistent severity-tagged format:

```text
[SEVERITY] file:line — Description
  Suggestion: What to change and why
```

- `[CRITICAL]` — Must fix before merging
- `[WARNING]` — Should fix, potential issue
- `[SUGGESTION]` — Nice to have, minor improvement

When a reviewer finds no issues, it explicitly states approval:

```text
No quality issues found. Code approved.
```

The loop only completes when all three reviewers return an approval message.

### Guidelines Reviewer and Documentation Checks

The `code-reviewer-guidelines` agent reads your project's `AGENTS.md` file first, then reviews changes against those rules. It also checks whether documentation needs updating:

- If code was added, changed, or removed, it verifies that `AGENTS.md` and `README.md` are updated accordingly
- Missing documentation updates are flagged as `[CRITICAL]`

### Multi-PR Reviews with Worktrees

When reviewing multiple PRs simultaneously, never switch branches in the main worktree. Use git worktrees:

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

Each worktree gets its own directory, so agents working on different PRs don't interfere with each other. Clean up when done:

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

### Extending the Review System

#### Adding a Custom Reviewer

To add a project-specific reviewer (e.g., for domain-specific rules), create an agent file in your project's `.pi/agents/` directory. See [Customization and Extension Recipes](customization-recipes.html) for the step-by-step process.

#### Async-Only Enforcement

All three code reviewers are in the async-only enforcement list. If the orchestrator accidentally tries to dispatch them synchronously, the system automatically promotes the call to async. This prevents the session from blocking while reviews run.

> **Warning:** If you create a custom reviewer agent and want it enforced as async-only, it must be added to the enforcement list in the extension configuration. Without this, sync calls will block your session for the duration of the review.

## Troubleshooting

**Reviews seem to take a long time**
Reviewer agents run as full pi sessions with their own context. Complex diffs take longer. Use `/async-status` to monitor progress and view live output.

**A reviewer keeps finding the same issue after I fix it**
Make sure your fix is saved to disk. Reviewers read files directly — unsaved editor buffers won't be seen. Also ensure you're not accidentally reverting changes between review cycles.

**"No async agents running" but I just started a review**
Agents take a moment to spawn. Wait a few seconds and check `/async-status` again. If the agent failed to start, the orchestrator will report an error in the conversation.

**Tests fail but the failures existed before my changes**
The baseline comparison should filter pre-existing failures. If it reports "baseline comparison unavailable," the patch couldn't be cleanly applied to the base. In that case, manually verify whether failures are new.

**Review comments conflict with each other**
When reviewers disagree, the priority order is: security > correctness > performance > style. If the conflict is still ambiguous, you'll be asked to decide.

## 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)
- [Common Workflow Recipes](workflow-recipes.html)
- [Your First Coding Workflow](first-workflow.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. Fetches the PR diff and project rules (AGENTS.md)
2. Runs three reviewers in parallel (quality, guidelines, security)
3. Presents findings grouped by severity (CRITICAL → WARNING → SUGGESTION)
4. Lets you choose which findings to post as inline comments

> **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.

### /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`) |
| `/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)
- [Running the Automated Code Review Loop](code-review-loop.html)
- [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html)

---

Source: memory-system.md

# Working with Project Memory

Teach pi what matters in your project — your preferences, lessons learned, and conventions — so it remembers across sessions and gets smarter over time.

- You need a pi session running in a git repository (pi stores memory under `.pi/memory/`)
- Memory works automatically once you start talking — but knowing the tools gives you full control

## Quick Example

Tell pi to remember something, and it persists across sessions:

```
/remember Always run tests with --no-cache flag
```

Or say it naturally in conversation — pi detects preference statements automatically:

```
I prefer using pnpm over npm for this project
```

Both approaches create memory entries that pi recalls in future sessions.

## How Memory Categories Work

Every memory entry belongs to one of six categories:

| Category | What it stores | How long it lasts |
|----------|---------------|-------------------|
| `preference` | How you like things done | 90 days (slow decay) |
| `lesson` | Gotchas, tips, how things work | 60 days |
| `pattern` | Recurring approaches, conventions | 30 days |
| `decision` | Architectural or design choices | 30 days |
| `done` | Completed tasks, merged PRs | 14 days (fast decay) |
| `mistake` | Things that went wrong | 14 days |

> **Note:** Decay doesn't mean deletion — it means lower priority. Memories you reinforce stay strong. Pinned memories never decay.

## Searching and Recalling Memories

Pi automatically recalls relevant memories before every response. You can also ask it directly:

```
What do you remember about our Docker setup?
```

Pi will use `memory_search` behind the scenes to find matching entries. Results combine keyword matching and semantic (vector) similarity search — so even paraphrased queries find the right memories.

You can search by category too:

```
Search my memories for lessons about CI/CD
```

## Adding Memories

### Explicit — You Tell Pi to Remember

Use the `/remember` command for important things you never want pi to forget:

```
/remember Use port 8443 for the dev server, not 8080
```

This creates a **pinned** entry that never decays and is protected from automatic cleanup.

### Proactive — Pi Remembers on Its Own

Pi adds memories automatically when it notices something worth saving:

| What happens | Category pi uses |
|-------------|-----------------|
| You correct pi | `lesson` |
| A fix attempt fails | `mistake` |
| You say "don't do X" or "always do Y" | `preference` |
| A PR gets merged | `done` |
| Pi notices a recurring pattern | `pattern` |
| An architectural decision is made | `decision` |

### Auto-extraction — Pi Detects Your Preferences

When you say things like "I prefer...", "always use...", "never...", or "from now on...", pi automatically extracts and saves them as preferences. No explicit command needed.

### CLI — Manage Memory from the Terminal

```bash
# Add a memory
uv run myk-pi-tools memory add -c lesson -s "buildah chown -R breaks cache mounts"

# Add a pinned memory
uv run myk-pi-tools memory add -c preference -s "Always use uv run" --pinned

# Remove a memory
uv run myk-pi-tools memory forget -c lesson -s "buildah chown -R breaks cache mounts"

# Show all memories
uv run myk-pi-tools memory show

# Print the memory directory path
uv run myk-pi-tools memory path
```

## Where Memories Are Stored

Memories live in your project under `.pi/memory/topics/` as simple Markdown files:

```
.pi/memory/
├── memory-scores.json          # Scoring data (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 is human-readable Markdown:

```markdown
# Preferences

- [preference] Always use pnpm over npm *(pinned)*
- [preference] Prefers concise responses
```

> **Tip:** You can edit these files directly — pi reads them as the source of truth on every session start.

## Memory Scoring and Decay

Every memory has a stability score that determines whether it appears in pi's context. The score decays over time unless reinforced.

**What keeps memories alive:**

- **Reinforcement** — when pi notices a memory is relevant to the current task, it bumps the evidence count, resetting the decay clock
- **Pinning** — pinned entries have a fixed score of 9999 and never decay
- **Repetition** — if you state a preference that already exists, pi reinforces it automatically

**Lifecycle states:**

| State | What it means |
|-------|--------------|
| `active` | Included in pi's context every turn |
| `provisional` | Overflow — included only when budget allows |
| `candidate` | Low priority — at risk of being dropped |
| `dropped` | No longer injected into context |

Per-category budgets keep memory focused: 8 entries max for preferences and lessons, 6 for patterns, 4 each for decisions, completions, and mistakes. A total cap of 40 active entries prevents context overload.

## Dreaming — Background Memory Consolidation

Dreaming is pi's way of processing memories in the background — deduplicating entries, removing stale information, and extracting new knowledge from past sessions.

### When Dreaming Runs

- **Automatically** every 3 hours (configurable)
- **On session shutdown** when you quit pi
- **On demand** with the `/dream` command

### Manual Trigger

```
/dream
```

This runs memory consolidation as a background agent — it never blocks your session.

### Toggle Auto-Dreaming

```
/dream-auto off    # Disable automatic dreaming
/dream-auto on     # Re-enable it
/dream-auto        # Check current status
```

### What Dreaming Does

1. Reads session transcripts and extracts durable knowledge
2. Adds new entries to the appropriate topic files
3. Deduplicates and removes stale entries
4. Generates reusable skills from recurring multi-step workflows
5. **Never** touches pinned entries

### Configuring the Dream Interval

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:** Project settings take priority over environment variables. See [Configuration and Environment Variables Reference](configuration-reference.html) for all settings.

## Capacity Management

The situation report header shows your current memory usage:

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

The total budget is 1,700 tokens by default, dynamically adjusted based on how much of the system prompt is used by rules and other context.

### When Memory Gets Full

When usage exceeds 80%, pi shows a warning:

```
> ⚠️ Memory above 80% capacity. Before adding new entries, consolidate or
> remove existing ones using memory_remove.
```

**To free up space:**

1. Ask pi to consolidate memories:
   ```
   Consolidate my project memory — find duplicates and remove stale entries
   ```

2. Remove specific outdated entries:
   ```
   Remove the memory about Python 3.11, we upgraded to 3.12
   ```

3. Run dreaming to auto-clean:
   ```
   /dream
   ```

### Topic File Size Limits

Each topic file is capped at ~3,000 tokens (12,000 characters). If you hit this limit on a specific category, pi will prompt you to consolidate or remove entries before adding new ones.

## Advanced Usage

### Memory Editing

Pi can update memories in place without losing scoring history:

```
Update my memory about the dev server port — it changed from 8443 to 9090
```

This preserves the evidence count and reinforcement history of the original entry, unlike a remove-then-add which starts fresh.

Pi can also invalidate superseded memories:

```
The memory about using webpack is outdated — we switched to vite
```

### Memory Reflection

Ask pi to synthesize an answer from its memories rather than returning raw entries:

```
What do you remember about how our deployment pipeline works?
```

Pi searches across all topic files using both keyword and vector similarity, then composes a coherent answer from the matching entries.

### Session History Search

Beyond topic-based memory, pi indexes summaries of past conversations. When you reference something from a previous session, pi automatically searches these summaries and injects relevant snippets — at zero LLM cost.

You can also search explicitly:

```
What did we discuss about the database migration last week?
```

Session summaries are stored in `.pi/data/session-search.json` and indexed on session shutdown.

### Contextual Memory Auto-Injection

Three mechanisms inject memory into pi's context automatically on every turn:

1. **Situation Report** — a token-budgeted summary of scored memories, always present at the top of pi's context
2. **Contextual Memory Recall** — vector similarity search against your current message, injecting entries with similarity > 0.65
3. **File-Change Reminders** — after pi modifies files, it searches for memories related to those file paths and surfaces relevant ones

> **Tip:** Trivial messages like "ok", "thanks", or emoji skip vector search to avoid wasted computation.

### Vector Embeddings

Memory search uses a local embedding model (`Xenova/bge-small-en-v1.5`, 384 dimensions) that runs entirely in-process — no API keys needed, no network calls. The model downloads automatically on first use (~50MB).

Embeddings are stored in `.pi/memory/embeddings.json` and created automatically when memories are added. On first search after upgrading, pi migrates existing entries that don't have embeddings yet.

### Retrieval Telemetry

Pi logs which memories were injected and whether they were actually used in the response. This data lives in `.pi/data/memory-telemetry.jsonl` and helps track memory effectiveness over time.

### Cold Topic Archival

Topics that haven't been reinforced for 2× their half-life are archived automatically (deleted). For example, a completions topic with no reinforcement for 28 days is removed. Pinned entries are never archived.

### Writing Good Memory Entries

| ❌ Avoid | ✅ Prefer |
|----------|----------|
| "We had issues with Docker caching" | "buildah chown -R breaks cache mounts — use --mount=type=cache with correct uid" |
| "The integration 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 only** — max ~100 characters
- **Specific and actionable** — concrete "do X" or "don't do Y"
- **No fluff** — no context, background, or explanation

## Troubleshooting

**Memories aren't showing up in pi's context**

- Check capacity: if memory is at 100%, lower-priority entries are dropped. Remove or consolidate entries.
- Verify the entry exists: `uv run myk-pi-tools memory show`
- The entry may have decayed to `dropped` state — reinforce it by asking pi about the topic.

**Vector search isn't finding relevant memories**

- On first run, the embedding model downloads (~50MB). If it fails, pi falls back to keyword-only search.
- Check that `.pi/memory/embeddings.json` exists. If corrupted, delete it — pi rebuilds it on next search.

**Dreaming isn't running**

- Check status: `/dream-auto` (shows enabled/disabled)
- Dreaming is disabled in one-shot modes (`print`, `json`) — it only runs in interactive sessions.
- The dream interval may be too long. Check `.pi/pi-config-settings.json` or set `PI_DREAM_INTERVAL_HOURS`.

**Memory entries seem duplicated**

- Run `/dream` to trigger consolidation, which deduplicates entries.
- Or ask pi directly: "Consolidate my project memory — find and merge duplicates."

## Related Pages

- [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [myk-pi-tools CLI Reference](cli-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 and delivers results independently.

### 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)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)
- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)

---

Source: inter-agent-communication.md

# Communicating Between Pi Sessions

Enable multiple pi sessions to send messages to each other and collaborate on tasks — useful for patterns like a manager agent reviewing a coder agent's work, or distributing work across specialized agents.

## Prerequisites

- Two or more pi sessions running in the same project directory (or accessible via network)
- For `/coms-net`: [Bun](https://bun.sh) must be installed (used to run the hub server)

## Quick Example

Open two terminals in the same project directory.

**Terminal 1** — start a pi session and activate P2P communication:

```
/coms start --name reviewer --purpose "code reviewer"
```

**Terminal 2** — start another pi session and activate P2P communication:

```
/coms start --name coder --purpose "implements features"
```

The agent now has tools to list peers and send messages. Ask pi to "send a message to reviewer asking for feedback on the login module" and it will use the `coms_send` and `coms_await` tools automatically.

## Choosing Between P2P and Networked

| | P2P (`/coms`) | Networked (`/coms-net`) |
|---|---|---|
| **Transport** | Direct Unix socket connections | HTTP/SSE hub server |
| **Scope** | Same machine only | Same machine or across a LAN |
| **Setup** | No extra processes needed | Requires a hub server (auto-started) |
| **Server management** | None | Server auto-managed by `/coms-net start` |
| **Tool prefix** | `coms_*` | `coms_net_*` |
| **Best for** | Quick local multi-agent work | Teams, remote collaboration, persistent hubs |

Both systems can run simultaneously without conflicts.

## Setting Up P2P Communication (`/coms`)

### Step 1: Start coms in each session

Run this in each pi session that should participate:

```
/coms start --name <agent-name>
```

Available flags:

| Flag | Description |
|---|---|
| `--name <name>` | Agent name (auto-generated if omitted) |
| `--purpose <text>` | Short description of this agent's role |
| `--project <name>` | Project namespace for peer discovery (defaults to current directory) |
| `--color #RRGGBB` | Hex color for the pool widget |
| `--explicit` | Hide from auto-discovery (only reachable by exact name) |

### Step 2: Verify peers are visible

A pool widget appears below the editor showing connected peers with their names, models, and context usage.

You can also check status at any time:

```
/coms status
```

### Step 3: Send messages between agents

Ask pi to communicate with a peer naturally — for example: "ask the coder to implement a retry mechanism." Pi will use the communication tools (`coms_list`, `coms_send`, `coms_await`) automatically.

### Stop P2P communication

```
/coms stop
```

## Setting Up Networked Communication (`/coms-net`)

### Step 1: Start the hub and connect

```
/coms-net start --name <agent-name>
```

This automatically:

1. Starts a hub server (via Bun) if one isn't already running
2. Registers your session with the hub
3. Opens a real-time SSE connection for instant message delivery

Available flags (in addition to those listed for `/coms`):

| Flag | Description |
|---|---|
| `--port <number>` | Server port (OS picks a free port by default) |
| `--host <address>` | Server bind address (default: `127.0.0.1`) |

### Step 2: Connect additional sessions

In other terminals, run:

```
/coms-net start --name <another-name>
```

Additional sessions auto-discover the running server — no URL or token configuration needed for local use.

### Connecting to an existing server

If a hub is already running (started by another session or manually), connect without starting a new one:

```
/coms-net connect --name <agent-name>
```

To connect to a remote server:

```
/coms-net connect --name <agent-name> --url http://host:port --auth-token <token>
```

### Disconnecting vs stopping

| Command | Effect |
|---|---|
| `/coms-net disconnect` | Disconnect from the hub but leave the server running (for sessions that used `connect`) |
| `/coms-net stop` | Disconnect and shut down the hub server (for the session that used `start`) |

### Check status

```
/coms-net status
```

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

## The Coms Feature Manager Pattern

For structured multi-agent workflows, generate a project-specific coms feature manager prompt:

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

This creates a `.pi/prompts/coms-feature-manager.md` file customized for your project. The pattern sets up:

- A **manager** agent that reviews code and directs implementation
- A **coder** agent that implements changes and responds to feedback
- A review → feedback → fix → re-review loop over coms

After generating the prompt, run `/reload`, then start a coms session and use `/coms-feature-manager` to activate the manager role.

## Available Tools

When coms is active, pi gains these tools (used automatically based on your requests):

| Action | P2P Tool | Networked Tool |
|---|---|---|
| List connected peers | `coms_list` | `coms_net_list` |
| Send a message to a peer | `coms_send` | `coms_net_send` |
| Poll for a reply (non-blocking) | `coms_get` | `coms_net_get` |
| Wait for a reply (blocking, ESC to cancel) | `coms_await` | `coms_net_await` |

> **Tip:** You don't need to call these tools directly. Just tell pi what you want — for example, "ask the reviewer to check my changes" — and it will use the right tools.

## Advanced Usage

### Project isolation

Sessions are scoped by project namespace. By default, the project is derived from the current working directory. Sessions in different directories won't see each other.

To override the project namespace:

```
/coms start --name agent1 --project my-shared-project
```

### Running the coms-net hub server manually

Instead of letting `/coms-net start` auto-manage the server, you can run it yourself:

```bash
bun ~/.pi/agent/git/github.com/myk-org/pi-config/extensions/coms/upstream-coms/coms-net-server.ts
```

Then connect sessions with `/coms-net connect`.

### LAN access

By default, the hub binds to `127.0.0.1` (localhost only). To allow connections from other machines:

1. Set an explicit auth token (required for non-loopback binds):

   ```bash
   export PI_COMS_NET_AUTH_TOKEN="your-secret-token"
   ```

2. Start with `--host 0.0.0.0`:

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

3. On remote machines, connect with the server URL and token:

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

> **Warning:** Always set `PI_COMS_NET_AUTH_TOKEN` when binding to non-loopback addresses. The server refuses to start on `0.0.0.0` without an explicit token.

### Hiding agents from discovery

Use `--explicit` to create agents that are only reachable by exact name — they won't appear in peer listings unless the caller passes `include_explicit=true`:

```
/coms start --name secret-agent --explicit
```

### Environment variables

| Variable | Default | Description |
|---|---|---|
| `PI_COMS_TIMEOUT_MS` | `1800000` (30 min) | P2P message response timeout |
| `PI_COMS_MAX_HOPS` | `5` | Maximum message forwarding hops (P2P) |
| `PI_COMS_PING_INTERVAL_MS` | `10000` | Peer health check interval (P2P) |
| `PI_COMS_NET_AUTH_TOKEN` | auto-generated | Bearer token for coms-net hub authentication |
| `PI_COMS_NET_HOST` | `127.0.0.1` | Hub server bind address |
| `PI_COMS_NET_PORT` | `0` (auto) | Hub server port |
| `PI_COMS_NET_SERVER_URL` | auto-discovered | Override hub server URL for clients |
| `PI_COMS_NET_MAX_HOPS` | `5` | Maximum message forwarding hops (networked) |
| `PI_COMS_NET_MESSAGE_TTL_MS` | `1800000` (30 min) | Message TTL on the hub |
| `PI_COMS_NET_HEARTBEAT_MS` | `10000` | Client heartbeat interval |
| `PI_COMS_NET_STALE_AFTER_MS` | `30000` | Time without heartbeat before agent marked stale |
| `PI_COMS_NET_OFFLINE_AFTER_MS` | `60000` | Time without heartbeat before agent marked offline |

### Hop limits and message forwarding

Messages include a hop counter that increments each time a message is forwarded between agents. This prevents infinite loops when agents forward messages to each other. The default limit is 5 hops — if reached, the send fails with a "hop limit reached" error.

### Reload resilience

Both `/coms` and `/coms-net` survive `/reload`. When you reload pi's configuration, the communication session is automatically re-established with the same flags. You don't need to re-run `/coms start` or `/coms-net start`.

## Troubleshooting

**Peers not visible after starting coms:**
- Ensure both sessions are in the same project directory (or use `--project` to set the same namespace)
- Run `/coms status` to confirm coms is active
- P2P sessions must be on the same machine

**`coms-net: failed to start server. Is Bun installed?`**
- Install Bun: `curl -fsSL https://bun.sh/install | bash`
- Bun is required for the coms-net hub server (already included in the Docker container)

**`coms-net: no auth token`**
- For local use, the token is auto-generated and stored in `~/.pi/coms-net/projects/<project>/server.secret.json`
- For remote connections, set `PI_COMS_NET_AUTH_TOKEN` or pass `--auth-token`

**Agent name collisions:**
- If a name is already taken, a numeric suffix is added automatically (e.g., `coder` becomes `coder2`)
- Use unique `--name` values across sessions to avoid this

**Stale peers in the pool widget:**
- Stale entries from crashed sessions are cleaned up automatically on session start
- Run `/coms` or `/coms-net` (bare command) to force-refresh the pool widget

See [Slash Commands and Extension Commands Reference](commands-reference.html) for the full `/coms` and `/coms-net` command syntax. See [Configuration and Environment Variables Reference](configuration-reference.html) for all environment variable details. See [Orchestrator Rules Reference](rules-reference.html) for the coms protocol rules that govern how the orchestrator interacts with coms tools.

## Related Pages

- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Customization and Extension Recipes](customization-recipes.html)
- [Orchestrator Rules Reference](rules-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.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 inside an isolated Docker container to sandbox the agent's access to your filesystem. The container ensures pi can only read/write your mounted project directory and pi settings — everything else on your host stays protected.

## Prerequisites

- Docker installed and running on your host
- A project directory you want pi to work in
- API credentials for your LLM provider (Vertex AI, Gemini, etc.)
- A GitHub token (`GITHUB_TOKEN`) for GitHub operations

## Quick start

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

docker run --rm -it \
  --name "pi-config-$(basename $PWD)-$(date +%s)" \
  --network host \
  -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 /tmp/pi-work:/tmp/pi-work:rw \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

This starts an interactive pi session in your current project directory. The container is destroyed when you exit (`--rm`).

## Step 1: Create an environment file

Create `~/.pi/.env` with your credentials and container-specific settings:

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

# Host username — required when your host user is not "node"
PI_HOST_USER=youruser

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

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

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

> **Warning:** Paths in the environment file (like `GOOGLE_APPLICATION_CREDENTIALS`) must use your **container home path** (`/home/<PI_HOST_USER>/...`), not the host path. The `PI_HOST_USER` mechanism creates symlinks so these paths resolve correctly inside the container.

## Step 2: Run with the environment file

```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 \
  -v /tmp/pi-work:/tmp/pi-work:rw \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest
```

## Step 3: Set up a shell alias

Add this to your `~/.bashrc` or `~/.zshrc` to start pi 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 /tmp/pi-work:/tmp/pi-work:rw \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest'
```

Then run from any project:

```bash
cd ~/projects/my-app
pi-docker
```

> **Tip:** The alias pulls the latest image on every run. If you prefer faster startup, remove the `docker pull` line and update manually with `docker pull ghcr.io/myk-org/pi-config:latest`.

## Understanding the volume mounts

Every mount serves a specific purpose:

| Mount | Mode | Purpose |
|---|---|---|
| `$PWD:$PWD` | rw | Your project directory — the only writable workspace |
| `$HOME/.pi:$HOME/.pi` | rw | Pi settings, sessions, memory, and installed packages |
| `$HOME/.gitconfig:$HOME/.gitconfig` | ro | Git configuration (user name, email, aliases) |
| `$HOME/.gitignore-global:$HOME/.gitignore-global` | ro | Global gitignore patterns |
| `$HOME/.ssh:$HOME/.ssh` | ro | SSH keys for git push/pull |
| `$HOME/.config/gh:$HOME/.config/gh` | ro | GitHub CLI authentication |
| `/tmp/pi-work:/tmp/pi-work` | rw | Temp files that persist across container restarts |

> **Note:** Read-only (`:ro`) mounts prevent the agent from modifying your host configuration. The container automatically copies `.gitconfig` to a writable location internally so git operations still work.

## How PI_HOST_USER works

The container runs as user `node` (UID 1000) with home directory `/home/node`. When you mount host paths that expand to `/home/youruser/...`, they won't resolve inside the container without help.

Setting `PI_HOST_USER=youruser` tells the init script to:

1. Create symlinks between `/home/youruser` and `/home/node`
2. Set `HOME` to `/home/youruser` inside the container
3. Ensure all mounted paths resolve correctly

If you skip this variable, mounts that use `$HOME` expansion may not resolve inside the container.

## Filesystem isolation

The container enforces strict filesystem boundaries:

- **Read-write:** Your project directory (`$PWD`) and pi settings (`~/.pi`)
- **Read-only:** Git, GitHub, and SSH configuration
- **Blocked:** All other host directories, other git repos, system files

This means the agent cannot accidentally modify files outside your project or access sensitive data on your host.

## Network mode

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

- Local MCP servers (via `mcpl`)
- LiteLLM proxy
- File preview (agents serve generated HTML via a local HTTP server)
- Pidash and Pidiff web dashboards

If you only use cloud-based LLM providers and don't need local services, you can omit `--network host`.

## Advanced Usage

### Optional mounts

Add these mounts to enable additional features:

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

When using `mcpl`, add the config path to your `.env` file too:

```env
MCPL_CONFIG_FILES=/home/youruser/.config/mcpl/mcp.json
```

### Docker socket access

To let the agent inspect running containers (read-only), mount the Docker socket:

```bash
-v /var/run/docker.sock:/var/run/docker.sock:ro \
--group-add $(stat -c '%g' /var/run/docker.sock)
```

The init script automatically handles socket permissions — it detects the socket's group ID and either adds the container user to that group or sets an ACL.

The agent uses a restricted `docker-safe` wrapper that only allows read-only commands:

| Allowed | Blocked |
|---------|---------|
| `ps`, `logs`, `inspect`, `top`, `stats` | `exec`, `run`, `rm`, `cp` |
| `port`, `diff`, `images`, `version`, `info` | `build`, `push`, `pull`, `stop`, `kill` |

For Podman, mount the Podman socket instead and set the runtime:

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

### Dashboard configuration

Two web dashboards start automatically alongside your pi session. See [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html) for full details on using them.

| Dashboard | Default Port | Environment Variable | URL |
|---|---|---|---|
| Pidash | 19190 | `PI_PIDASH_PORT` | `http://localhost:19190` |
| Pidiff | 19290 | `PI_PIDIFF_PORT` | `http://localhost:19290` |

To use custom ports or disable either dashboard, add to your `.env`:

```env
# Custom ports
PI_PIDASH_PORT=9999
PI_PIDIFF_PORT=9998

# Or disable entirely
PI_PIDASH_ENABLE=false
PI_PIDIFF_ENABLE=false
```

### External agent providers (acpx)

To route prompts through external AI agents like Cursor, set `ACPX_AGENTS` in your `.env` and mount the auth file:

```env
ACPX_AGENTS=cursor
```

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

See [Using External AI Agents (Cursor, Claude, Gemini)](external-ai-agents.html) for setup details.

### Passing arguments to pi

Any arguments after the image name are forwarded to `pi`:

```bash
# Run a specific slash command
docker run --rm -it ... ghcr.io/myk-org/pi-config:latest /implement add retry logic

# Start with a prompt
docker run --rm -it ... ghcr.io/myk-org/pi-config:latest "fix the failing tests"
```

### Building from source

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

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

### Project settings inside the container

Per-project settings in `.pi/pi-config-settings.json` override environment variables for that project. These work identically inside and outside the container:

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

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

### Complete alias with all optional mounts

Here's a full alias including every optional mount:

```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/mcpl/mcp.json":"$HOME/.config/mcpl/mcp.json":ro \
  -v "$HOME/.agents":"$HOME/.agents":rw \
  -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/.coderabbit":"$HOME/.coderabbit":rw \
  -v "$HOME/screenshots":"$HOME/screenshots":ro \
  -v /tmp/pi-work:/tmp/pi-work:rw \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --group-add $(stat -c '%g' /var/run/docker.sock) \
  -w "$PWD" \
  ghcr.io/myk-org/pi-config:latest'
```

## Environment variables reference

These are the container-specific variables you can set in your `.env` file. For the complete environment variables reference, see [Configuration and Environment Variables Reference](configuration-reference.html).

| Variable | Required | Description |
|---|---|---|
| `PI_HOST_USER` | Yes (if your username ≠ `node`) | Maps host home directory into container |
| `TZ` | No | Timezone for timestamps (e.g., `America/New_York`) |
| `GOOGLE_CLOUD_PROJECT` | Provider-dependent | Google Cloud project ID |
| `GOOGLE_CLOUD_LOCATION` | Provider-dependent | Google Cloud region |
| `GOOGLE_APPLICATION_CREDENTIALS` | Provider-dependent | Path to ADC JSON (container path) |
| `VERTEX_PROJECT_ID` | Provider-dependent | Vertex AI project |
| `VERTEX_REGION` | Provider-dependent | Vertex AI region |
| `VERTEX_CLAUDE_1M` | No | Enable 1M context for Claude on Vertex |
| `GITHUB_TOKEN` | Yes | GitHub personal access token |
| `GITHUB_API_TOKEN` | Yes | GitHub API token (can be same as above) |
| `GH_CONFIG_DIR` | No | GitHub CLI config directory (container path) |
| `GEMINI_API_KEY` | No | Gemini API key (for image generation) |
| `PI_IMAGE_MODEL` | No | Gemini model for image generation |
| `ACPX_AGENTS` | No | Comma-separated acpx agents (e.g., `cursor`) |
| `PI_PIDASH_PORT` | No | Pidash dashboard port (default: `19190`) |
| `PI_PIDIFF_PORT` | No | Pidiff diff viewer port (default: `19290`) |
| `PI_PIDASH_ENABLE` | No | Set `false` to disable pidash |
| `PI_PIDIFF_ENABLE` | No | Set `false` to disable pidiff |
| `PI_CO_AUTHOR` | No | Add co-author trailer to commits |
| `PI_USE_WORKTREES` | No | Force git worktree workflow |
| `PI_DREAM_INTERVAL_HOURS` | No | Memory dreaming interval (default: `3`) |
| `MCPL_CONFIG_FILES` | No | Path to MCP Launchpad config (container path) |

## Pre-installed tools

The container image comes with all tools ready to use:

| Tool | Purpose |
|---|---|
| `git`, `gh`, `glab` | Version control, GitHub CLI, GitLab CLI |
| `uv` / `uvx` | Python package management and execution |
| `go` | Go development |
| `node` / `npm` | JavaScript runtime (Node.js 22) |
| `bun` | Fast JavaScript runtime (required by coms-net) |
| `kubectl` / `oc` | Kubernetes and OpenShift CLI |
| `mcpl` | MCP server access |
| `acpx` | Agent proxy for external AI models |
| `agent-browser` | Browser automation (Chromium via Playwright) |
| `docker-safe` | Read-only Docker/Podman inspection wrapper |
| `cr` | CodeRabbit CLI for local AI code reviews |
| `prek` | Pre-commit hook runner |
| `mcp-proxy` | MCP transport proxy |
| `cursor`, `claude` | External AI agent CLIs |
| `jq`, `curl` | JSON processing, HTTP requests |

## Container startup lifecycle

On every container start, the entrypoint automatically:

1. Installs/updates pi to the latest version
2. Installs or updates the `pi-config` package from GitHub
3. Installs `myk-pi-tools` CLI from the latest source
4. Registers companion packages (`pi-web-access`, `pi-tasks`)
5. Copies `.gitconfig` to a writable location (since the mount is read-only)
6. Configures SSH timeouts for git operations (15s keepalive, 10s connect timeout)
7. Ensures `.pi/memory/`, `.worktrees/`, and `.pi/tasks/` are in the global gitignore
8. Starts pi with any arguments you passed

This means you always get the latest version of pi and all extensions on every session.

## Troubleshooting

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

Make sure `PI_HOST_USER` in your `.env` file matches your host username exactly. Without it, paths like `/home/youruser/.ssh` won't resolve because the container's default home is `/home/node`.

### Permission denied on mounted files

The container runs as user `node` (UID 1000). If your host files are owned by a different UID, you may see permission errors. Ensure your host user's UID is 1000, or adjust file permissions on the host.

### Container can't reach local services

Make sure you included `--network host` in your `docker run` command. Without it, the container has its own network namespace and can't reach services on `localhost`.

### Git push/pull hangs

The container sets SSH keepalive and connection timeouts automatically (15-second keepalive interval, 10-second connection timeout). If git operations still hang, check that your SSH keys are correctly mounted at `$HOME/.ssh` with `:ro` mode.

### Startup WARNING about cached packages

A `WARNING` on stderr during startup is normal when pi-config is already cached in `~/.pi`. The container runs `pi install` and `pi update` on every start to stay current. If pi misbehaves, verify your network connectivity.

## Related Pages

- [Installing and Starting Your First Session](quickstart.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Using the Web Dashboard and Diff Viewer](dashboards-and-diffs.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)
- [Using ACPX Provider for External Agent Models](acpx-provider.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

- [Controlling Pi Sessions from Discord](discord-bot.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)
- [Slash Commands and Extension Commands Reference](commands-reference.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 fetches the PR diff and the project's AGENTS.md, then sends both to all three code review agents in parallel. After analysis, pi presents findings grouped by severity (CRITICAL, WARNING, SUGGESTION) and lets you choose which to post as inline GitHub comments.

- Requires `gh` CLI to be authenticated
- 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".

- 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

Practical, copy-paste recipes for customizing pi-config — adding agents, writing prompts, creating skills, configuring project settings, and connecting MCP servers.

## Add a New Specialist Agent

Create a specialist agent that the orchestrator routes tasks to automatically.

**Step 1 — Create the agent file** (`agents/rust-expert.md`):

```markdown
---
name: rust-expert
description: Rust code creation, modification, refactoring, and fixes. Specializes in ownership, lifetimes, async, and idiomatic Rust.
tools: read, write, edit, bash
---

You are a Rust Expert specializing in safe, performant, and idiomatic Rust 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

- Ownership, borrowing, lifetimes
- Async: tokio, async-std
- Error handling: thiserror, anyhow
- Testing: cargo test, proptest
- Tooling: clippy, rustfmt, cargo-audit

## Quality Checklist

- [ ] `cargo clippy` passes with no warnings
- [ ] `cargo test` passes
- [ ] Error types use thiserror for libraries, anyhow for binaries
- [ ] Public APIs have doc comments
- [ ] Formatted with rustfmt
```

**Step 2 — Add routing** in `rules/10-agent-routing.md`:

```markdown
| Rust (.rs)                                                   | `rust-expert`                    |
```

**Step 3 — Register for bug reporting** in `rules/50-agent-bug-reporting.md` — add `rust-expert` to the agents list.

The agent file uses YAML frontmatter with three required fields: `name`, `description`, and `tools`. The body contains the system prompt. Changes take effect on the next pi session.

- **Minimal agent:** Only `name` and `description` are required in frontmatter. `tools` defaults to all available tools.
- **Read-only agents:** Set `tools: read, bash` for agents that should not modify files (like `scout` or `debugger`).
- **Model override:** Add `model: claude-haiku-4-5` to frontmatter for fast, cheap agents (the `scout` agent does this).

## Add a Project-Local Agent

Override or extend agents for a specific project without modifying pi-config.

Create `.pi/agents/qa-checker.md` in your project root:

```markdown
---
name: qa-checker
description: Project-specific QA validation — runs smoke tests and checks acceptance criteria.
tools: read, bash
---

You are a QA checker for this project. Run the smoke test suite and verify
acceptance criteria from the linked GitHub issue.

## Steps

1. Read the issue description for acceptance criteria
2. Run `make smoke-test`
3. Verify each criterion is met
4. Report pass/fail with evidence
```

Project agents (`.pi/agents/`) override package agents with the same name. User agents (`~/.pi/agent/agents/`) sit in between — the priority order is: package → user → project (later wins).

> **Tip:** Use project-local agents for workflows unique to one repository. Use user agents (`~/.pi/agent/agents/`) for personal agents shared across all your projects.

## Create a Custom Prompt Template

Add a new slash command that the orchestrator executes directly.

Create `prompts/lint-fix.md` in the pi-config repo (or `.pi/prompts/lint-fix.md` for project-local):

```markdown
---
description: "Run linter and auto-fix all issues — /lint-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

Detect the project's linter and auto-fix all issues.

## Steps

1. Detect linter from project files:
   - `pyproject.toml` with `[tool.ruff]` → `uv run ruff check --fix .`
   - `package.json` with `eslint` → `npx eslint --fix .`
   - `Makefile` with `lint` target → `make lint`

2. Delegate to the appropriate language expert:
   - Python → `python-expert`
   - JS/TS → `ts-expert`
   - Go → `go-expert`

3. If a path was provided in raw arguments, scope to that path only.

4. Report what was fixed.
```

The `$ARGUMENTS` placeholder is replaced with whatever the user types after the command (e.g., `/lint-fix src/`). The `description` field appears in autocomplete. The bug reporting blockquote is mandatory for all prompt templates.

- **Project-local prompts** go in `.pi/prompts/` and are only available in that project.
- **Argument autocomplete:** If your command needs Tab completions, add an entry in `extensions/orchestrator/extended-autocomplete.ts`. See [Slash Commands and Extension Commands Reference](commands-reference.html) for all available commands.

## Create a Reusable Skill with /create-skill

Capture a successful workflow as a reusable skill that pi can apply to future tasks.

```text
/create-skill debug-flaky-test
```

Pi will:
1. Ask whether to save **globally** (`~/.agents/skills/`) or **per-project** (`.pi/skills/`)
2. Review the current conversation for steps, commands, and pitfalls
3. Write a `SKILL.md` file with the extracted workflow

The generated skill follows this structure:

```markdown
---
name: debug-flaky-test
description: "Diagnose and fix flaky tests caused by timing-sensitive assertions or shared state"
---

# Debug Flaky Test

## When to Use

- Test passes locally but fails in CI
- Test fails intermittently with no code changes

## Steps

1. Run the test 10 times: `uv run pytest tests/test_api.py -x --count=10`
2. Check for shared state: grep for module-level variables and class attributes
3. Check for timing: search for `sleep`, `time.time()`, hardcoded timeouts
4. Add isolation: use `tmp_path` fixtures, reset state in `setUp`/`tearDown`
5. Verify: run 50 times in CI-like conditions

## Pitfalls

- Don't just increase sleep timeouts — find the race condition
- Shared database fixtures are the #1 cause of flaky tests
```

Skills are automatically discovered by pi at session start. Global skills are available everywhere; project skills only in that project.

> **Tip:** The dreaming system (`/dream`) can also auto-generate project-level skills when it detects recurring multi-step workflows in your conversation history.

## Configure Project Settings

Customize pi behavior per-project using `.pi/pi-config-settings.json`.

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

Place this file at `.pi/pi-config-settings.json` in your project root.

| Setting | Type | Default | Effect |
|---------|------|---------|--------|
| `co_author` | boolean | `false` | Add co-author trailer to git commits |
| `use_worktrees` | boolean | `false` | Force worktree-only workflow for branches |
| `dream_interval_hours` | number | `3` | Hours between automatic memory consolidation |

Resolution order: project file → environment variable → default. Environment variables (`PI_CO_AUTHOR`, `PI_USE_WORKTREES`, `PI_DREAM_INTERVAL_HOURS`) serve as global fallbacks when no project file exists.

> **Note:** Changes to the settings file are picked up automatically within 30 seconds — no session restart needed. See [Configuration and Environment Variables Reference](configuration-reference.html) for the full list of env vars.

## Save a Memory with /remember

Persist a lesson, preference, or decision across sessions.

```text
/remember Always run pre-commit hooks before pushing — CI rejects unformatted code
```

Pi determines the best category automatically (`lesson`, `preference`, `decision`, `mistake`, `pattern`, or `done`) and saves it as a **pinned** memory that won't decay over time.

Under the hood, this runs:

```bash
uv run myk-pi-tools memory add -c lesson -s "Always run pre-commit hooks before pushing — CI rejects unformatted code" --pinned
```

See [Working with Project Memory](memory-system.html) for the full memory system.

## Search MCP Servers for Available Tools

Find and use tools from MCP servers configured via mcpl.

```bash
# Search for a tool by what it does
mcpl search "list projects"

# List all configured MCP servers
mcpl list

# List tools on a specific server
mcpl list vercel

# Get full schema with example call
mcpl inspect sentry search_issues --example

# Call a tool
mcpl call vercel list_projects '{"teamId": "team_xxx"}'
```

The orchestrator uses `mcpl search` or `mcpl list` to discover tools, then delegates actual tool execution to specialist agents. See [Orchestrator Rules Reference](rules-reference.html) for the MCP launchpad rules.

- **Verify connections:** Run `mcpl verify` to test all server connections.
- **Debug issues:** Run `mcpl session stop` to restart the daemon, then retry.
- **Timeout tuning:** Set `MCPL_CONNECTION_TIMEOUT=120` for slow servers.

## Add a Project-Local Prompt Template

Create a slash command available only in one project.

```bash
mkdir -p .pi/prompts
```

Create `.pi/prompts/deploy-staging.md`:

```markdown
---
description: "Deploy current branch to staging — /deploy-staging"
---

## 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?"

# Deploy to Staging

1. Delegate to `git-expert`: ensure working tree is clean, all changes committed
2. Delegate to `worker`: run `make docker-build && make deploy-staging`
3. Delegate to `worker`: run `curl -sf https://staging.example.com/health` to verify
4. Report deployment status
```

After creating the file, run `/reload` in your pi session to register the new command. It will appear as `/deploy-staging` with Tab completion.

## Override a Built-in Agent for One Project

Customize a built-in agent's behavior in a specific project without forking pi-config.

Create `.pi/agents/python-expert.md` in your project:

```markdown
---
name: python-expert
description: Python expert customized for this Django project. Uses poetry, Django conventions, and pytest-django.
tools: read, write, edit, bash
---

You are a Python Expert for this Django project.

## Base Rules

- Execute first, explain after
- Do NOT explain what you will do — just do it
- If a task falls outside your domain, report it and hand off

## Project Conventions

- Package manager: poetry (NOT uv for this project)
- Framework: Django 5.x with DRF
- Tests: pytest-django with factory_boy fixtures
- Run tests: `poetry run pytest --reuse-db`
- Migrations: always run `poetry run python manage.py makemigrations` after model changes

## Quality Checklist

- [ ] `poetry run ruff check .` passes
- [ ] `poetry run pytest` passes
- [ ] Django migrations created for model changes
- [ ] ViewSet permissions tested
```

Since project agents override package agents by name, the orchestrator will use your customized `python-expert` instead of the built-in one — only in this project.

## Create a Multi-Agent Chain Prompt

Build a prompt that chains multiple specialist agents together.

Create `.pi/prompts/refactor-and-test.md`:

```markdown
---
description: "Refactor a module and add tests — /refactor-and-test <module>"
argument-hint: "<module>"
---

## 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?"

Use the subagent tool with a chain of 3 agents:

1. **scout** — Find all usages, callers, and tests for the module from raw arguments.
   Return file locations, public API, and dependency graph.

2. **worker** — Based on {previous}, refactor the module:
   - Extract complex functions
   - Improve naming
   - Remove dead code
   - Preserve the public API

3. **test-automator** — Based on {previous}, add missing test coverage:
   - Unit tests for extracted functions
   - Edge case tests identified during refactoring
   - Verify existing tests still pass
```

The `{previous}` placeholder passes the output of one agent to the next. This pattern is used by the built-in `/implement` and `/scout-and-plan` commands.

## Set Up a Coms Feature Manager

Generate a project-specific inter-agent review workflow using the built-in template.

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

Pi will:
1. Read the immutable template from `templates/coms-feature-manager-prompt.md`
2. Analyze your project (detect test commands, test locations, project type)
3. Ask if you need live/E2E verification
4. Fill all placeholders with project-specific values
5. Write `.pi/prompts/coms-feature-manager.md`

After running `/reload`, use `/coms-feature-manager` to activate a manager agent that reviews and directs a coder peer via the coms system.

> **Note:** This requires a running coms session. See [Communicating Between Pi Sessions](inter-agent-communication.html) for setup.

## Enable Co-Author Commit Trailers

Add pi as a co-author on all git commits in a project.

```bash
mkdir -p .pi
echo '{ "co_author": true }' > .pi/pi-config-settings.json
```

Or set globally via environment variable:

```bash
export PI_CO_AUTHOR=true
```

When enabled, the git-expert agent adds a `Co-authored-by` trailer to commit messages. The project setting overrides the env var.

## Force Worktree-Only Workflow

Prevent branch switching in the main worktree — essential for multi-PR parallel work.

```json
{
  "use_worktrees": true
}
```

Save to `.pi/pi-config-settings.json`. When enabled, pi uses `git worktree` for every branch operation instead of `git checkout`/`git switch`, preventing corruption when multiple agents work simultaneously.

## Adjust Dreaming Frequency

Control how often the background memory consolidation runs.

```json
{
  "dream_interval_hours": 1
}
```

The dreaming system scans conversation history and writes memories to topic files. The default interval is 3 hours. Set a lower value for active sessions where you want faster learning, or a higher value (up to 24) to reduce background work.

- **Manual trigger:** Run `/dream` to consolidate immediately.
- **Toggle auto-dreaming:** Run `/dream-auto off` to disable, `/dream-auto on` to re-enable.

## Create a Read-Only Analysis Agent

Build an agent that can investigate but never modify files.

```markdown
---
name: perf-analyzer
description: Performance analysis — profiles code, identifies bottlenecks, suggests optimizations. Does not modify files.
tools: read, bash
---

You are a performance analysis specialist. Profile code and identify bottlenecks.

## Base Rules

- Execute first, explain after
- Do NOT modify files — only analyze and report
- If a task falls outside your domain, report it and hand off

## Approach

1. Profile the target code path
2. Identify the top 3 bottlenecks
3. Measure baseline metrics
4. Report findings with specific optimization recommendations
5. Estimate expected improvement for each recommendation
```

By setting `tools: read, bash`, the agent cannot use `write` or `edit`. This is the same pattern used by `scout`, `planner`, `debugger`, and the code reviewer agents.

## Related Pages

- [Specialist Agents Reference](agents-reference.html)
- [Understanding Agent Routing and Delegation](agent-routing.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Using Slash Commands and Prompt Templates](slash-commands.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 defined as a Markdown file with YAML frontmatter in the `agents/` directory and is automatically discovered at session start.

For how the orchestrator selects agents, see [Understanding Agent Routing and Delegation](agent-routing.html). For the code review loop that uses the three reviewer agents, see [Running the Automated Code Review Loop](code-review-loop.html). For adding or removing agents, see [Customization and Extension Recipes](customization-recipes.html).

## Agent Discovery

Agents are loaded from three sources, in priority order (later overrides earlier by name):

1. **Package agents** — bundled in `agents/` (this repository)
2. **User agents** — `~/.pi/agent/agents/`
3. **Project agents** — `.pi/agents/` in the current directory or nearest parent

## Agent Summary Table

| Agent | Tools | Model | Async-Only | Category |
|-------|-------|-------|------------|----------|
| `api-documenter` | read, write, edit, bash | default | No | Documentation |
| `bash-expert` | read, write, edit, bash | default | No | Language |
| `code-reviewer-guidelines` | read, bash | default | **Yes** | Code Review |
| `code-reviewer-quality` | read, bash | default | **Yes** | Code Review |
| `code-reviewer-security` | read, bash | default | **Yes** | Code Review |
| `debugger` | read, bash | default | No | Development |
| `docker-expert` | read, write, edit, bash | default | No | Infrastructure |
| `docs-fetcher` | read, bash | default | No | Documentation |
| `git-expert` | read, bash | default | No | Version Control |
| `github-expert` | read, bash | default | No | Version Control |
| `go-expert` | read, write, edit, bash | default | No | Language |
| `java-expert` | read, write, edit, bash | default | No | Language |
| `jenkins-expert` | read, write, edit, bash | default | No | Infrastructure |
| `kubernetes-expert` | read, write, edit, bash | default | No | Infrastructure |
| `planner` | read, bash | default | No | Development |
| `python-expert` | read, write, edit, bash | default | No | Language |
| `reviewer` | read, bash | default | No | Code Review |
| `scout` | read, bash | `claude-haiku-4-5` | No | Development |
| `security-auditor` | read, bash | default | No | Security |
| `technical-documentation-writer` | read, write, edit, bash | default | No | Documentation |
| `test-automator` | read, write, edit, bash | default | No | Testing |
| `test-runner` | bash, read | default | No | Testing |
| `ts-expert` | read, write, edit, bash | default | No | Language |
| `worker` | read, write, edit, bash | default | No | General |

> **Note:** Async-only agents are automatically promoted to `async: true` by the subagent tool. They cannot be used in chain mode. See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for details.

---

## Language Specialist Agents

### `python-expert`

Python code creation, modification, refactoring, and fixes. Specializes in idiomatic Python, async/await, testing, and modern Python development.

| Property | Value |
|----------|-------|
| **File** | `agents/python-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Python files (`.py`), Python-related tasks, running Python tests.

**Key behaviors:**

- Enforces `uv`/`uvx` exclusively — never uses `python`, `python3`, `pip`, or `pip3` directly
- Uses type hints on public functions
- Targets pytest with >90% coverage
- Formats with ruff/black

**Example delegation:**

```text
subagent(agent="python-expert", task="Add retry logic to the API client in src/client.py")
```

---

### `ts-expert`

TypeScript, JavaScript, and frontend framework development (React/Vue/Angular/CSS). UI design, component creation, and modern web technologies.

| Property | Value |
|----------|-------|
| **File** | `agents/ts-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Frontend files (JS/TS/React/Vue/Angular), CSS/styling work, frontend testing.

**Key behaviors:**

- Covers JavaScript, TypeScript, React, Vue, Angular, and CSS
- Frontend testing with Jest, Vitest, Cypress, Playwright
- Build tooling: Vite, Webpack, esbuild

**Example delegation:**

```text
subagent(agent="ts-expert", task="Create a React component for the user settings page")
```

---

### `go-expert`

Go code creation, modification, refactoring, and fixes. Specializes in goroutines, channels, modules, testing, and high-performance Go.

| Property | Value |
|----------|-------|
| **File** | `agents/go-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Go files (`.go`), Go-related tasks.

**Key behaviors:**

- Concurrency patterns: goroutines, channels, sync primitives
- Table-driven tests with `-race` flag
- Error wrapping with `fmt.Errorf("...: %w", err)`
- Context propagation through call chains
- Linting with golangci-lint, formatting with gofmt/goimports

**Example delegation:**

```text
subagent(agent="go-expert", task="Implement a worker pool with graceful shutdown in pkg/workers/")
```

---

### `java-expert`

Java code creation, modification, refactoring, and fixes. Specializes in Spring Boot, Maven, Gradle, JUnit testing, and enterprise applications.

| Property | Value |
|----------|-------|
| **File** | `agents/java-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Java files (`.java`), Spring/Maven/Gradle tasks.

**Key behaviors:**

- Targets Java 17+ (records, sealed classes, pattern matching)
- Spring ecosystem: Boot, MVC, Data, Security, WebFlux
- Testing with JUnit 5, Mockito, TestContainers
- Logging with SLF4J, JavaDoc on public APIs

**Example delegation:**

```text
subagent(agent="java-expert", task="Add a REST endpoint for user profiles using Spring Boot")
```

---

### `bash-expert`

Bash and shell scripting creation, modification, refactoring, and fixes. Specializes in Bash, Zsh, POSIX shell, automation scripts, and system administration.

| Property | Value |
|----------|-------|
| **File** | `agents/bash-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Shell scripts (`.sh`), shell scripting tasks, system administration automation.

**Key behaviors:**

- Defensive scripting with `set -euo pipefail`
- All variables quoted (`"$var"`)
- Trap for cleanup on exit
- Shebang: `#!/usr/bin/env bash`
- Must pass shellcheck with no warnings
- Prefers POSIX when possible, bash-specific when needed

**Example delegation:**

```text
subagent(agent="bash-expert", task="Write a deployment script that rotates log files and restarts the service")
```

---

## Code Review Agents

> **Note:** All three code review agents (`code-reviewer-quality`, `code-reviewer-guidelines`, `code-reviewer-security`) are **async-only**. They are always dispatched in parallel during the code review loop. See [Running the Automated Code Review Loop](code-review-loop.html) for the full workflow.

### `code-reviewer-quality`

Code review focused on general code quality and maintainability. Reviews for clean code, proper abstractions, DRY, and readability.

| Property | Value |
|----------|-------|
| **File** | `agents/code-reviewer-quality.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |
| **Async-only** | Yes |

**Review focus areas:**

- 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

**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`

Code review focused on project guidelines and style adherence. Reviews for AGENTS.md compliance, naming conventions, and project patterns.

| Property | Value |
|----------|-------|
| **File** | `agents/code-reviewer-guidelines.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |
| **Async-only** | Yes |

**Review focus areas:**

- AGENTS.md compliance (reads the project's AGENTS.md first)
- Documentation updates — flags missing AGENTS.md/README.md updates as `[CRITICAL]`
- Project-specific coding standards
- Naming conventions matching existing codebase
- File/folder structure consistency
- Commit message and branch naming compliance
- Import ordering and grouping

**Output format:**

```text
[SEVERITY] file:line — Description
  Rule: Which guideline is violated
  Suggestion: How to fix
```

Severity levels: `[CRITICAL]`, `[WARNING]`, `[SUGGESTION]`

Approval output: `"Code follows all project guidelines. Approved."`

---

### `code-reviewer-security`

Code review focused on bugs, logic errors, and security vulnerabilities. Reviews for correctness, edge cases, and potential exploits.

| Property | Value |
|----------|-------|
| **File** | `agents/code-reviewer-security.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |
| **Async-only** | Yes |

**Review focus areas:**

- 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
- Insecure cryptographic usage
- Path traversal and file access
- Resource leaks (unclosed connections/files)
- Edge cases and boundary conditions

**Output format:**

```text
[SEVERITY] file:line — Description
  Risk: What could go wrong
  Suggestion: How to fix
```

Severity levels: `[CRITICAL]`, `[WARNING]`, `[SUGGESTION]`

Approval output: `"No bugs or security issues found. Code approved."`

---

### `reviewer`

General code review agent. Reviews code changes for quality, correctness, and style.

| Property | Value |
|----------|-------|
| **File** | `agents/reviewer.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Review areas:** Correctness, security, quality, performance, style.

**Output format:**

```text
[SEVERITY] file:line — Description
  Suggestion: How to fix
```

Approval output: `"No issues found. Code approved. ✅"`

> **Tip:** The three specialized review agents (`code-reviewer-quality`, `code-reviewer-guidelines`, `code-reviewer-security`) are preferred for the automated code review loop. The `reviewer` agent serves as a general-purpose reviewer for simpler reviews.

---

## Version Control Agents

### `git-expert`

Local git operations including commits, branching, merging, rebasing, stash, and resolving git issues. For GitHub platform operations, use `github-expert`.

| Property | Value |
|----------|-------|
| **File** | `agents/git-expert.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No (modifies git state only) |

**Routing triggers:** commit, branch, merge, rebase, stash, cherry-pick, log, diff, status, config.

**Protection rules:**

- Never commits or pushes to main/master
- Never commits to already-merged branches
- Never uses `--no-verify`
- Branch prefixes: `feature/`, `fix/`, `hotfix/`, `refactor/`

**Commit message format:** Uses `-F -` to read from stdin:

```bash
echo -e "Your commit title\n\nYour commit body" | git commit -F -
```

**Separation of concerns:**

- Does NOT run tests — asks the orchestrator to confirm tests passed before pushing
- Does NOT fix code — reports pre-commit hook failures to orchestrator

**Delegates to:** `github-expert` for PRs, issues, releases, workflows.

**Example delegation:**

```text
subagent(agent="git-expert", task="Create a feature branch and commit the changes in src/")
```

---

### `github-expert`

GitHub platform operations including PRs, issues, releases, repos, and workflows. Uses the `gh` CLI for all GitHub API interactions.

| Property | Value |
|----------|-------|
| **File** | `agents/github-expert.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** PRs, issues, releases, repos, workflows, GitHub API operations.

**Core operations:**

| Operation | Commands |
|-----------|----------|
| Pull Requests | `gh pr create`, `gh pr view`, `gh pr list`, `gh pr merge`, `gh pr close`, `gh pr checkout`, `gh pr diff`, `gh pr checks` |
| Issues | `gh issue create`, `gh issue view`, `gh issue list`, `gh issue close`, `gh issue comment`, `gh issue edit` |
| Releases | `gh release create`, `gh release view`, `gh release list` |
| Workflows | `gh workflow list`, `gh workflow run`, `gh run list`, `gh run view` |

**Protection rules:**

- Never pushes to main/master
- Never commits to merged branches
- Does NOT run tests — asks orchestrator to delegate to `test-runner` first

**Delegates to:** `git-expert` for commit, branch, merge, rebase.

**Example delegation:**

```text
subagent(agent="github-expert", task="Create a PR from feature/add-retry-logic to main with a description of the changes")
```

---

## Infrastructure Agents

### `docker-expert`

Docker and container-related tasks including Dockerfile creation, container orchestration, image optimization, and containerization workflows.

| Property | Value |
|----------|-------|
| **File** | `agents/docker-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Docker, Dockerfile, container orchestration tasks.

**Key behaviors:**

- Security first: non-root users, minimal base images
- Multi-stage builds, cache mounts
- Small images: Alpine, distroless, scratch
- Reproducible builds: pinned versions, locked dependencies
- Covers Docker Engine, BuildKit, Buildx, Docker Compose, Docker Swarm, Podman, Buildah

**Example delegation:**

```text
subagent(agent="docker-expert", task="Optimize the Dockerfile to use multi-stage builds and reduce image size")
```

---

### `kubernetes-expert`

Kubernetes-related tasks including cluster management, workload deployment, service mesh, and cloud-native orchestration.

| Property | Value |
|----------|-------|
| **File** | `agents/kubernetes-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Kubernetes, OpenShift, Helm, K8s manifest tasks.

**Key behaviors:**

- Declarative (GitOps) over imperative commands
- Security: RBAC, Network Policies, Pod Security Standards
- Observability: Prometheus, Grafana integration
- Covers: Core K8s, StatefulSets, DaemonSets, Jobs, CronJobs, Helm, Kustomize, ArgoCD, Flux, Istio, Linkerd
- Platforms: OpenShift, EKS, GKE, AKS, k3s

**Example delegation:**

```text
subagent(agent="kubernetes-expert", task="Create Helm chart for the API service with liveness/readiness probes")
```

---

### `jenkins-expert`

Jenkins-related code including CI/CD pipelines, Jenkinsfiles, Groovy scripts, and build automation.

| Property | Value |
|----------|-------|
| **File** | `agents/jenkins-expert.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Jenkins, CI/CD, Groovy scripts, Jenkinsfile tasks.

**Critical rules:**

- Never hardcodes credentials — uses `withCredentials`
- Never skips validation with workarounds
- Uses `@NonCPS` for non-serializable code
- Cleans workspace after builds

**Key behaviors:**

- Declarative and scripted pipelines
- Shared libraries, Groovy scripting
- Jenkins Configuration as Code (JCasC)
- Plugin integration: Pipeline, Docker, Kubernetes, credentials

**Example delegation:**

```text
subagent(agent="jenkins-expert", task="Create a declarative Jenkinsfile with parallel test stages and Docker build")
```

---

## Development Agents

### `debugger`

Debugging specialist for errors, test failures, and unexpected behavior. Diagnoses only — does not modify files.

| Property | Value |
|----------|-------|
| **File** | `agents/debugger.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** Error analysis, test failure investigation, unexpected behavior debugging, stack trace analysis.

**Key behaviors:**

- Diagnoses only — the orchestrator delegates the actual fix to the appropriate language specialist
- **Rule of Three:** After 3 failed fix attempts, stops and flags an architectural problem
- Follows a 4-phase systematic debugging approach:
  1. Root cause investigation
  2. Pattern analysis
  3. Hypothesis and testing
  4. Implementation recommendation

> **Warning:** This agent never modifies files. It produces a diagnosis with recommended fixes, file locations, and testing approaches. The orchestrator must route the fix to the appropriate specialist.

**Example delegation:**

```text
subagent(agent="debugger", task="Investigate why test_user_auth is failing with a 403 after the latest changes")
```

---

### `planner`

Creates detailed implementation plans from codebase context. Does not write code.

| Property | Value |
|----------|-------|
| **File** | `agents/planner.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** Used by the `/scout-and-plan` prompt template and when the orchestrator needs an implementation plan before coding.

**Output structure:**

- Overview of changes and rationale
- Per-file change details with specific functions/classes and line ranges
- Edge cases and handling strategies
- Test scenarios with expected behavior
- Risks and mitigations

**Example delegation:**

```text
subagent(agent="planner", task="Create an implementation plan for adding WebSocket support to the notification service")
```

---

### `scout`

Fast codebase reconnaissance. Finds relevant files, functions, and dependencies for a given task.

| Property | Value |
|----------|-------|
| **File** | `agents/scout.md` |
| **Tools** | `read`, `bash` |
| **Model** | `claude-haiku-4-5` |
| **Modifies files** | No |

> **Note:** This is the only agent with a model override. It uses `claude-haiku-4-5` for fast, low-cost reconnaissance.

**Routing triggers:** Used by the `/scout-and-plan` prompt template for initial codebase exploration before planning.

**Output structure:**

- Relevant files with descriptions
- Key functions/classes with file paths and line numbers
- Dependency mapping (internal and external)
- Related test files
- Observations about codebase structure

**Example delegation:**

```text
subagent(agent="scout", task="Find all files related to user authentication and map their dependencies")
```

---

## Testing Agents

### `test-automator`

Creates comprehensive test suites with unit, integration, and e2e tests. Sets up CI pipelines, mocking strategies, and test data.

| Property | Value |
|----------|-------|
| **File** | `agents/test-automator.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Test creation, test suite design, CI/CD test pipeline configuration.

**Key behaviors:**

- Follows the test pyramid: many unit, fewer integration, minimal E2E
- Arrange-Act-Assert pattern
- Tests behavior, not implementation
- Enforces TDD (RED-GREEN-REFACTOR cycle)
- Uses appropriate frameworks: Jest, pytest, JUnit, etc.

**Example delegation:**

```text
subagent(agent="test-automator", task="Write unit tests for the PaymentProcessor class with edge cases for failed transactions")
```

---

### `test-runner`

Runs tests and analyzes failures. Returns detailed failure analysis without making fixes.

| Property | Value |
|----------|-------|
| **File** | `agents/test-runner.md` |
| **Tools** | `bash`, `read` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** Invoked during the code review loop (step 5) and when the orchestrator needs to verify tests pass.

**Key behaviors:**

- Runs exactly the test command specified
- Never modifies files
- 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.
```

**Example delegation:**

```text
subagent(agent="test-runner", task="Run pytest in tests/ and analyze any failures")
```

---

## Documentation Agents

### `technical-documentation-writer`

Comprehensive, user-focused technical documentation for projects, features, or systems.

| Property | Value |
|----------|-------|
| **File** | `agents/technical-documentation-writer.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Markdown files (`.md`), documentation tasks.

**Key behaviors:**

- User-first writing with progressive disclosure
- Supports: Markdown, MkDocs, Docusaurus, Sphinx
- All code examples tested and verified
- WCAG accessibility and SEO-friendly structure

**Example delegation:**

```text
subagent(agent="technical-documentation-writer", task="Write a getting started guide for the new CLI tool")
```

---

### `api-documenter`

Creates OpenAPI/Swagger specs, generates SDKs, and writes developer documentation. Handles versioning, examples, and interactive docs.

| Property | Value |
|----------|-------|
| **File** | `agents/api-documenter.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** API documentation, OpenAPI specs, SDK generation tasks.

**Key behaviors:**

- OpenAPI 3.0/Swagger specification writing
- SDK generation and client libraries
- Interactive documentation (Postman/Insomnia)
- Code examples in multiple languages
- Authentication and error documentation
- Versioning strategies and migration guides

**Example delegation:**

```text
subagent(agent="api-documenter", task="Generate an OpenAPI 3.0 spec for the /users and /orders REST endpoints")
```

---

### `docs-fetcher`

Fetches current documentation for external libraries and frameworks. Prioritizes `llms.txt` when available, falls back to web parsing.

| Property | Value |
|----------|-------|
| **File** | `agents/docs-fetcher.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** Any request for external library/framework documentation (React, FastAPI, Django, etc.).

> **Warning:** The orchestrator must never fetch external documentation directly — it must always delegate to `docs-fetcher`. See [Understanding Agent Routing and Delegation](agent-routing.html) for the mandatory routing rule.

**Retrieval priority:**

1. `{base_url}/llms-full.txt` (optimized for LLMs)
2. `{base_url}/llms.txt`
3. HTML parsing (fallback)

**Output format:**

```markdown
## {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})
```

**Example delegation:**

```text
subagent(agent="docs-fetcher", task="Fetch the React hooks documentation from the official React docs")
```

---

## Security Agent

### `security-auditor`

Audits external repositories for security risks before adoption — checks for malicious code, data exfiltration, supply chain risks, and trust signals.

| Property | Value |
|----------|-------|
| **File** | `agents/security-auditor.md` |
| **Tools** | `read`, `bash` |
| **Model** | default |
| **Modifies files** | No |

**Routing triggers:** External repository security audits, third-party dependency evaluation.

**Audit categories:**

| Category | What It Checks |
|----------|----------------|
| Malicious Code | Backdoors, eval/exec, obfuscated strings, hidden functionality |
| Data Exfiltration | Outbound endpoints, telemetry, credential reading, DNS exfiltration |
| Supply Chain Risk | Dependency CVEs, install hooks, abandoned packages, floating versions |
| Filesystem & System Access | Sensitive path access, self-updating mechanisms, child process usage |
| Network & Permissions | Port listening, TLS bypass, proxy/redirect behavior |
| Trust Signals | Contributors, stars, activity, organization reputation |
| License Compatibility | MIT/Apache/BSD (✅), GPL/AGPL (⚠️), missing license (❌) |
| Build & Release Integrity | Source-release match, signed binaries, CI transparency |

**Verdict levels:** `✅ SAFE`, `⚠️ CAUTION`, `❌ UNSAFE`

**Example delegation:**

```text
subagent(agent="security-auditor", task="Audit https://github.com/example/some-library for security risks before we adopt it")
```

---

## General-Purpose Agent

### `worker`

General-purpose agent for tasks that don't match any specialist. Full capabilities.

| Property | Value |
|----------|-------|
| **File** | `agents/worker.md` |
| **Tools** | `read`, `write`, `edit`, `bash` |
| **Model** | default |
| **Modifies files** | Yes |

**Routing triggers:** Fallback — any task with no matching specialist.

**Key behaviors:**

- Handles any file type and shell commands
- General code writing and refactoring
- File system operations, research, and analysis
- Hands off to a specialist if a better match is identified

**Example delegation:**

```text
subagent(agent="worker", task="Parse the CSV export and generate a summary report")
```

---

## Agent Frontmatter Schema

Every agent file uses YAML frontmatter with the following fields:

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | string | Yes | Unique agent identifier used in routing and delegation |
| `description` | string | Yes | One-line description of the agent's purpose |
| `tools` | string | No | Comma-separated list of tool names (`read`, `write`, `edit`, `bash`) |
| `model` | string | No | LLM model override (omit to use the session default) |

**Example frontmatter:**

```yaml
---
name: python-expert
description: Python code creation, modification, refactoring, and fixes.
tools: read, write, edit, bash
---
```

**Example with model override:**

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

---

## Routing Table

The orchestrator routes tasks to agents based on domain. See [Orchestrator Rules Reference](rules-reference.html) for full rule details.

| 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) | `github-expert` |
| Tests | `test-automator` |
| Debugging | `debugger` |
| API docs | `api-documenter` |
| External repo security audit | `security-auditor` |
| External library/framework docs | `docs-fetcher` |
| No specialist match | `worker` |

> **Tip:** Routing is based on task intent, not tool usage. Running Python tests routes to `python-expert`, not `bash-expert`. Creating a PR routes to `github-expert`, not `git-expert`. See [Understanding Agent Routing and Delegation](agent-routing.html) for examples.

## 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)
- [Orchestrator Rules Reference](rules-reference.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 → data fetch → 3 parallel reviewers → user selection → post 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

**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)
- [Common Workflow Recipes](workflow-recipes.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.6.2
**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 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 unresolved review threads from the current branch's PR.

| Argument | Type | Required | Default | Description |
|---|---|---|---|---|
| `REVIEW_URL` | string | no | `""` | Specific review URL for context (e.g., `#pullrequestreview-XXX`) |

```bash
myk-pi-tools reviews fetch
myk-pi-tools reviews fetch "#pullrequestreview-12345"
```

**Output:** JSON saved to `/tmp/pi-work/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` |

```bash
myk-pi-tools reviews poll
myk-pi-tools reviews poll --source qodo
myk-pi-tools reviews poll "#pullrequestreview-12345" --source coderabbit
```

**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 | Type | Required | Description |
|---|---|---|---|
| `PR_URL` | string | yes | GitHub PR URL (e.g., `https://github.com/owner/repo/pull/123`) |

```bash
myk-pi-tools reviews pending-fetch https://github.com/myk-org/pi-config/pull/42
```

**Output:** JSON saved to `/tmp/pi-work/pr-<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 | Default | Description |
|---|---|---|---|
| `--pr` | integer | auto-detected from current branch | PR number |

```bash
myk-pi-tools reviews status
myk-pi-tools reviews status --pr 42
```

**Output:** TUI table to stdout and an HTML report saved to `/tmp/pi-work/<project>/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` statements are allowed. Other SQL statements are rejected.

```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 "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)
- [Running the Automated Code Review Loop](code-review-loop.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 |

> **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:** `/tmp/pi-data/<project>/`

Project name format: cwd with `/` replaced by `__` (e.g., `home__user__git__my-project`).

| 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` creates and returns the project temp directory.

---

## 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)
- [Working with Project Memory](memory-system.html)
- [Orchestrator Rules Reference](rules-reference.html)
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)

---

Source: rules-reference.md

# Orchestrator Rules Reference

Rules in `rules/` are the orchestrator's behavioral contract. They load automatically in **alphabetical order** (by numeric prefix) at session start and inject into the orchestrator's system prompt via the `before_agent_start` hook. Specialist agents **never** see these rules — they are scoped to the orchestrator only.

> **Note:** Rules take effect on the **next pi session**. Running sessions are not affected by rule file changes. See [Extension Architecture and Lifecycle Hooks](extension-architecture.html) for details on the injection mechanism.

---

## Loading Mechanism

| Property | Value |
|----------|-------|
| Source directory | `rules/` |
| File format | Markdown (`.md`) |
| Load order | Alphabetical (numeric prefix: `00`, `05`, `10`, … `60`) |
| Injection point | `before_agent_start` event (orchestrator only) |
| Skipped for | All specialist subagents (`PI_SUBAGENT_CHILD=1`) |

The extension reads all `.md` files from the `rules/` directory, sorts them, concatenates their contents, and appends the result to the orchestrator's system prompt.

---

## 00 — Orchestrator Core

**File:** `rules/00-orchestrator-core.md`

Defines the orchestrator's fundamental role: it is a **manager** that delegates work to specialist agents and never performs direct edits.

### Forbidden Actions

| Action | Status |
|--------|--------|
| `edit`, `write`, `bash` (except `mcpl`) | ❌ Forbidden |
| Delegating slash commands to agents | ❌ Forbidden |
| `read` (single files) | ✅ Allowed |
| `bash` for `mcpl` only | ✅ Allowed |
| Ask clarifying questions | ✅ Allowed |
| Analyze, plan, route via `subagent` | ✅ Allowed |
| Execute slash commands directly | ✅ Allowed |

### Delegation Targets

| Work type | Delegate to |
|-----------|------------|
| `edit` / `write` | Language specialist via `subagent` |
| Git commands | `git-expert` via `subagent` |
| MCP tools | Manager agents via `subagent` |
| Multi-file exploration | `worker` agent via `subagent` |

### Pre-Implementation Checklist

Before any code change, the orchestrator verifies:

1. Root cause investigated (read relevant code, understand the problem)
2. GitHub issue created (when issue-first workflow applies)
3. On issue branch (`feat/issue-N-...` or `fix/issue-N-...`)

> **Tip:** The checklist is skipped when the issue-first workflow does not apply. See [rule 05](#05--issue-first-workflow) for skip conditions.

---

## 05 — Issue-First Workflow

**File:** `rules/05-issue-first-workflow.md`

Requires creating a GitHub issue and a dedicated branch before code changes. See [Your First Coding Workflow](first-workflow.html) for a guided walkthrough.

### Workflow Steps

1. Analyze the user's request
2. Check skip conditions (see below)
3. Investigate root cause — read source, identify files, verify the problem exists
4. Delegate issue creation to `github-expert`
5. Ask user: "Issue #N created. Do you want to work on it now?"
6. On confirmation, delegate branch creation to `git-expert`
7. Proceed with implementation

### Skip Conditions

| Condition | Effect |
|-----------|--------|
| Trivial fix (typo, single-line change) | Skip entire workflow |
| Question or explanation (no code changes) | Skip |
| Exploration or research | Skip |
| User says "just do it" or "quick fix" | Skip |
| Urgent hotfix with time pressure | Skip |

### Branch Naming

| Type | Pattern | Example |
|------|---------|---------|
| Feature | `feat/issue-N-description` | `feat/issue-70-issue-first-workflow` |
| Bug 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:

- Type (fix/feat/refactor/docs)
- Problem or feature description
- Root cause analysis (for bugs — affected files, functions, why)
- Proposed fix approach
- **`## Done` section with checkboxes** — these define the completion contract

```markdown
## Done

- [ ] Deliverable 1
- [ ] Deliverable 2
- [ ] Deliverable 3
```

### Edge Cases

| Scenario | Behavior |
|----------|----------|
| User says "just fix it" | Skip workflow, do directly |
| Partial requirements provided | 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 |

> **Warning:** Issues are never closed until **all** checkboxes in the `## Done` section are checked. Unchecked deliverables that are no longer needed must be explicitly removed or marked N/A.

---

## 10 — Agent Routing

**File:** `rules/10-agent-routing.md`

Maps task domains to specialist agents. For the full agent list, see [Specialist Agents Reference](agents-reference.html).

### 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 Principle: Intent over Tool

Route based on **what the task is**, not which CLI tool is involved.

| Task | Correct Route | Reason |
|------|--------------|--------|
| Running Python tests | `python-expert` | Intent is testing Python code |
| Editing Python files with sed | `python-expert` | Intent is Python file modification |
| Creating a PR | `github-expert` | Intent is GitHub interaction |
| Committing changes | `git-expert` | Intent is local git operation |
| Shell script creation | `bash-expert` | Intent is shell scripting |

### Documentation Routing

External library/framework documentation (React, FastAPI, Django, Oh My Posh, etc.) **must** go through `docs-fetcher`. The orchestrator is forbidden from calling `fetch_content` on external docs directly.

```text
# Correct
subagent(agent="docs-fetcher", task="Fetch React hooks documentation...")

# Forbidden
fetch_content(https://react.dev/...)
```

`docs-fetcher` tries `llms.txt` first (LLM-optimized format) and extracts only relevant sections.

---

## 15 — MCP Launchpad

**File:** `rules/15-mcp-launchpad.md`

Governs MCP (Model Context Protocol) server interaction via the `mcpl` CLI. See [Customization and Extension Recipes](customization-recipes.html) for MCP server setup.

### Command Reference

| Command | Purpose |
|---------|---------|
| `mcpl search "<query>"` | Search all tools (5 results default) |
| `mcpl search "<query>" --limit N` | Search with custom result count |
| `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 with example call |
| `mcpl call <server> <tool> '{}'` | Execute tool (no arguments) |
| `mcpl call <server> <tool> '{"param": "v"}'` | Execute tool with arguments |
| `mcpl verify` | Test all server connections |

### Workflow

```bash
# 1. Search for the right tool
mcpl search "list projects"

# 2. Get example for complex tools
mcpl inspect sentry search_issues --example

# 3. Call with required params
mcpl call vercel list_projects '{"teamId": "team_xxx"}'
```

### Orchestrator vs Agent Usage

| Role | Allowed |
|------|---------|
| Orchestrator | `mcpl search`, `mcpl list` (discovery only) |
| Specialist agents | Full `mcpl` workflow including `mcpl call` |

### Troubleshooting Commands

| Command | Purpose |
|---------|---------|
| `mcpl verify` | Test all server connections |
| `mcpl session status` | Check daemon and connection status |
| `mcpl session stop` | Restart daemon |
| `mcpl config` | Show current configuration |
| `mcpl call <server> <tool> '{}' --no-daemon` | Bypass daemon for debugging |

---

## 20 — Code Review Loop

**File:** `rules/20-code-review-loop.md`

Mandatory review cycle after every code change. See [Running the Automated Code Review Loop](code-review-loop.html) for usage guidance.

### 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 |

All three run as **async subagents** (`async: true`) in a single assistant turn. They execute in parallel — the orchestrator does not block waiting for results.

### Standard Loop (Manual Reviews)

1. Specialist writes or modifies code
2. All 3 reviewers launch in parallel (`async: true`)
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. Tests pass? → **Done**. Tests fail? → Fix code, then:
   - Minor fix (test/config only) → re-run tests (step 5)
   - Substantive code change → full re-review (step 2)

### Deduplication Criteria

| Condition | Action |
|-----------|--------|
| Same file/line + same issue type | Keep most actionable version |
| Conflicting suggestions | Priority: security > correctness > performance > style |
| Complementary findings (different types, same code) | Keep both |

### Staged Review Mode (Automated Workflows)

Used by automated flows (autorabbit, autoqodo) instead of parallel review:

- **Stage 1 — Spec Compliance:** Does the code meet requirements? All deliverables implemented? No scope creep?
- **Stage 2 — Code Quality:** Quality, security, and guidelines checks (only after Stage 1 passes)

### Baseline Test Comparison

Before declaring test failures as blockers, the rule compares against a clean baseline:

1. Save all changes (staged, unstaged, untracked)
2. Reset to `HEAD`, run tests → baseline failure count
3. Restore changes, run tests → current failure count
4. Only **new failures** (current minus baseline) block the review

> **Note:** Pre-existing failures are noted but do not block. If `git apply` fails, baseline comparison is skipped.

---

## 25 — Documentation Updates

**File:** `rules/25-documentation-updates.md`

Mandatory documentation check after any code addition, change, or removal.

### Update Matrix

| 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 is never skipped.

---

## 30 — Prompt Templates

**File:** `rules/30-prompt-templates.md`

Governs how the orchestrator executes slash commands backed by prompt templates (files in `prompts/`). See [Using Slash Commands and Prompt Templates](slash-commands.html) for the full command reference.

### Execution Rules

| Rule | Description |
|------|-------------|
| Template is authority | Follow the template's instructions exactly |
| Never delegate the command itself | The orchestrator executes the prompt, not an agent |
| Template decides delegation | If the template says "delegate to X", delegate. Otherwise, follow normal rules. |
| Template overrides general rules | Template instructions take priority over general delegation rules when they conflict |

### Correct Execution Pattern

```text
# WRONG — delegating the entire command
/mycommand → subagent(agent="worker", task="/mycommand ...")

# RIGHT — orchestrator runs the command, delegates sub-tasks
/mycommand → orchestrator follows prompt → delegates sub-tasks as instructed
```

---

## 35 — Memory

**File:** `rules/35-memory.md`

Defines the orchestrator's memory usage obligations. See [Working with Project Memory](memory-system.html) for user-facing guidance and [Memory Scoring, Embeddings, and Situation Reports](memory-internals.html) for implementation details.

### Memory Tools

| Tool | Purpose | Mandatory Usage |
|------|---------|----------------|
| `memory_search` | Hybrid keyword + vector search | Before answering questions about prior sessions, preferences, past decisions |
| `memory_reinforce` | Bump evidence count, prevent decay | When a memory is relevant to the current task |
| `memory_add` | Write new memory entry | When learning something worth remembering |
| `memory_remove` | Delete outdated entry | When information is outdated, wrong, or superseded |
| `memory_topics` | List topic files with hotness scores | Inspection and organization |
| `session_search` | Search past conversation summaries | When user references something from a prior session |

### Memory Categories

| Category | Storage File |
|----------|-------------|
| `preference` | `topics/preferences.md` |
| `lesson` | `topics/lessons.md` |
| `pattern` | `topics/patterns.md` |
| `decision` | `topics/decisions.md` |
| `done` | `topics/completions.md` |
| `mistake` | `topics/mistakes.md` |

### Auto-Injection Pipeline

Three mechanisms inject memories automatically — no tool calls needed:

1. **Situation Report** — token-budgeted summary of scored memories (always present)
2. **Contextual Memory Recall** — vector similarity search (threshold > 0.65) against the current message
3. **Session History Recall** — keyword search against past conversation summaries

> **Note:** Trivial messages ("ok", "thanks", "yes", messages < 6 chars) skip vector and session search.

### Entry Quality Rules

| Requirement | Example |
|-------------|---------|
| One line only (~100 chars max) | `"buildah chown -R breaks cache mounts — use --mount=type=cache with correct uid"` |
| Specific and actionable | `"Attach child processes to pi (no detached:true) — kills on exit"` |
| No fluff, no context, no explanation | ❌ `"We had issues with buildah and Docker caching and tried several approaches"` |

### Per-Turn Self-Improvement Triggers

| Event | Action |
|-------|--------|
| User corrected you | `memory_add(category: "lesson")` |
| Something failed | `memory_add(category: "mistake")` |
| User said "don't do X" / "always do Y" | `memory_add(category: "preference")` |
| PR merged | `memory_add(category: "done")` |
| Non-obvious pattern discovered | `memory_add(category: "pattern")` |
| Technical decision made | `memory_add(category: "decision")` |

### Capacity Signal

The situation report header shows usage:

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

- **Below 80%** — add freely
- **Above 80%** — consolidate first (merge related, remove outdated)

### Dreaming (Background Consolidation)

| Property | Value |
|----------|-------|
| Trigger | `/dream` command or session shutdown |
| Execution | Async + fireAndForget (never blocks session) |
| Actions | Extract memories, deduplicate, reorganize, remove stale |
| Restriction | Never removes or modifies **pinned** entries |

### Skill Creation

Multi-step workflows (3+ steps, trial-and-error, non-obvious commands) are saved as reusable skills via `/create-skill <name>`. Skills are stored at `~/.agents/skills/<name>/SKILL.md`.

---

## 40 — Critical Rules

**File:** `rules/40-critical-rules.md`

Mandatory behavioral constraints enforced across all orchestrator actions. Several of these rules are backed by code-level enforcement in `extensions/orchestrator/enforcement.ts`.

### Questions Are Not Instructions

When the user asks a question (contains `?`):

| Allowed | Forbidden |
|---------|-----------|
| Answer the question | Modify, create, or delete files |
| Use read-only commands (`read`, `grep`, `ls`, `cat`) | Run state-changing commands (`git commit`, `rm`, `write`) |
| Search memory (`memory_search`) | Create branches, PRs, issues |
| Ask for confirmation before acting | "Fix" something noticed while answering |

### Task Focus

During multi-step workflows:

- Side questions do **not** end the workflow — answer, then resume
- The workflow completes only when all steps are done (e.g., PR created, issue closed)

### Parallel Execution

| Requirement | Detail |
|-------------|--------|
| Default mode | Maximize parallelism — all independent operations in one message |
| Sequential only when | There is a proven dependency between operations |
| Async required when | Task is independent AND does not need immediate result |
| Kill unused agents | Immediately kill async agents whose results are no longer needed |

### Sync Agent Time Estimates

| Mode | `estimatedSeconds` Requirement | 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 | N/A |

> **Note:** Calls ≥ 30s without `async: true` are rejected by the tool.

### Subagent `cwd`

**Always** pass `cwd` when delegating to subagents — in all modes (single, parallel, chain, async). Omitting `cwd` causes enforcement checks to run against the wrong repository.

### Multi-PR / Multi-Branch Work

When working on multiple PRs or branches simultaneously, **always** use `git worktree`:

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

> **Warning:** Branch switching in the main worktree corrupts parallel agent work. The `use_worktrees` project setting enforces this by blocking `git checkout` and `git switch`. See [Configuration and Environment Variables Reference](configuration-reference.html).

### User Interaction

**Always** use the `ask_user` tool for approvals, selections, and confirmations. Never ask questions via plain text in the response.

### Technical Honesty

When the user proposes an approach:

1. Evaluate critically
2. Present alternatives with tradeoffs (if they exist)
3. Let the user decide

### Web Access

| Use case | Tool |
|----------|------|
| Research and search queries | `web_search` |
| Extracting content from URLs, YouTube, GitHub repos | `fetch_content` |
| Interactive pages (clicks, forms, screenshots) | `agent-browser` CLI |
| ❌ Never use | `curl` for reading web pages, SearXNG MCP |

### External Code Security Audit

Before adopting external code from untrusted sources, delegate to `security-auditor`:

| Source | Audit approach |
|--------|---------------|
| Git repos | Clone to `/tmp/pi-work/`, run `security-auditor` |
| Pi skills | Clone/download source, run `security-auditor` |
| PyPI packages | Clone source repo, check install hooks, scan code |
| npm packages | Download source, check `postinstall`, scan code |
| MCP servers | Audit server source before adding config |
| Docker images | Inspect Dockerfile, check base image provenance |
| Remote scripts (`curl \| bash`) | **Always block** — download first, audit, then run |

**Skip when:** User says "skip audit", source previously approved, or well-known package (e.g., `requests`, `react`).

### Temp Files

All temp files go to `/tmp/pi-work/<cwd-basename>/`. Never create temp files in the project directory.

### Python Execution

```bash
# Correct
uv run --with requests script.py
uv run --with requests --with pandas script.py

# Forbidden
uv run pip install requests
python3 script.py
pip install requests
```

### External Git Repository Exploration

Clone to `/tmp/pi-work/` with `--depth 1` for shallow clone. Never use `fetch_content` to browse repository files.

```bash
git clone --depth 1 https://github.com/org/repo.git /tmp/pi-work/repo
```

### Code-Level Enforcement

The `enforcement.ts` module backs several critical rules with `tool_call` event blocks:

| Enforced Rule | Block Condition |
|---------------|-----------------|
| Python/pip restriction | Direct `python3` / `pip` outside `uv` |
| Pre-commit restriction | Direct `pre-commit` (must use `prek`) |
| Git commit/push | Outside `git-expert` agent |
| Protected branch commits | Commit to `main` or other protected branches |
| Protected branch pushes | Push to protected branches |
| `git add .` / `git add -A` | Blanket staging forbidden — stage specific files |
| Staging gitignored files | `git check-ignore` blocks ignored files |
| Git hooks bypass | `--no-verify` and `core.hooksPath=/dev/null` forbidden |
| Merged branch commits | Commit to branches with merged PRs |
| Remote script execution | `curl \| bash`, `wget \| sh`, process substitution patterns |
| Repeat command spam | Same command ≥ 3 times in a row |
| Sleep in loops | `sleep > 5s` inside loops |
| Standalone sleep | `sleep > 30s` outside loops |
| `mktemp` location | Must use `/tmp/pi-work/` prefix |
| Docker/podman in container | Must use `docker-safe` wrapper |
| Memory writes by specialists | Only orchestrator can write memories |
| Worktree enforcement | `git checkout`/`switch` blocked when `use_worktrees` is enabled |
| Dangerous commands | User confirmation required (via `ctx.ui.select`) |

---

## 45 — File Preview

**File:** `rules/45-file-preview.md`

Serves generated HTML or browser-viewable files via a local HTTP server for user preview.

### Server Launch Sequence

```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 \
  > /tmp/pi-work/$(basename $PWD)/httpd-$PORT.log 2>&1 &
disown
sleep 0.5
if ! kill -0 $! 2>/dev/null; then
  echo "Server failed to start:"
  cat /tmp/pi-work/$(basename $PWD)/httpd-$PORT.log
fi
```

| Parameter | Description |
|-----------|-------------|
| `--find-port` | Returns a free port number |
| `--port PORT` | Port to listen on |
| `--dir PATH` | Directory to serve files from |

After launch, the orchestrator tells the user:

> File is being served at `http://localhost:<port>/<filename>` — open this URL in your browser.


> **Note:** `nohup` + `disown` are required because `uv run` creates a parent process chain. Without them, bash cleanup kills the `uv` parent and terminates the server.

---

## 50 — Agent Bug Reporting

**File:** `rules/50-agent-bug-reporting.md`

Defines the process when the orchestrator discovers a logic flaw in an agent's configuration (files in `agents/`).

### Covered Agents

All 24 agents defined in the `agents/` directory:

`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.

### Trigger Conditions

| Trigger | Not a Trigger |
|---------|--------------|
| Flawed logic in agent instructions | Runtime errors (network, missing files) |
| Agent producing incorrect results from its config | External tool failures |
| Agent behavior contradicts its purpose | User code bugs |
| Instructions causing systematic errors | Expected behavior user disagrees with |

### Workflow

1. Orchestrator discovers agent logic bug
2. **Ask user:** "I found a logic bug in [agent]. Do you want me to create a GitHub issue?"
3. If yes → delegate to `github-expert` to create issue in `myk-org/pi-config`
4. Continue with original task

### Issue Format

- **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 to other pi sessions. See [Communicating Between Pi Sessions](inter-agent-communication.html) for setup and usage.

### 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.

### 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 Messages (Replying)

Inbound messages appear as `[from <peer> @ <cwd>] <message>`. The orchestrator's assistant text **is** the reply — it is captured automatically by the `agent_end` hook.

```text
# WRONG — creates a new conversation instead of replying
Receive inbound → coms_send(peer="pi-2", msg="reply text")

# RIGHT — assistant text is the reply
Receive inbound → write answer as normal assistant text
```

### Outbound Messages (Initiating)

```text
1. coms_list                          # Find peers
2. coms_send(peer="pi-2", msg="...")  # Send question
3. coms_await                         # Wait for response (ESC to cancel)
```

### Key Rules

- `coms_await` / `coms_net_await` are interruptible (user can press ESC)
- Never use send tools to reply to inbound messages
- Always check peers (`list`) before sending
- When system is unspecified, try both `coms_` and `coms_net_`

---

## 60 — Task Tracking

**File:** `rules/60-task-tracking.md`

Mandatory task tracking for multi-step workflows (3+ steps). See [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) for related async agent management.

### When to Create Tasks

| Use tasks for | Skip tasks for |
|---------------|---------------|
| Feature implementation | Single-step actions |
| Bug fixes with multiple files | Questions or explanations |
| Issue-first or code-review workflows | `/btw` side questions |
| Multi-file refactoring | Trivial fixes (typos) |

### Task Granularity

```text
# BAD — too vague
- Implement the fix
- Review code
- Create PR

# GOOD — specific and actionable
- 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
```

### Task Lifecycle

1. **Create** all tasks via `TaskCreate` before starting work
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)

### Side Question Handling

When the user asks a side question while tasks are active:

1. Answer the question
2. Resume the next unchecked task immediately

### Enforcement

The extension injects reminders if tasks are ignored for **4+ turns**. Obsolete tasks are removed via `TaskUpdate` with `status: "deleted"`.

### Integration

Task tracking works alongside other workflow rules:

| Rule | Integration |
|------|-------------|
| 05 — Issue-first workflow | Create tasks for the full issue workflow |
| 20 — Code review loop | Include review steps as individual tasks |
| 25 — Documentation updates | Include doc updates as tasks when applicable |

## Related Pages

- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Specialist Agents Reference](agents-reference.html)
- [Running the Automated Code Review Loop](code-review-loop.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

**`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
- [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)
- [Configuration and Environment Variables Reference](configuration-reference.html)
- [Command Safety Guards and Enforcement](command-enforcement.html)
- [Specialist Agents Reference](agents-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. The entry is written to the appropriate topic file under `.pi/memory/topics/`
3. A stability score is computed and stored in `memory-scores.json`
4. 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. **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
3. **Search:** The query is embedded, then cosine similarity is computed against all stored vectors
4. **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.

### Graceful Fallback

If the `@huggingface/transformers` package is unavailable or the model fails to load, the system falls back to **keyword-only search**. 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)
- [Using Slash Commands and Prompt Templates](slash-commands.html)
- [Slash Commands and Extension Commands Reference](commands-reference.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 `/tmp/pi-work/<project>/`, 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 `/tmp/pi-work/<project-name>/` 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)
- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Slash Commands and Extension Commands Reference](commands-reference.html)
- [Installing and Starting Your First Session](quickstart.html)

---

Source: command-enforcement.md

# Command Safety Guards and Enforcement

Pi's enforcement system intercepts every `bash` tool call before execution, applying a layered set of safety guards that protect your environment from accidental damage, security risks, and workflow anti-patterns. Whether you're running pi in a container or natively, these guards prevent common mistakes — staging the wrong files, committing to protected branches, executing remote scripts, or running destructive commands without confirmation.

Understanding these guardrails helps you work *with* the system rather than against it. When a command is blocked, pi tells you exactly why and what to do instead.

## How Enforcement Works

The enforcement system is registered as a `tool_call` event handler in the orchestrator extension. Every time pi (or a specialist agent) attempts to run a bash command, the handler inspects the command string and either:

- **Allows** it — execution proceeds normally
- **Blocks** it — returns an error message explaining why and what to do instead
- **Prompts for confirmation** — asks the user before proceeding (dangerous commands only)

| Step | What Happens | Example |
|------|-------------|---------|
| 1. Command intercepted | `tool_call` event fires for every `bash` invocation | `git add .` |
| 2. Guards evaluated | Each guard checks the command in order | "Does this match `git add .`?" → Yes |
| 3. Decision returned | Block with reason, prompt user, or allow | `⛔ 'git add .' forbidden. Stage specific files.` |
| 4. Agent sees result | The blocked command's reason appears as the tool result | Agent retries with `git add src/file.ts` |

> **Note:** Enforcement applies to **all** agents — both the orchestrator and specialist subagents. Some guards are scoped to specific contexts (container-only, orchestrator-only, specialist-only).

## Blocked Commands

### Python and pip (Direct Execution)

Pi requires all Python execution to go through `uv`, which provides isolated, reproducible environments.

| Blocked | Use Instead |
|---------|-------------|
| `python script.py` | `uv run script.py` |
| `python3 -c "..."` | `uv run python3 -c "..."` |
| `pip install requests` | `uv add requests` |
| `pip3 install -r requirements.txt` | `uv sync` |
| `pre-commit run --all-files` | `prek run --all-files` |

Commands that already start with `uv` or `uvx` are allowed through. The check also catches piped variants like `something | python3`.

### Remote Script Execution

Pi blocks all patterns that pipe downloaded content directly into a shell or interpreter. This prevents supply-chain attacks from untrusted sources.

**Blocked patterns:**

- **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:** `eval $(curl https://example.com/script.sh)`
- **Backtick substitution:** `` `curl https://example.com/script.sh` ``

**What to do instead:** Download the script first, audit it with the `security-auditor` agent, then run it if safe:

```bash
curl -o /tmp/pi-work/myproject/install.sh https://example.com/install.sh
# Security audit happens here
bash /tmp/pi-work/myproject/install.sh
```

> **Tip:** Content inside heredocs (`<< 'EOF' ... EOF`) is stripped before the remote execution check. So documentation examples containing `curl | bash` won't trigger false positives.

### Sleep and Polling Loops

Pi blocks patterns that would tie up the session for extended periods:

| Blocked Pattern | Threshold | Alternative |
|----------------|-----------|-------------|
| `sleep N` (standalone) | N > 30 seconds | Use a subagent with `async: true` |
| `while ... sleep N ... done` | N > 5 seconds | Use a subagent with `async: true` |

These guards prevent the LLM from implementing naive polling loops that block the entire session. Long-running monitoring belongs in async background agents.

### Temp File Location

All temp files must use the `/tmp/pi-work/<project>/` prefix (where `<project>` is the basename of the current working directory). Bare `mktemp` calls without this prefix are blocked:

| Blocked | Use Instead |
|---------|-------------|
| `mktemp /tmp/XXXXXX` | `mktemp /tmp/pi-work/$(basename $PWD)/XXXXXX` |

This ensures temp files are organized by project and persist correctly across container restarts when `/tmp/pi-work` is mounted from the host.

## Git Branch Protection

Pi enforces a branching workflow that prevents accidental commits to protected branches. Protection checks run against the **effective working directory** — if a command starts with `cd /path && git ...` or uses `git -C /path`, the guard resolves the correct repo.

### Protected Branch Detection

Pi determines protected branches in this order:

1. **GitHub API** — queries `gh api repos/{owner}/{repo}/branches` for branches with `protected: true`
2. **Fallback** — always includes `main` and `master` regardless of API results
3. **Cache** — results are cached per repository for the session lifetime (one API call per repo)

### What's Protected

| Action | Guard | Error Message |
|--------|-------|---------------|
| Commit on protected branch | Blocked | `⛔ Cannot commit to 'main' (protected). Create a feature branch.` |
| Push to protected branch | Blocked | `⛔ Cannot push to 'main' (protected). Create a feature branch.` |
| Push explicitly naming a protected branch | Blocked | `⛔ Cannot push to 'main' (protected). Create a feature branch.` |
| Commit in detached HEAD | Blocked | `⛔ Detached HEAD. Create a branch first: git checkout -b my-branch` |
| Commit on already-merged branch | Blocked | `⛔ Branch 'my-feature' already merged into 'main'. Create a new branch.` |
| Commit on branch with merged PR | Blocked | `⛔ PR #42 for 'my-feature' already merged. Create a new branch from main.` |
| Push on already-merged branch | Blocked | `⛔ Branch 'my-feature' already merged into 'main'. Create a new branch.` |

> **Note:** When you combine `git checkout` and `git commit` in a single bash call (e.g., `git checkout -b feature && git commit -m "init"`), the branch check runs *before* execution. Split them into separate bash calls so the checkout happens first.

### Git Staging Guards

| Action | Guard | Error Message |
|--------|-------|---------------|
| `git add .` or `git add -A` or `git add --all` | Blocked | `⛔ 'git add .' / 'git add -A' forbidden. Stage specific files.` |
| `git add <gitignored-file>` | Blocked | `⛔ '<file>' is in .gitignore. Do not stage ignored files.` |

Staging guards force explicit, intentional file selection. This prevents accidentally committing build artifacts, secrets, or other ignored files.

### Git Hook Bypass Prevention

| Action | Guard |
|--------|-------|
| `git commit --no-verify` | Blocked — pre-commit hooks must run |
| `core.hooksPath=/dev/null` | Blocked — hook bypass is forbidden |

### Agent-Restricted Git Operations

Git `commit` and `push` commands are only allowed from the `git-expert` agent. If any other agent attempts these operations, the command is blocked with a message to delegate to `git-expert`.

## Worktree Enforcement

When the `use_worktrees` project setting is enabled (via `.pi/pi-config-settings.json` or `PI_USE_WORKTREES` env var), pi blocks branch switching entirely:

| Blocked Command | What to Do Instead |
|----------------|-------------------|
| `git checkout <branch>` | `git worktree add .worktrees/<name> -b <branch> main` |
| `git switch <branch>` | `git worktree add .worktrees/<name> -b <branch> main` |

> **Note:** `git checkout -- <file>` (restoring file contents, note the `--`) is still allowed — only branch-switching checkouts are blocked.

This setting is essential for multi-PR workflows where parallel agents work in the same repository. See [Configuration and Environment Variables Reference](configuration-reference.html) for how to enable it.

## Dangerous Command Confirmation

Some commands are too risky to block outright but require explicit user approval. When pi detects a dangerous command, it presents a confirmation prompt:

```
⚠️ Dangerous command:

  rm -rf /tmp/pi-work/old-project

Allow? [Yes / No]
```

**Commands that trigger confirmation:**

| Pattern | Examples |
|---------|---------|
| `rm -rf` or `rm -r` | `rm -rf build/`, `rm -r node_modules/` |
| `sudo` | `sudo apt install ...` |
| `chmod 777` or `chown 777` | `chmod 777 script.sh` |
| `mkfs` | `mkfs.ext4 /dev/sda1` |
| `dd ... of=/dev/` | `dd if=/dev/zero of=/dev/sda` |

> **Warning:** If pi is running without a UI (e.g., in `json` or `print` mode), dangerous commands are **blocked entirely** rather than prompted — there's no way to ask for confirmation.

## Repeat Command Detection

The orchestrator tracks consecutive identical bash commands to prevent polling-by-spam — where the LLM runs the same command over and over hoping for a different result.

**How it works:**

1. Each command is normalized (leading `cd ... &&` prefixes stripped, whitespace collapsed)
2. The normalized command is compared against the last command via a per-process temp file
3. On the 3rd consecutive identical execution, the command is blocked

**Block message:** `⛔ Same command executed 3 times in a row. Use a subagent with async: true for polling/monitoring instead of repeating the command.`

> **Note:** Repeat detection only applies to the **orchestrator**. Specialist subagents (which set `PI_SUBAGENT_CHILD=1`) are exempt, since they may legitimately retry commands.

## Docker-Safe Wrapper (Container Only)

When pi runs inside a Docker or Podman container, direct `docker` and `podman` CLI commands are blocked. Instead, pi provides the `docker-safe` wrapper script that only allows **read-only inspection commands**.

**Allowed commands through `docker-safe`:**

| Command | Purpose |
|---------|---------|
| `docker-safe ps` | List containers |
| `docker-safe logs` | View container logs |
| `docker-safe inspect` | Inspect container or image metadata |
| `docker-safe top` | Display running processes in a container |
| `docker-safe stats` | Show resource usage statistics |
| `docker-safe port` | List port mappings |
| `docker-safe diff` | Show filesystem changes in a container |
| `docker-safe images` | List images |
| `docker-safe version` | Show Docker/Podman version |
| `docker-safe info` | Show system-wide information |

**Everything else** (`exec`, `run`, `rm`, `cp`, `build`, etc.) is blocked.

To use Podman instead of Docker, pass `--runtime podman` or set `DOCKER_SAFE_RUNTIME=podman`.

> **Tip:** Container detection uses filesystem checks (`/.dockerenv`, `/run/.containerenv`) and cgroup inspection. This guard only activates when pi detects it's running inside a container.

## Memory Write Restrictions for Subagents

Specialist agents cannot modify pi's memory system. Any `myk-pi-tools memory add` or `myk-pi-tools memory delete` command from a subagent is blocked:

```
Memory writes are restricted to the orchestrator. Specialists can only search/list memories.
```

This ensures memory consistency — only the orchestrator (which has full context of the conversation) can add or remove memories. Specialist agents can still **search** memories via `memory_search`. See [Working with Project Memory](memory-system.html) for how the memory system works.

## Async-Only Agents

Some agents are enforced to always run asynchronously. If the LLM attempts to call them synchronously, the system auto-promotes them to `async: true`. If they appear in a chain, the call is rejected entirely (chains are inherently synchronous).

**Currently enforced async-only agents:**

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

This prevents code reviews from blocking the session — they can take minutes to complete and the user should be able to continue working.

> **Note:** The `ASYNC_ONLY_AGENTS` set is defined in `extensions/orchestrator/subagent-tool.ts`. Changes to this list should be kept in sync with `rules/20-code-review-loop.md`.

## Timeout Stripping

For known long-running commands (specifically `myk-pi-tools reviews poll`), pi silently removes any `timeout` parameter the LLM sets. These poll commands can run for 30+ minutes waiting for rate limits to clear. Rather than blocking the command (which causes retry loops), the timeout is simply deleted so the command runs to completion.

## Co-Author Trailer Injection

While not a safety guard per se, the enforcement handler also manages automatic co-author trailer injection. When the `co_author` setting is enabled and a `git commit` command doesn't already include a `Co-authored-by:` trailer, enforcement automatically appends one with the current model ID. This works for both `-m "message"` style commits and `echo "message" | git commit -F -` piped commits.

## What to Do When a Command Is Blocked

Every block message includes three things:

1. **What was blocked** — the exact command or pattern that triggered the guard
2. **Why it was blocked** — the safety reason
3. **What to do instead** — the correct alternative command or approach

The agent (or orchestrator) automatically retries using the suggested alternative in most cases. If you see repeated blocks, check that:

- You're on a feature branch, not `main` or `master`
- You're staging specific files, not using `git add .`
- Your worktree setting matches your workflow (see [Configuration and Environment Variables Reference](configuration-reference.html))
- Long-running tasks are dispatched as async agents

## Extending the Enforcement System

The enforcement handler is a single `tool_call` event listener registered in `extensions/orchestrator/enforcement.ts`. To add a new guard:

1. **Add your check** inside the `pi.on("tool_call", ...)` callback, after the existing guards
2. **Return a block object** with `{ block: true, reason: "..." }` to prevent execution
3. **Return `undefined`** to allow the command through
4. **For confirmation prompts**, use `ctx.ui.select()` — check `ctx.hasUI` first to handle headless mode

The handler receives the full `event.input.command` string and the `ctx` object with `cwd`, `hasUI`, `ui`, and `model` properties. You can also **modify** the command in-place by reassigning `event.input.command` (as co-author trailer injection does).

**Hook signature:**

```typescript
pi.on("tool_call", async (event, ctx) => {
  if (!isToolCallEventType("bash", event)) return undefined;
  const command = event.input.command;

  // Your guard logic here
  if (shouldBlock(command)) {
    return { block: true, reason: "Explanation and alternative" };
  }

  return undefined; // Allow
});
```

Git helper functions (`getCurrentBranch`, `getMainBranch`, `getProtectedBranches`, `hasGitSub`, `isBranchMerged`, etc.) are exported from `extensions/orchestrator/git-helpers.ts` for use in enforcement checks. The `DANGEROUS` regex array is also exported from there.

## Related Pages

- [Extension Architecture and Lifecycle Hooks](extension-architecture.html) — how `tool_call` event handlers fit into pi's extension lifecycle
- [Running the Automated Code Review Loop](code-review-loop.html) — async-only enforcement for review agents in practice
- [Running Background Agents and Scheduled Tasks](async-agents-and-cron.html) — using async agents instead of blocked polling loops
- [Configuration and Environment Variables Reference](configuration-reference.html) — `use_worktrees`, `co_author`, and other settings that affect enforcement
- [Running Pi in a Docker Container](docker-deployment.html) — container setup and the `docker-safe` wrapper
- [Working with Project Memory](memory-system.html) — memory write restrictions and the orchestrator-only policy
- [Orchestrator Rules Reference](rules-reference.html) — the rule files that complement enforcement with behavioral guidance

## Related Pages

- [Extension Architecture and Lifecycle Hooks](extension-architecture.html)
- [Orchestrator Rules Reference](rules-reference.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)

---
