Files
obsidian-vault/100 inbox/Pi Dashboard.md

13 KiB

Pi Dashboard — Decisive Build Plan

Architecture Overview

┌─────────────────────────────────────────────────────────────────┐
│  pi sessions (each machine)                                     │
│                                                                 │
│  pi (with dashboard.ts extension)                               │
│  ├── agent_start → track: status, model, duration, tokens       │
│  ├── agent_end   → notify: NTFY/Apprise + mark complete         │
│  ├── tool_call   → track: last tool, tokens consumed            │
│  ├── blocked     → mark: waiting, save prompt text              │
│  └── register_task / complete_task → write to todo.txt          │
│       │                                                         │
│       └── Writes to:                                            │
│           ~/.pi/agent/dashboard/<session>.json    (agent state) │
│           ~/.pi/agent/dashboard/tasks/todo.txt   (task list)    │
│                                                                 │
│  On agent_end / blocked:                                        │
│  └── curl → NTFY server (phone notification)                    │
│  └── apprise → Slack/Telegram/email (configured routes)         │
└─────────────────────────────────────────────────────────────────┘
                        │
                        ▼
┌─────────────────────────────────────────────────────────────────┐
│  pi-dashboard viewer (Go + Bubble Tea)                          │
│                                                                 │
│  Reads: ~/.pi/agent/dashboard/*.json (local + SSH remote)       │
│  Renders: agent status table with cost, duration, location      │
│  Controls:                                                      │
│    Enter → tmux attach -t <session> (jump to agent)             │
│    Tab   → switch to Tuxedo (task list in todo.txt)             │
│    d     → hunk diff (review agent's worktree changes)          │
│    q     → quit                                                 │
│                                                                 │
│  Config: ~/.config/pi-dashboard.yaml                            │
│  (local paths, SSH remotes, polling interval)                   │
└─────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────┐
│  Companion tools (existing, not building)                       │
│                                                                 │
│  Tuxedo  → TUI todo.txt manager                                 │
│            Reads ~/.pi/agent/dashboard/tasks/todo.txt           │
│            Vim keys, phone capture QR, project/context filters  │
│                                                                 │
│  Hunk    → TUI diff viewer                                     │
│            hunk diff --watch → review agent changes live        │
│            hunk show → review last commit from agent            │
│                                                                 │
│  NTFY    → Push notification server (already running)           │
│            curl → ntfy.sh/pi-alerts → phone notification        │
│                                                                 │
│  Apprise → Multi-route notification dispatcher                  │
│            One command → Slack + Telegram + Email + NTFY        │
└─────────────────────────────────────────────────────────────────┘

Key Decisions

Decision Choice Why
State transfer SSH pull Phase 1 → HTTP collector on .13 Phase 2 Zero infra to start, resilient later
TUI framework Go + Bubble Tea Single binary, fast, portable
Web UI Phase 2, optional SSH from Termux works for Phase 1
Task board Use Tuxedo — don't build custom Tuxedo is already a polished todo.txt TUI with phone capture, vim keys, filters
Diff review Use Hunk — don't build custom Hunk is purpose-built for reviewing agent changesets
Notifications Use NTFY + Apprise — don't build custom Both already available, extension just calls curl / apprise
Polling 2s intervals, no file watcher Simple, no edge cases
Session naming pi-<role> (pi-work, pi-explore, etc.) Consistent jump target
Herdr Try alongside, no special integration Dashboard is multiplexer-agnostic

What Gets Built (Phase 1)

1. ~/.pi/agent/extensions/dashboard.ts (~150 lines)

Pi extension that collects state and writes files.

Event hooks:

  • agent_start → record: agent type, model, timestamp, status=running
  • agent_end → record: duration, token count, cost, status=done
  • tool_call → record: tool name, duration, input/output tokens (for cost)

Blocked detection:

  • Intercept ctx.ui.confirm(), ctx.ui.select(), ctx.ui.input() calls
  • When these fire and return is pending → mark status=blocked, save the prompt text

Task integration:

  • Register tool register_task(title, project, assignee) → append line to todo.txt
  • Register tool complete_task(id) → mark line as done in todo.txt
  • Register tool list_tasks() → read todo.txt, return formatted list

Notifications (Phase 1):

  • On agent_end: spawn curl to NTFY server with completion summary
  • On blocked: spawn curl to NTFY with blocking prompt and session name
  • On error: spawn curl to NTFY with error details

State file format (<session>.json):

{
  "session": "pi-work",
  "machine": "nixos-desktop",
  "host": "192.168.20.13",
  "agent_type": "coder-basic",
  "model": "opencode-go/deepseek-v4-flash",
  "status": "running",
  "started_at": "2026-07-27T10:23:00Z",
  "current_task": "Refactor auth middleware",
  "duration_seconds": 742,
  "tokens_in": 28100,
  "tokens_out": 20100,
  "cost": 0.09,
  "last_tool": "edit",
  "last_tool_at": "2026-07-27T10:34:22Z",
  "blocked": false,
  "blocked_prompt": null,
  "connection_type": "tmux",
  "connection_name": "pi-work",
  "worktree": "/tmp/pi/worktrees/auth-refactor/"
}

2. ~/bin/pi-dashboard (Go + Bubble Tea, ~400 lines)

Standalone TUI binary.

Rendering: Agent status table with columns:

╔══════════════════════════════════════════════════════════════════╗
║  ⬡ Pi Dashboard                    3 machines · 5 agents       ║
║  Total: $0.52 · Running: 2 · Blocked: 1 · Done: 2             ║
╠══════════════════════════════════════════════════════════════════╣
║  MACH  SESSION    TYPE    MODEL            STATUS   DUR   $    ║
║  ───────────────────────────────────────────────────────────────║
║  .27   pi-work    coder   oc/dsv4-flash    ● run   12:34 0.09 ║
║  .27   pi-explore explore oc/dsv4-flash    ● run   03:12 0.02 ║
║  .13   pi-resrch  rsrc    gemini-flash     ○ idle  00:47 0.00 ║
║  .51   pi-bugfix  coder   ds/v4-pro        ⚠ blk   01:23 0.11 ║
║        └─ ⚡ Allow rm -rf src/? (y/N)                         ║
╠══════════════════════════════════════════════════════════════════╣
║  [Enter] Attach  [d] Hunk diff  [Tab] Tuxedo  [r] Refresh  [q] ║
╚══════════════════════════════════════════════════════════════════╝

Keyboard controls:

Key Action Implementation
↑↓ Select agent Bubble Tea list model
Enter Attach to agent os.Exec("tmux attach -t <session>") or ssh -t user@host tmux attach -t <session>
d Hunk diff os.Exec("cd <worktree> && hunk diff --watch")
Tab Launch Tuxedo os.Exec("tuxedo --file ~/.pi/agent/dashboard/tasks/todo.txt")
r Force refresh Clear cache, re-poll
q Quit Exit

Config file (~/.config/pi-dashboard.yaml):

poll_interval: 2s

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/

What You DON'T Build

Feature Handled by Why not build it
Task board UI Tuxedo Already a polished todo.txt TUI with vim keys, phone capture, project/context filters. The extension just writes tasks to a standard format.
Diff review Hunk Already purpose-built for reviewing agent changesets with watch mode, AI annotations, split/stack layouts.
Push notifications NTFY Already running. Extension just POSTs to it.
Multi-route notifications Apprise Already available. Extension calls apprise -b "msg" to fan-out to Slack/Telegram/email.
Web UI Phase 2 TUI + SSH from Termux covers Phase 1.

Implementation Order

Step 1: dashboard.ts extension (~1.5 hours)

  • Write ~/.pi/agent/extensions/dashboard.ts
  • Add event listeners: agent_start, agent_end, tool_call
  • Add task tool registrations: register_task, complete_task, list_tasks
  • Add blocked detection via ui.custom wrappers
  • Add NTFY/Apprise notification on agent_end and blocked
  • Write state atomically to ~/.pi/agent/dashboard/<session>.json
  • Write tasks to ~/.pi/agent/dashboard/tasks/todo.txt
  • Test with one pi session
  • Commit to Gitea, pull on .13 and .51

Step 2: Go TUI viewer (~3 hours)

  • Init Go module at ~/src/pi-dashboard/
  • Implement state file reader (local + SSH with golang.org/x/crypto/ssh)
  • Implement YAML config reader
  • Build Bubble Tea model with agent list (bubbletea + bubbles list)
  • Add keyboard controls
  • Build binary to ~/bin/pi-dashboard
  • Test with 2-3 background pi sessions on .27

Step 3: Cross-machine + polish (~2 hours)

  • Test SSH pull from .51 and .13
  • Handle timeouts, unreachable machines, auth errors gracefully
  • Test Enter jumping to remote agents (ssh -t)
  • Test d → Hunk diff opens correctly
  • Test Tab → Tuxedo opens with task file

Step 4: Try Herdr (~1 hour)

  • nix shell nixpkgs#herdr or download
  • Create simple Herdr layout for WS 2
  • Run pi session inside Herdr
  • Verify dashboard picks it up
  • Evaluate whether migration from Zellij is worth it

Step 5: HTTP collector + web UI (~2 hours, optional Phase 2)

  • Add POST to collector endpoint in dashboard.ts
  • Write collector (Go, simple HTTP server)
  • Update viewer to try collector first, fall back to SSH
  • If web UI wanted: Svelte frontend served by collector

Files to Create

File Location Purpose
dashboard.ts ~/.pi/agent/extensions/ Pi extension: collects state, writes files, tracks tasks, sends notifications
pi-dashboard/main.go ~/src/pi-dashboard/ Entry point
pi-dashboard/config.go ~/src/pi-dashboard/ YAML config reader
pi-dashboard/state.go ~/src/pi-dashboard/ State file reader + SSH fetcher
pi-dashboard/tui.go ~/src/pi-dashboard/ Bubble Tea model, view, update
pi-dashboard/go.mod ~/src/pi-dashboard/ Dependencies
~/.config/pi-dashboard.yaml user config Machine list, paths, polling interval
~/bin/pi-dashboard binary Built Go binary

Total Effort

Step Time What you get
1. Extension 1.5h State files appearing, NTFY notifications on completion
2. TUI viewer 3h See all agents in one terminal, attach to any of them
3. Cross-machine 2h Agents on .51 and .13 visible from .27
4. Herdr trial 1h Know if Herdr is worth migrating to
Phase 1 total ~7.5h Full visibility across all machines
5. HTTP + web 2h Single source of truth, browser view

Prerequisites

  • Go (will install via nix)
  • Bubble Tea (go get)
  • NTFY server (already running)
  • Apprise (already available)
  • Tuxedo (will install via brew/nix)
  • Hunk (will install via npm/nix)
  • tmux (already available)
  • SSH (already configured)
  • Gitea (for syncing the extension)