--- 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, hardcoded in settings.json on .13) | --- ## 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 | Machine | Package installed | Provider config | `/omni setup` done | Models synced | |---------|-----------------|-----------------|-------------------|--------------| | .27 | ✅ In home.nix | ✅ `omni` | ✅ | ✅ | | .13 | ✅ pi install | ✅ `omni` | ✅ | ✅ | | .51 | ✅ pi install | ✅ `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-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 --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 # 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 --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/.json (heartbeat every 15s + on events) ├─ tracks tasks → /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 `/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 && 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 ` 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/.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 `#<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 ` / `zellij attach ` (dashboard outside zellij) / `zellij action switch-session ` (dashboard inside zellij) — local, or over SSH for remote rows | | `d` | **Hunk** — review the selected agent's changes *in its own folder*: `cd && hunk diff --watch` | | `Tab` | **Tuxedo** — open the selected agent's **project** task board: `/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 ``` > 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**: `/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 /*.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 (`/.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 `/.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 ` | Activate an extension from `~/.agents` | | `/config-add skill ` | 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 ` | Convert file to Markdown (PDF, Word, Excel, PPTX, images, HTML, etc.) | | `markitdown-vision ` | 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