Files
obsidian-vault/300 areas/350 AI/Pi Agent Extensions & Skills.md

900 lines
45 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
created: 2026-05-16
modified: 2026-08-03
type: note
tags:
- ai
- dev-ops
aliases: []
---
# Pi Agent Extensions & Skills
## Source Repositories
| Source | Location |
|---|---|
| Gitea (package) | `git:https://gitea.lab.audasmedia.com.au/sam/pi-config` |
| Local filesystem | `~/.agents/` |
| Project settings | `sys_config/.pi/settings.json`, `ai_setup/.pi/settings.json` |
---
## OmniRoute — LLM Provider Router
OmniRoute is the central LLM routing proxy running on .13 (port 20128/20129). All three machines route pi's LLM requests through it.
| Aspect | Detail |
|--------|--------|
| **What it is** | Docker-based LLM proxy with **combo routing** — you define a prioritized list of providers and it tries them in order until one succeeds |
| **Where** | `.13:20129` via Docker, exposed through Caddy on .35 for remote access |
| **Provider registered in pi as** | `omni` (not `omniroute`) — the `omniroute-pi-ext-integration` npm package registers the `omni` provider |
| **Pi default model** | `default-opencode-go-ds-flash` — a combo on OmniRoute that prioritises OpenCode-Go's DeepSeek V4 Flash ($5/month sub) before falling back to other providers |
| **Combo chain** | User-created combo `default-opencode-go-ds-flash` tries providers in order: OpenCode-Go → OpenRouter → DeepSeek direct → Google Gemini |
| **Sub-agent routing** | Sub-agents route through the same combo — individual model IDs like `opencode-go/deepseek-v4-flash` match the combo and fall through the same priority chain |
| **Models** | 484 models available via OmniRoute (synced with `/omni sync`), available in pi's Ctrl+P model picker |
| **How pi connects** | The `omniroute-pi-ext-integration` extension registers all models + the `omni` provider. URL + API key set once via `/omni setup`. Re-sync via `/omni sync`. |
### Files & Commands
| Item | Location / Command |
|------|-------------------|
| Docker compose | `/home/sam/Docker/Containers/omniroute/docker-compose.yml` on .13 |
| pi extension | `omniroute-pi-ext-integration` (npm package, installed via `pi install npm:omniroute-pi-ext-integration`) |
| Extension config | `~/.pi/agent/models.json` — stores URL + API key for `omni` provider, plus model list |
| Setup | `/omni setup` (one-time: URL + API key) |
| Sync | `/omni sync` (re-fetch model list) |
| Access (local) | `http://192.168.20.13:20129/v1` |
| Access (via Caddy) | `https://omniroute.lab.audasmedia.com.au/v1` |
| API key | `sk-fff5c0d55c0bc0bf-b58ed0-76da5716` (stored in `~/.config/environment.d/10-secrets.conf` on .27/.51; on .13 in `~/.pi/agent/settings.json` — `chmod 600`, outside any git repo). ⚠️ This key is also written in this doc — rotate/move to a vault secret if this file ever syncs outside the vault |
---
## Open WebUI — Chat Frontend
Open WebUI v0.11.0 runs on .13 as a native NixOS process (not Docker), managed via Home Manager. Provides a chat UI that can connect to any OpenAI-compatible API — including OmniRoute.
| Aspect | Detail |
|--------|--------|
| **URL** | `http://192.168.20.13:3000` |
| **Package** | `open-webui-0.11.0` (NixOS nixpkgs) |
| **How to connect OmniRoute** | Admin Panel ⚙️ → Settings → Connections → OpenAI API → URL: `http://192.168.20.13:20129/v1` (include `/v1`), Key: OmniRoute API key |
| **Also works with** | Any OpenAI-compatible API (TokenRouter, OpenRouter, DeepSeek) — add each as a separate connection |
| **Port note** | :3000 is taken by Open WebUI. Langfuse was bumped to :3001. |
---
## Ollama — Local LLM Inference (REMOVED)
~~Runs on .13 with `qwen2.5-coder:7b` (Q4_K_M, 7.6B params).~~ **Removed August 2026.** Redundant — OmniRoute provides 485 models including superior `qwen/qwen3.5-9b`. The 4.7GB disk + RAM cost on a 15.5GB server wasn't justified.
### Pi default model selection model
Machines route through `omni` provider with `defaultModel: "default-opencode-go-ds-flash"`:
```
pi → omni provider → POST /v1/chat/completions { model: "default-opencode-go-ds-flash" }
→ OmniRoute matches combo "default-opencode-go-ds-flash"
→ Tries: OpenCode-Go → OpenRouter → DeepSeek direct → Google Gemini
→ Returns first successful response
```
### Per-machine setup state
pi is **Nix-managed on all three** — the nixpkgs **`pi-coding-agent`** package (v0.82.1) in `home.packages` (npx wrapper removed 2026-08-05). Version uniform on all machines (matches all three flake locks). Updates = nixpkgs flake bump + rebuild. Global settings also include **pi-tool-display** (see below).
| Machine | pi package | pi version | Provider config | `/omni setup` done | Models synced |
|---------|-----------|-----------|-----------------|-------------------|--------------|
| .27 | `pi-coding-agent` (home.nix) | 0.82.1 | ✅ `omni` | ✅ | ✅ |
| .13 | `pi-coding-agent` (home.nix) | 0.82.1 | ✅ `omni` | ✅ | ✅ |
| .51 | `pi-coding-agent` (home.nix) | 0.82.1 | ✅ `omni` | ✅ | ✅ |
---
## Extensions
| Extension | Source | Purpose |
|---|---|---|
| **pi-config** | `~/.agents` | `/config-add`, `/config-remove`, `/config-show`, `/config-setup` — manage which extensions/skills are active in a project |
| **tavily-search** | Gitea | `tavily_search` — web search via Tavily API (AI-optimized) |
| **web-fetch** | `~/.agents` | `web_fetch` — fetch any URL and return clean markdown (HTML, PDF, JS-rendered with Jina fallback) |
| **ask-user-question** | `~/.agents` | `ask_user_question` — LLM presents structured multiple-choice / text questions with keyboard UI |
| **video-extract** | `~/.agents` | `video_extract` — extract frames from YouTube/local video + full Gemini analysis (requires ffmpeg + yt-dlp + GEMINI_API_KEY) |
| **filechanges** | `~/.agents` | `/filechanges`, `/filechanges-accept`, `/filechanges-decline` — tracks every file LLM edits/writes, diff review, revert |
| **pi-prompt-template-model** | npm (global) | Model-switching prompt templates with frontmatter. See [[#Prompt Templates]] section below |
| **pi-mcp-adapter** | npm (global) | Single proxy tool (~200 tokens) replaces hundreds of MCP tool definitions. `/mcp` command for management. Lazy server connections |
| **pi-graphify** | `~/.agents` | Knowledge graph tools: build, query, path tracing, explain, watch, add, update |
| **plannotator** | `~/.agents` | Interactive plan review with browser UI, annotations, code review |
| **caveman** | `~/.agents` | Ultra-compressed communication mode |
| **markitdown** | `~/.agents` | Convert files (PDF, Word, Excel, PPTX, images, HTML, etc.) to Markdown. Image analysis via Qwen 2.5 VL 72B on OpenRouter. |
| **@tintinweb/pi-subagents** | npm (global) | 18 custom agent types, background agents, mid-run steering, session resume, worktree isolation, scheduling, cross-extension RPC. See [[Pi Subagent]] for full documentation |
| **@tintinweb/pi-tasks** | npm (global) | Task management with dependency tracking, auto-cascade, background process tracking, TaskExecute spawns subagents via RPC |
| **gentle-engram** | `~/.agents` | Memory service connecting to engram via ENGRAM_URL. Replaces memory-vault. Session capture, compaction recovery |
| **headroom-bridge** | `~/.agents` | `compress_for_agent` tool — compresses >20K chars via Headroom Docker on .13:8787. 60-95% token reduction |
| **pi-langfuse** | `~/.agents` (vendored from npm 1.5.8, commit `bc91a15`) | Langfuse LLM observability for pi — one trace per conversation, grouped by pi session, with tokens + cost. Activate per project via `/config-add ext pi-langfuse`. See [[#pi-langfuse — LLM Observability for Pi]] |
| **pi-tool-display** | `~/.agents` (vendored npm 0.5.0, commit `41cc33d`) | OpenCode-style compact tool rendering, adaptive edit/write diffs, pending-edit previews, thinking labels. **Global** — 0 tools / 0 token cost (added via home.nix settings). `/tool-display` presets: opencode / balanced / verbose |
| **pi-lsp-extension** | `~/.agents` (vendored npm 1.3.0, commit `41cc33d`) | LSP diagnostics, hover, definition, references, symbols, rename, completions, code_actions + tree-sitter `code_overview`/`ast_search`/`code_rewrite`. **Per-project** via `/config-add ext pi-lsp-extension` (10 tools — token-lean). Commands: `/lsp`, `/lsp-config`, `/lsp-restart`, `/lsp-lombok` |
### pi-tool-display
OpenCode-style tool rendering for pi (vendored from npm `pi-tool-display@0.5.0`, by MasuRii, commit `41cc33d`).
| Aspect | Detail |
|---|---|
| **What it does** | Compact built-in tool rendering (read/grep/find/ls/bash/edit/write), adaptive split/unified edit diffs, workspace-scoped pending edit/write previews while streaming, thinking labels, optional native user message box |
| **Placement** | **Global** — registers 0 tools (pure TUI renderer), so no token cost. Added to the Gitea package `extensions` list in home.nix global settings (`extensions/pi-tool-display/index.ts`) on all three machines |
| **Presets** | `/tool-display` → opencode / balanced / verbose |
| **Token note** | Compacts/truncates tool output = saves context. Does NOT remove blocks from the transcript (that's `pi-foldable-tools`, deliberately skipped — overlapping renderer, no persistent token gain) |
| **Compat** | peer range `^0.74–0.80` — verified working on pi 0.82.1 |
### pi-lsp-extension
LSP integration for pi (vendored from npm `pi-lsp-extension@1.3.0`, by samfoy, commit `41cc33d`).
| Aspect | Detail |
|---|---|
| **Tools (11)** | `lsp_diagnostics`, `lsp_hover`, `lsp_definition`, `lsp_references`, `lsp_symbols`, `lsp_rename`, `lsp_completions`, `lsp_code_actions`, `code_overview`, `ast_search`, `code_rewrite` |
| **Commands** | `/lsp` (server status), `/lsp-config <lang> <cmd> [args]`, `/lsp-restart <lang>`, `/lsp-lombok` |
| **Placement** | **Per-project** via `/config-add ext pi-lsp-extension` (10+ tool defs — token-lean). Same on all machines |
| **Language servers** | Installed via home.nix: `vtsls` (TS/JS/React — use `/lsp-config typescript vtsls stdio`), `pyright` (Python), `gopls` (Go), `clang-tools` (C/C++/Arduino), `yaml-language-server`, `bash-language-server`, `vscode-langservers-extracted` (JSON/HTML/CSS), `lua-language-server`, `emmet-ls`, `intelephense` (PHP — paid; free alt `phpactor`), `nixd` (Nix), `marksman` (Markdown), `lemminx` (XML). Rust later → `rust-analyzer` |
| **Auto-diagnostics** | After `edit`/`write`, appends compile errors for the changed file when a server is running (configurable via `.pi-lsp.json` in workspace root) |
| **⚠️ Vendoring pitfall** | The published package imports `vscode-languageserver-protocol/node.js` — the `.js` subpath was dropped from v3.18's `exports` map, which crashes the whole extension at load (no commands appear). Fixed in our vendor (commit `57c5cd2`): import `/node` instead. **Re-apply if re-vendoring from npm** |
### pi-subagents (@tintinweb)
v0.10.2, installed globally. 18 custom agent types in `~/.pi/agent/agents/` → `~/.agents/agents/`. Tools: `Agent()`, `get_subagent_result()`, `steer_subagent()`. `/agents` command for interactive management. Features: background agents with concurrency (4 default), mid-run steering, session resume, worktree isolation, scheduling, persistent widget showing live agent status. Cross-extension RPC event bus. Patched: 24h agent survival (was 10min), clearDisabled on session start. See [[Pi Subagent]] for full documentation.
### pi-tasks (@tintinweb)
v0.7.0, installed globally. 7 task tools: `TaskCreate`, `TaskList`, `TaskGet`, `TaskUpdate`, `TaskOutput`, `TaskStop`, `TaskExecute`. `/tasks` command. Features: dependency tracking (blocks/blockedBy), auto-cascade, background process tracking, persistent widget. `TaskExecute` spawns subagents via RPC.
---
## Skills
| Skill | Purpose |
|---|---|
| **nixos-workflow** | STRICT workflow for managing Pi assets via Gitea on NixOS |
| **system-architect** | Multi-machine NixOS infrastructure (Snapcast, MQTT, Docker, Nvim) |
| **obsidian-cli** | Interact with Obsidian vault (notes, search, plugin dev, theme dev) |
| **graphify** | Full-pipeline knowledge graph orchestration |
| **caveman** | Caveman communication mode |
| **openspec-propose** | Propose new changes with design docs, specs, tasks |
| **openspec-apply-change** | Implement tasks from an OpenSpec change |
| **openspec-archive-change** | Archive completed changes |
| **openspec-explore** | Explore ideas and clarify requirements |
| **npm-security** | Scan packages with SafeDep Vet, check typosquatting with npq, wrap installs with Socket Firewall |
| **ste-writing** | Rewrite prose (docs, READMEs, PRs, errors) into ASD-STE100 Simplified Technical English. Removes AI slop. Two modes: strict (procedures) and STE-flavored (general prose). Includes heuristic anti-slop linter (ste-lint.py). |
| **design-build** | Generate production-ready HTML/Tailwind code from design specifications and DESIGN.md design tokens. |
| **design-explore** | Generate UI design mockups as images for exploration and ideation. Supports DESIGN.md for design-token-accurate mockups. |
| **markitdown** | Convert files (PDF, Word, Excel, PowerPoint, images, HTML, CSV, JSON, XML, ZIP, EPubs, YouTube) to Markdown for LLM consumption. Image analysis via Qwen 2.5 VL 72B on OpenRouter. |
---
## markitdown
Convert various file formats to Markdown. Useful for feeding documents and images into LLMs.
### What it converts
| Format | Input | Notes |
|--------|-------|-------|
| PDF | `.pdf` | Preserves structure (headings, lists, tables) |
| Word | `.docx` | mammoth + lxml |
| PowerPoint | `.pptx` | python-pptx |
| Excel | `.xlsx`, `.xls` | openpyxl + pandas |
| Images | `.jpg`, `.png`, etc. | EXIF metadata (free) + LLM vision description (via OpenRouter) |
| HTML | `.html` | beautifulsoup4 |
| CSV / JSON / XML | `.csv`, `.json`, `.xml` | Structured data → Markdown tables |
| ZIP | `.zip` | Iterates contents, converts each file |
| EPubs | `.epub` | |
| YouTube | URLs | Transcript extraction |
### CLI usage
```bash
# Convert file to Markdown (stdout)
markitdown document.pdf
# Write to file
markitdown document.pdf -o document.md
# Image with LLM vision description
markitdown-vision photo.jpg
```
### Image analysis
Two levels:
1. **EXIF metadata only** (free, no API key): `markitdown photo.jpg`
2. **LLM vision description** (via OpenRouter, requires API key): `markitdown-vision photo.jpg`
The `markitdown-vision` wrapper auto-sources `OPENROUTER_API_KEY` from `~/.config/environment.d/10-secrets.conf` and uses `qwen/qwen2.5-vl-72b-instruct`.
### Missing / can be added
| Feature | What's needed |
|---------|--------------|
| Audio transcription | `pip install markitdown[audio-transcription]` (pydub + speechrecognition) |
| Azure AI Document Intelligence | `pip install markitdown[az-doc-intel]` + Azure credentials |
| Azure Content Understanding | `pip install markitdown[az-content-understanding]` + Azure credentials |
| markitdown-ocr plugin | Installed but needs OpenRouter key enabled to activate |
---
## falcode-zellij
Zellij plugin + agent extensions that track all active AI coding panes (pi, OpenCode, Claude Code) across Zellij sessions in a floating popup. Jump to any pane with one keystroke. Shows attention icons on Zellij tabs when an agent starts/stops working.
### Components
| Component | Location | Purpose |
|-----------|----------|---------|
| **Zellij WASM plugin** | `~/.config/zellij/plugins/falcode-zellij-sessions.wasm` | Floating popup UI showing all agent panes |
| **pi extension** | `~/.pi/agent/extensions/falcode.ts` | Reports pi pane status (working/idle) to the Zellij plugin |
| **attention WASM** | `~/.config/zellij/plugins/zellij-attention.wasm` | Shows ⏳/✅ icons on Zellij tabs when agent is active/done |
| **detection script** | `~/.local/state/falcode-zellij/` | Shared state directory for pane status snapshots |
### Keybindings
| Key | Action |
|-----|--------|
| `Alt a` | Launch/focus falcode floating popup (config.kdl `shared_except "locked"`) |
### pi integration
The `falcode.ts` extension auto-detects Zellij via `ZELLIJ_PANE_ID`/`ZELLIJ_SESSION_NAME` env vars. Outside Zellij it's a no-op.
- `agent_start` event → writes `"working"` status
- `agent_end` event → writes `"waiting_user_input"` status
- Heartbeat every 60s to keep pane alive
- `FALCODE_NOTIFY_SCRIPT=/bin/true` in home.nix (disables macOS notifications on Linux)
### Install on new machine
```bash
# pi extension
mkdir -p ~/.pi/agent/extensions
curl -L https://raw.githubusercontent.com/victor-falcon/falcode-zellij/main/pi-extension/falcode.ts \
-o ~/.pi/agent/extensions/falcode.ts
# WASM plugins
mkdir -p ~/.config/zellij/plugins
curl -L https://github.com/victor-falcon/falcode-zellij/releases/latest/download/falcode-zellij-sessions.wasm \
-o ~/.config/zellij/plugins/falcode-zellij-sessions.wasm
curl -L https://github.com/victor-falcon/falcode-zellij/releases/latest/download/zellij-attention.wasm \
-o ~/.config/zellij/plugins/zellij-attention.wasm
```
### Claude Code integration
Also has a hook at `~/.local/state/falcode-zellij/falcode-hook.sh` for Claude Code status reporting. See [README](https://github.com/victor-falcon/falcode-zellij#readme) for Claude config.
### Zellij config (`config.kdl`)
Already configured in Home Manager:
```kdl
plugins {
falcode location="file:/home/sam/.config/zellij/plugins/falcode-zellij-sessions.wasm" {
state_dir "/home/sam/.local/state/falcode-zellij"
}
attention location="file:/home/sam/.config/zellij/plugins/zellij-attention.wasm"
}
load_plugins {
"file:/home/sam/.config/zellij/plugins/zellij-attention.wasm" {
enabled "true"
waiting_icon "⏳"
completed_icon "✅"
}
}
keybinds {
shared_except "locked" {
bind "Alt a" {
LaunchOrFocusPlugin "falcode" {
floating true
move_to_focused_tab true
}
}
}
}
```
---
## Security Tools (npm Global)
Three tools installed globally at `~/.local/share/npm-global/bin/` to guard package installs.
### SafeDep Vet (`vet`)
Scans local directories for multi-language malware signatures. Catches obfuscated code, suspicious imports, base64 payloads.
```bash
# Scan a cloned repo before touching it
vet scan -D . --format json --filter "package.malware == true"
# Scan package metadata from npm registry
vet scan package <name> --format json
```
### Socket Firewall (`socket`)
Wraps npm/pip installs with real-time scanning. Blocks malicious packages at install time.
```bash
# Safe npm install
socket npm install <package>
# Safe pip install
socket pip install -r requirements.txt
```
### npq
Checks package names against typosquatting lists before install. Lightweight, local, no phoning home.
```bash
npq check <package> --json
```
### Workflow
```
1. vet scan → checks for malware in the code/package
2. npq check → checks the package name for typosquatting
3. socket install → wraps the actual install with runtime scanning
```
The **npm-security** skill instructs the Pi agent to follow this workflow before any install.
## Headroom
Headroom is a **context compression layer** that reduces prompt token usage by 60-95% for heavy analysis/code/devops workloads. It runs as a Docker container on the server (192.168.20.13) and is triggered by the headroom-bridge extension.
### How it works
1. headroom-bridge detects analysis/code/devops contexts
2. Tags `read`, `discuss`, `search` **never** trigger compression (these are fast paths)
3. For all other tags, if accumulated context exceeds ~5K tokens, headroom-bridge calls `compress()`
4. Messages are sent to the Headroom proxy at `192.168.20.13:8787`
5. Headroom compresses the context (using SmartCrusher for JSON, CodeCompressor for AST, Kompress-base ML for text)
6. Compressed messages are returned and forwarded to the LLM
7. If the proxy is down, messages pass through unchanged (graceful fallback)
### Architecture
```
Desktop (.27) Server (.13)
───────────── ────────────
headroom-bridge headroom proxy (Docker)
│ │
│ if compress needed: │
│ compress_for_agent(content) ──────►│
│ HTTP POST 192.168.20.13:8787 │
│ ◄────────── compressed content │
│ │
│ return to agent │
│ │
│ if proxy down: pass through │
```
### Compression thresholds
| Condition | Action |
|---|---|
| Tag is `read`/`discuss`/`search` | Skip — no compression |
| Context < 5K tokens | Skip — too small to benefit |
| Context ≥ 5K tokens + analysis/code/devops tag | Compress |
| Proxy unreachable | Pass through unchanged |
### headroom-bridge
Path: `~/.agents/extensions/headroom-bridge/index.ts`. Tool: `compress_for_agent({ content })` — compresses content >20K chars via Headroom Docker on .13:8787. 60-95% token reduction. See [[#Function Calls]] for signature.
### Management
```bash
# Check status
ssh 192.168.20.13 "docker ps --filter name=headroom"
# View logs
ssh 192.168.20.13 "docker logs --tail 20 headroom"
# Restart
ssh 192.168.20.13 "docker restart headroom"
# Update image
ssh 192.168.20.13 "cd /home/sam/Docker/Containers/headroom && docker compose pull && docker compose up -d"
```
### Files
| File | Purpose |
|------|---------|
| `~/.agents/extensions/headroom-bridge/index.ts` | `compress_for_agent` tool implementation |
| `/home/sam/Docker/Containers/headroom/docker-compose.yml` | Docker service definition (on .13) |
| `/home/sam/Docker/Containers/headroom/.env` | Environment file (on .13) |
## pi-langfuse — LLM Observability for Pi
Sends pi's LLM traffic to Langfuse (self-hosted on .13:3001) for tracing, token usage, and cost-per-session. One trace per user prompt, grouped by pi session.
| Aspect | Detail |
|--------|--------|
| **What it is** | pi extension (npm package `pi-langfuse` v1.5.8, by gooyoung) that captures pi runs — agent steps, LLM generations, tool calls, final output, usage, cost — into Langfuse |
| **Where it runs** | Per-project — vendored at `~/.agents/extensions/pi-langfuse/`, activated with `/config-add ext pi-langfuse` then `/reload`. Keys read globally from `~/.pi/agent/pi-langfuse/config.json` |
| **Config file** | `~/.pi/agent/pi-langfuse/config.json` (mode 600): `{ "publicKey": "pk-lf-…", "secretKey": "sk-lf-…", "host": "http://192.168.20.13:3001" }` |
| **Env var fallback** | `LANGFUSE_PUBLIC_KEY`, `LANGFUSE_SECRET_KEY`, `LANGFUSE_BASE_URL` (used only when config.json is missing/incomplete) |
| **Commands** | `/langfuse-setup` (interactive key entry), `/langfuse-status` (show config state, masked keys, capture policy) |
| **Requirements** | Node ≥ 22 (machines run 24); peer dep `@earendil-works/pi-coding-agent: *` |
| **What you get** | Root `agent`, per-request `generation`, and per-tool `tool` observations; token usage + cost; privacy controls (input/output/tool redaction, path hashing, secret redaction) |
| **Dashboard** | `http://192.168.20.13:3001` |
### Install (per project)
Run inside the target project folder (uses the standard `~/.agents` workflow — see the nixos-workflow skill):
```text
/config-add ext pi-langfuse
/reload
```
pi installs the extension's npm dependencies automatically (deps are gitignored in `~/.agents`).
### Global install (all projects / machines)
The global `~/.pi/agent/settings.json` is a Nix-store symlink (read-only). To enable everywhere, add `npm:pi-langfuse` to the `packages` list in `/etc/nixos/home/sam/home.nix` and rebuild Home Manager.
### Why not the OmniRoute langfuse plugin?
OmniRoute's example langfuse plugin is **broken against the 3.8.48 runtime** (verified in source, 2026-08-03):
- Plugin config is stored in SQLite but **never delivered to hook payloads** — `PluginContext` has no `config` field
- `onRequest` metadata is **not threaded** to `onResponse` (each hook gets a fresh `metadata: {}`)
- **Streaming requests** (what pi uses) receive `response: { status: 200, streamed: true }` — no response body to trace
pi-langfuse traces at the pi layer instead, which works for streaming and gives per-session grouping. The plugin files were removed from .13 (compose restored, container recreated clean).
## codebase-memory-mcp
Code intelligence MCP server by DeusData. Single static C binary (~13MB), zero dependencies, 158 languages. Indexes a codebase into a persistent knowledge graph — average repo in milliseconds. 15 MCP tools for structural queries. Runs locally, code never leaves your machine.
**Install:**
```bash
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
```
Installed to `~/.local/bin/codebase-memory-mcp`.
**Index a project:**
```
mcp({ tool: "index_repository", args: '{"repo_path": ".", "mode": "fast"}' })
```
**15 Tools:**
| Tool | What it does |
|------|-------------|
| `index_repository` | Index a repo (full/moderate/fast/cross-repo-intelligence modes) |
| `search_graph` | BM25 full-text search + semantic vector search for code |
| `query_graph` | Cypher queries — multi-hop patterns, complexity analysis |
| `trace_path` | Follow call chains, data flow, or cross-service HTTP via Route nodes |
| `get_code_snippet` | Read source code for a function/class/symbol |
| `get_graph_schema` | Show available node labels and edge types |
| `get_architecture` | High-level architecture: packages, clusters, routes, entry points |
| `search_code` | Grep + graph enrichment, ranked by structural importance |
| `list_projects` | List all indexed projects |
| `delete_project` | Remove a project from the graph |
| `index_status` | Check index freshness and stats |
| `detect_changes` | Find files changed since last index |
| `manage_adr` | Architecture Decision Records |
| `ingest_traces` | Import OpenTelemetry traces into the graph |
**MCP config** (`~/.pi/agent/mcp.json`):
```json
{
"mcpServers": {
"codebase-memory": {
"command": "/home/sam/.local/bin/codebase-memory-mcp",
"lifecycle": "lazy"
}
}
}
```
**Deployed on all machines (.27, .13, .51):**
```bash
~/.local/bin/codebase-memory-mcp --version # v0.9.0
```
Path not in shell PATH on .13/.51 — MCP config uses absolute path `/home/sam/.local/bin/codebase-memory-mcp` so still works.
**Install command (if needed on new machine):**
```bash
curl -fsSL https://raw.githubusercontent.com/DeusData/codebase-memory-mcp/main/install.sh | bash
```
**UI mode** (graph visualization at `localhost:9749`):
```bash
curl -fsSL .../install.sh | bash -s -- --ui
codebase-memory-mcp --ui=true --port=9749
```
Paper: [arXiv:2603.27277](https://arxiv.org/abs/2603.27277)
---
## code-review-graph
Structural code intelligence MCP server by tirth8205. Parses source code with Tree-sitter AST into a knowledge graph (functions, classes, imports, calls, inheritance, tests). Stored in SQLite. 28+ MCP tools for token-efficient code review, blast-radius analysis, and architectural insights. **Per-project** — each repo gets its own `.code-review-graph/graph.db`.
**Install:**
```bash
uv tool install code-review-graph # or: pipx install code-review-graph
```
Installed to `~/.local/bin/code-review-graph` v2.3.7.
**Build a graph for a project:**
```bash
cd /etc/nixos
code-review-graph build # parses codebase → .code-review-graph/graph.db
```
**Key MCP tools:**
| Tool | What it does |
|------|-------------|
| `get_review_context` | Compact review context (callers, callees, tests, risks) |
| `get_impact_radius` | Blast radius — every caller/dependent/test affected by a change |
| `query_graph` | Direct graph queries (traverse call chains, dependency paths) |
| `semantic_search_nodes` | Semantic (embedding-based) code search |
| `detect_changes` | Diff analysis: what changed and what's affected |
| `traverse_graph` | Walk the graph in any direction (BFS/DFS from any node) |
| `get_architecture_overview` | High-level structure: packages, clusters, entry points |
| `get_affected_flows` | Execution paths impacted by a change |
**Complement to codebase-memory-mcp:** code-review-graph captures **what your code is** (structure, dependencies), codebase-memory-mcp captures **what agents learn** (decisions, patterns, runbooks). They solve different layers — install both.
**Installed on:** .27 (uv tool install), .51 (nix-shell -p uv → uv tool install)
**GitHub:** [tirth8205/code-review-graph](https://github.com/tirth8205/code-review-graph) (28K+ stars)
---
## Pi Dashboard
A multi-component system for live agent visibility across all machines. Every pi session on every machine (plus sub-agents) reports its state; the TUI shows them all in one table and can attach to them, review their diffs, or open their task boards.
### Architecture
```
pi session (any machine, any terminal: zellij / tmux / plain)
└─ dashboard.ts extension
├─ writes ~/.pi/agent/dashboard/<session>.json (heartbeat every 15s + on events)
├─ tracks tasks → <project>/todo.txt
└─ sends NTFY / Apprise / notify-send notifications
│ SSH pull (cat *.json)
pi-dashboard (Go TUI on .27) ◄───────────────────────┴── .13 + .51 state dirs
```
| Component | Type | Purpose |
|-----------|------|---------|
| **dashboard.ts** | pi extension (`~/.pi/agent/extensions/dashboard.ts`; source `~/.agents/extensions/dashboard.ts` → Gitea `pi-config`) | Per-session telemetry: heartbeat, cwd, started/closed times, agent status, tool count; task tools; notifications |
| **pi-dashboard** | Go binary (`~/.local/bin/pi-dashboard`) | Bubble Tea TUI over all machines' state files |
| **Tuxedo** | Rust binary (`tuxedo`, nix) | todo.txt task manager (vim keys, phone capture QR) — per-project boards |
| **Hunk** | Node CLI (`hunk`, nix / npm `hunkdiff`) | Review-first terminal diff viewer for agent-authored changes |
### Quick start
```bash
pi-dashboard # full TUI
pi-dashboard --list # plain-text snapshot of local sessions
pi-dashboard --help # keybindings + config reference
```
### Day-to-day usage (the mental model)
**The pi terminal is for talking; the dashboard TUI is for watching.** You never type tool names or run hunk/tuxedo inside the pi input.
| You want to… | What you do | What happens |
|---|---|---|
| Add / list / complete tasks | Tell pi: *"add a task: …"*, *"what tasks do I have?"*, *"mark … done"* | The agent calls `register_task` / `list_tasks` / `complete_task`, which write lines to `<project>/todo.txt` at the project root |
| See the task board | Press `Tab` in the dashboard TUI | Tuxedo opens the selected session's `todo.txt` (vim keys: `j/k`, `dd` complete, `u` undo, `s` phone QR) |
| Review what an agent changed | Press `d` on its row in the dashboard TUI | Hunk opens in the agent's folder: `cd <cwd> && hunk diff --watch` — shows **all uncommitted changes** in that repo (not a two-file compare) |
| Jump into a session | Press `Enter` on its row | `tmux attach` / `zellij attach` / `zellij action switch-session` |
Key points:
- `register_task`/`complete_task`/`list_tasks` are **agent tools** — you ask in English, the AI calls them. They feed todo.txt, which is what Tuxedo displays.
- **Hunk's "first/second file" mode** is `hunk diff <left> <right>` for comparing two concrete files. The dashboard `d` key uses `hunk diff --watch` (whole working tree) instead.
- Both task systems coexist: the **dashboard tools** → todo.txt → Tuxedo (vim board), while **@tintinweb/pi-tasks** (`TaskCreate`, `TaskExecute`, `/tasks`) is a separate dependency-tracked task engine that can spawn subagents.
### State model
Each session writes `~/.pi/agent/dashboard/<session>.json` (atomic write):
| Field | Meaning |
|-------|---------|
| `session` | pi session name |
| `cwd` | full working directory the session runs in (the **Folder** column) |
| `session_started_at` / `closed_at` | session start / graceful-close times |
| `last_seen_at` | heartbeat — refreshed every 15 s + on every event |
| `agent_status` | `idle` / `running` / `blocked` / `error` (the *agent turn*) |
| `session_state` | `open` / `closed` (the *process liveness*) |
| `terminal_type` | `tmux` / `zellij` / `tmux+zellij` / `direct` |
| `zellij_session` / `tmux_session` / `pid` | attach targets for Enter |
| `is_subagent` | true for rows named `<Agent>#<8hex>` (pi-subagents) |
**Closed detection** — a session counts as closed when:
- the extension wrote `session_state: "closed"` on graceful shutdown, **or**
- `last_seen_at` is older than `stale_after` (default 45 s) — the terminal was killed (pane closed, `kill -9`) without a shutdown event.
Status labels: `● running` · `○ idle` · `⚠ blocked` · `✕ error` · `✗ closed` (graceful) · `✗ lost` (died without shutdown).
### TUI keybindings
| Key | Action |
|-----|--------|
| `↑↓` | Select agent |
| `Enter` | Attach: `tmux attach -t <name>` / `zellij attach <name>` (dashboard outside zellij) / `zellij action switch-session <name>` (dashboard inside zellij) — local, or over SSH for remote rows |
| `d` | **Hunk** — review the selected agent's changes *in its own folder*: `cd <cwd> && hunk diff --watch` |
| `Tab` | **Tuxedo** — open the selected agent's **project** task board: `<cwd>/todo.txt` (created if missing; falls back to global board) |
| `s` | Cycle sort: **smart** (live first → running first → last activity) → activity → started → folder |
| `x` | Toggle hiding closed sessions (dead sessions sink to the bottom by default; `x` removes them from the view, press again to restore) |
| `z` | Toggle hiding sub-agent rows (marked `◇`) |
| `r` | Force refresh |
| `q` | Quit |
Selecting a row shows a detail pane: full folder path, started / closed / last-seen times, terminal + zellij/tmux session + pid, model, tool count, current task, blocked prompt.
### Session naming & rename
Name resolution order on start: pi session name → `PI_SESSION` env → tmux session name → **zellij session name** (only when it isn't zellij's auto-generated `word-word` animal name like `chatty-echidna`) → working-directory basename.
**Recommended workflow — one named zellij session per pi session, same name for both:**
```bash
zellij -s computer_software # create a named zellij session…
# …pi started inside it auto-inherits "computer_software" as its pi session name
```
**Rename mid-session (pi session + zellij session + dashboard row together):**
```text
/dash-name <name>
```
> pi's built-in `/name` only renames the pi session and cannot be hooked by extensions — `/dash-name` renames all three (pi, zellij, dashboard row). Use `/name` or `Ctrl+R` in `/tree` when you only want to rename the pi session.
### Long-running / background sessions (tmux survival layer)
To keep a pi session running after zellij (or the terminal) closes — e.g. a long agent job on a remote machine — run pi inside a tmux session **inside** the zellij pane:
```bash
tmux new -s deploy-job # inside the zellij pane
pi # start pi inside tmux
# detach with Ctrl-b d — tmux (and pi) keep running after zellij closes
tmux attach -t deploy-job # reattach whenever
```
The extension detects the `TMUX` env var: rows show `Ⓣ`, and `Enter` does `tmux attach` — the session survives zellij closing. Rows in bare zellij panes show `Ⓩ`; `tmux+zellij` shows `ⓉⓏ`; plain terminals show `·`.
### Tasks & Tuxedo
- Agents register tasks via the `register_task` / `complete_task` / `list_tasks` tools.
- Task files are **per project**: `<project>/todo.txt` at the project root (standard todo.txt format) — visible in `ls`, easy to open, and **tracked in git** when the project is a repo: task changes are versioned (progress history) and visible to collaborators who clone the repo. (No gitignore — it's a tiny file; the only caveat is that tasks in a public/shared repo are public, so keep secrets out of task titles.)
- In the dashboard, `Tab` opens Tuxedo on the **selected row's** project board; with nothing selected it falls back to `~/.pi/agent/dashboard/tasks/todo.txt`.
- Tuxedo: vim keys (`j/k`, `dd`, `gg/G`), `u` undo (50 levels), `s` QR phone capture → https://github.com/webstonehq/tuxedo
### Hunk
- `d` in the dashboard runs `hunk diff --watch` in the selected agent's folder (over SSH for remote rows) — review exactly what that agent changed.
- Standalone: `hunk diff --watch` (live review of the working tree), `hunk show` (last commit). Multi-file sidebar, inline AI annotations, split/stack/responsive layouts. → https://github.com/modem-dev/hunk
### Cross-machine config (`~/.config/pi-dashboard.yaml`)
```yaml
poll_interval: 2
stale_after: 45 # seconds without heartbeat ⇒ session considered closed
hide_closed: false # start with closed sessions hidden (toggle with x)
local:
path: /home/sam/.pi/agent/dashboard/
remote:
- host: 192.168.20.13
user: sam
path: /home/sam/.pi/agent/dashboard/
- host: 192.168.20.51
user: sam
path: /home/sam/.pi/agent/dashboard/
```
Remote polling is plain `ssh … "cat <path>/*.json"` (BatchMode, 5 s connect timeout); unreachable remotes are skipped silently.
### Deployment
- **Extension** — source of truth: `~/.agents/extensions/dashboard.ts` (Gitea `pi-config`). Edit there, commit + push, then copy to `~/.pi/agent/extensions/dashboard.ts` on each machine (`.27`, `.13`, `.51`).
- **Binary** — `cd ~/src/pi-dashboard && CGO_ENABLED=0 go build -o ~/.local/bin/pi-dashboard .`, then `scp` to `.13`/`.51`.
- After updating the extension on a machine, run `/reload` in running pi sessions (or restart) to activate it.
- Dead state files accumulate by design (they just show as closed); the `archive/` subfolder holds pruned files.
---
## engram + gentle-engram
engram v1.16.1 runs on nixos-desktop (.13) at `~/.local/bin/engram`. Systemd user service auto-starts. Binds `127.0.0.1:7437`, accessed via SSH tunnel: `ssh -fNL 7437:127.0.0.1:7437 192.168.20.13`.
**gentle-engram** connects via `ENGRAM_URL=http://127.0.0.1:7437`. Replaces memory-vault. Features: session capture, compaction recovery, private block redaction.
⚠️ **The SSH tunnel must be running for engram to work.** It does not auto-start. Re-establish with: `ssh -fNL 7437:127.0.0.1:7437 192.168.20.13`
---
## MCP Servers
pi-mcp-adapter connects Pi to external services via the Model Context Protocol.
**Config files:** `~/.pi/agent/mcp.json` (pi global), `~/.config/mcp/mcp.json` (shared), `.mcp.json` (project)
```json
// ~/.pi/agent/mcp.json — pi MCP servers
{
"mcpServers": {
"codebase-memory": {
"command": "/home/sam/.local/bin/codebase-memory-mcp",
"lifecycle": "lazy"
},
"code-review-graph": {
"command": "/home/sam/.local/bin/code-review-graph",
"args": ["serve"],
"lifecycle": "lazy"
}
}
}
```
Shared config at `~/.config/mcp/mcp.json`:
```json
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "/home/sam"]
}
}
}
```
**Find MCP servers at:**
- [github.com/modelcontextprotocol/servers](https://github.com/modelcontextprotocol/servers)
- [smithery.ai](https://smithery.ai) — community registry
**Usage:**
- `/mcp` — interactive panel to manage servers
- `mcp({ search: "..." })` — search available tools
- `mcp({ tool: "tool_name", args: '{}' })` — call a tool
- Servers are lazy (connect on first use, disconnect after 10 min idle)
---
## Configuration Files
### Global (`~/.pi/agent/settings.json`)
- Nix store symlink — managed via `/etc/nixos/home/sam/home.nix`
- Contains: providers (opencode-go, openrouter, google), packages (pi-memctx, pi-prompt-template-model, Gitea)
- **Read-only** — cannot be modified by `pi install` or `/config-add`
### Project (`<project-dir>/.pi/settings.json`)
- Overrides global settings (arrays replace, not merge)
- Contains: `~/.agents` package (extensions + skills), Gitea package (tavily-search)
- Modified via `/config-add` / `/config-remove` commands
### Per-folder Memory (via pi-memctx)
- Memory stored in `<chat-folder>/.pi/memory-vault/packs/`
- Workspace map at `~/.pi/agent/memory-vault/00-system/workspace-map.json`
- Each chat folder has isolated memory (prevents sibling directory contamination)
### models.json (Provider Routing)
Path: `~/.pi/agent/models.json` (symlinked from `~/.agents/models.json` for Gitea). Injects OpenRouter provider routing for KV cache sharing. DeepSeek cache discount: 91.7% ($0.145/M vs $1.74/M input). Configured: deepseek, qwen, minimax, moonshotai. Mechanism: pi-core reads `model.compat.openRouterRouting` → injects `provider: { order: [...] }`.
### subagents.json
Path: `~/.pi/agent/subagents.json`. Configuration for pi-subagents agent types, default models, and providers.
---
## Useful Commands
| Command | What it does |
|---|---|
| `/config-setup` | One-shot: creates `.pi/`, `settings.json`, memory vault in current folder |
| `/config-add ext <name>` | Activate an extension from `~/.agents` |
| `/config-add skill <name>` | Activate a skill from `~/.agents` |
| `/config-show` | Show active extensions and skills |
| `/agents` | Interactive agent management (pi-subagents) |
| `/tasks` | Interactive task management (pi-tasks) |
| `/memctx-init` | Scan folder, build initial memory pack |
| `/memctx-status` | Show memory status |
| `/memctx-refresh` | Re-scan and enrich memory |
| `/filechanges` | Review changed files, diffs, accept/decline |
| `/filechanges-accept` | Accept all changes |
| `/filechanges-decline` | Revert all changes |
| `markitdown <file>` | Convert file to Markdown (PDF, Word, Excel, PPTX, images, HTML, etc.) |
| `markitdown-vision <file>` | Describe image using Qwen 2.5 VL 72B via OpenRouter |
| `Agent()` | Spawn subagent (pi-subagents) |
| `get_subagent_result()` | Retrieve results from background agent |
| `steer_subagent()` | Send mid-run steering message |
| `compress_for_agent()` | Compress large content via Headroom |
| `/langfuse-setup` | Set Langfuse keys interactively (pi-langfuse) |
| `/langfuse-status` | Show pi-langfuse config state (masked keys, host, capture policy) |
## Agent Roster (18)
| Agent | Model | Provider |
|-------|-------|----------|
| chat-search | google/gemini-2.5-flash:free | openrouter |
| code-analysis | deepseek-r1-distill-qwen-32b | opencode-go |
| code-ingest | google/gemini-2.5-flash:free | openrouter |
| coder-basic | deepseek/deepseek-chat | openrouter |
| coder-pro | deepseek/deepseek-v4-pro | openrouter |
| database | deepseek-r1-distill-qwen-32b | opencode-go |
| devops-basic | deepseek/deepseek-chat | openrouter |
| devops-pro | deepseek/deepseek-v4-pro | openrouter |
| document-writer | deepseek-r1-distill-qwen-32b | opencode-go |
| file-ops | qwen-coder-32b-instruct | opencode-go |
| home-automation | deepseek-r1-distill-qwen-32b | opencode-go |
| image-maker | black-forest-labs/flux-1-schnell | openrouter |
| iot-coder | qwen-coder-32b-instruct | opencode-go |
| iot-hardware | moonshotai/kimi-k2.6 | openrouter |
| obsidian | deepseek-r1-distill-qwen-14b | opencode-go |
| research | google/gemini-2.5-flash:free | openrouter |
| video-analyze | qwen/qwen-2.5-vl | openrouter |
| vscode-setup | qwen/qwen-3-coder-next | openrouter |
## Function Calls
```
Agent({ subagent_type, prompt, description, model?, thinking?, max_turns?, run_in_background?, resume?, isolated?, isolation?, inherit_context? })
get_subagent_result({ agent_id, wait?, verbose? })
steer_subagent({ agent_id, message })
compress_for_agent({ content })
```
---
## Skipped / Bookmarked
| Extension/Skill | Reason |
|---|---|
| **web-search** (amosblomqvist) | ❌ Redundant — Tavily does this |
| **subagents** (amosblomqvist) | ❌ Redundant — pi-subagents already installed |
| **bash-guard** (amosblomqvist) | ❌ Too aggressive — would interrupt flow |
| **google-image-search** (amosblomqvist) | ❌ Would need Google Search API + CSE setup |
| **pdf-reader** (amosblomqvist) | ⏳ Bookmarked — Python + pymupdf setup needed |
| **notify** (mitsuhiko) | ⏳ Minor QoL — desktop notifications on task complete |
| **audio/voice** | ⏳ Not practical | Pi TUI has no mic access or audio playback — fundamental platform limitation |
---
## Tasks
- [x] Rebuild NixOS to activate new packages ✅ 2026-06-11
- [x] Migrate to @tintinweb/pi-subagents with 18 agent types ✅ 2026-06-14
- [x] Deploy models.json with OpenRouter provider pinning (only: provider) ✅ 2026-06-14
- [x] Deploy engram + gentle-engram memory service on .13 ✅ 2026-06-13
- [x] Install pi-tasks (@tintinweb/pi-tasks) v0.7.0 ✅ 2026-06-13
- [x] Patch pi-subagents: 24h cleanup, disable clearCompleted ✅ 2026-06-14
- [x] Add memory: project to all 18 agent frontmats ✅ 2026-06-14
- [x] Remove custom subagent-registry skill (built-in /agents menu is sufficient) ✅ 2026-06-14
- [x] Update Pi Subagent.md and Pi Agent Extensions & Skills.md documentation ✅ 2026-06-14
- [x] Update pi-subagents to v0.10.3 ✅ 2026-06-14
- [x] Update pi-tasks to v0.7.0 ✅ 2026-06-13
- [x] Install pi-langfuse tracing extension (pi → Langfuse on .13:3001) ✅ 2026-08-03
- [x] Pi Dashboard v2: heartbeat + cwd + started/closed columns, hide/sort, /dash-name (pi+zellij), hunk in agent folder, tuxedo project boards, zellij/tmux attach ✅ 2026-08-04
- [ ] Verify video-extract works with Gemini
- [ ] Clean up workspace-map.json entries for any stale memory packs