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

7.2 KiB

Pi Dashboard — Decisive Build Plan

Decision 1: Architecture — SSH Pull (Phase 1) → HTTP Collector (Phase 2)

Decision: Phase 1 uses SSH pull. Phase 2 adds HTTP collector on .13.

Rationale: SSH pull requires zero infrastructure. Every machine already has SSH set up. The Go binary SSHes into each machine and reads state files. Later, the HTTP collector on .13 (alongside OmniRoute) becomes the single source of truth — extensions POST state to it, the viewer reads from it. This gives resilience when machines sleep.

Decision 2: TUI Tech Stack — Go + Bubble Tea

Decision: Go binary, Bubble Tea v2 for rendering.

Rationale: Single portable binary (~10MB), instant startup, no npm/Node dependency. The viewer runs from ~/bin/pi-dashboard on any machine, including Termux. Bubble Tea is actively maintained (v2.0.8, July 2026). The viewer is simple enough (~400 lines) that Go's learning curve isn't a barrier.

Decision 3: Web UI — Phase 2, Optional

Decision: Not building in Phase 1. Termux SSH → TUI binary is the mobile path.

Rationale: SSH from Termux renders the TUI perfectly. Web UI is a convenience for glanceable status from a browser — nice but not essential. If built in Phase 2, it's a small Svelte/Vue app served by the dashboard binary itself (pi-dashboard --web opens :9877).

Decision 4: Task List Integration — Yes, Phase 1

Decision: The dashboard shows a task board alongside agent status.

Rationale: The sub-agent system already has TaskCreate/TaskUpdate/TaskList/TaskExecute. The extension hooks into these and mirrors task state. The dashboard renders them as a tiered list sorted by status. Sub-agents call complete_task() via tool calls. This makes the dashboard a work tracker, not just a status panel.

Decision 5: Polling — 2-second interval, no file watcher

Decision: Poll state directory every 2 seconds.

Rationale: Simpler and more robust than fsnotify file watchers (which miss mid-write files, have edge cases on NFS/SSH mounts). A 2-second poll is invisible to the user and uses negligible CPU.

Decision 6: Session Naming — pi-<role> convention

Decision: tmux sessions named pi-work, pi-explore, pi-research, etc.

Rationale: The dashboard uses the session name as the connection key. Enter → tmux attach -t pi-work. Consistent naming lets the viewer jump without config.

Decision 7: Herdr — Try alongside, dashboard is multiplexer-agnostic

Decision: The dashboard works with any multiplexer (tmux, Zellij, Herdr, none). No Herdr-specific features in Phase 1.

Rationale: The dashboard reads state files and shows connection info. It doesn't care what runs the agent. Herdr can be tried in parallel on WS 2 without affecting the dashboard.


What Each Component Is

1. ~/.pi/agent/extensions/dashboard.ts

A pi extension. One file. Runs inside each pi session.

What it does:

  • Listens to agent_start / agent_end / tool_call events
  • Accumulates: agent type, model, status, duration, token count, last tool call
  • Detects blocked state (when ctx.ui.confirm() or ctx.ui.select() fires and waits)
  • Tracks tasks via tool calls (register_task, complete_task)
  • Writes ~/.pi/agent/dashboard/<session-name>.json on each event change
  • Optionally: POSTs state to HTTP collector on .13 (Phase 2)

Not needed: Any TUI rendering. The extension just collects and writes.

2. ~/bin/pi-dashboard (Go binary)

Standalone TUI. One binary.

What it does:

  • Reads all ~/.pi/agent/dashboard/*.json (local + SSH from remote machines)
  • Renders interactive table with agent status, tasks, costs
  • Keyboard controls: navigate, attach, filter, quit
  • Entertmux attach or shows Zellij tab/pane location
  • Polls every 2s for changes

Not needed: HTTP server in Phase 1.

3. .pi/agent/mcp.json entry (optional, Phase 2)

If the HTTP collector exists, the viewer can also be an MCP client querying the collector.


Implementation Order

Step 1: dashboard.ts extension

  • Correctly identify that the state file avoids reading the existing subagent code
  • Write the extension in ~/.pi/agent/extensions/dashboard.ts
  • Add event handlers: agent_start, agent_end, tool_call
  • Add blocked detection (intercept ctx.ui.select/confirm/input)
  • Add task tracking via tool registration
  • Write state to ~/.pi/agent/dashboard/<session>.json atomically
  • Test: launch a pi session, verify state file updates
  • Commit to Gitea

Step 2: Go TUI viewer

  • Initialize Go module at ~/src/pi-dashboard/
  • Add Bubble Tea dependency
  • Implement state file reader (local + SSH)
  • Render agent table with colors and status indicators
  • Add keyboard controls (nav, attach, filter, quit)
  • Add polling loop (2s interval)
  • Build binary to ~/bin/pi-dashboard
  • Test: launch 2-3 background pi sessions, verify dashboard shows them

Step 3: Cross-machine (SSH pull)

  • Add ~/.config/pi-dashboard.yaml config file support
  • Implement SSH state reader with timeout and error handling
  • Test: verify agents on .51 and .13 appear in .27's dashboard
  • Test: Enter on remote agent → SSH + tmux attach

Step 4: Task list view

  • Add task board panel (toggle with Tab)
  • Show tasks grouped by status (pending / in_progress / done)
  • Show which agent is assigned to which task
  • Integrate with existing TaskCreate/TaskUpdate APIs in pi

Step 5: Try Herdr

  • nix shell nixpkgs#herdr or download binary
  • Create a simple Herdr layout for WS 2
  • Run a pi session inside Herdr
  • Verify dashboard picks it up from state files
  • Evaluate: is the pain of migration worth Herdr's native visibility?

Step 6: HTTP collector + web UI (Phase 2, optional)

  • Add POST endpoint to dashboard.ts extension
  • Write collector server (Go, small binary on .13)
  • Update viewer to prefer collector over 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
pi-dashboard/ ~/src/pi-dashboard/ Go module for the TUI viewer
pi-dashboard/main.go entry point Bubble Tea model, view, update
pi-dashboard/config.go config YAML config reader for local paths + SSH remotes
pi-dashboard/state.go state reader Reads JSON files, polls, SSH fetch
pi-dashboard/tui.go TUI rendering Table layout, colors, keybindings
pi-dashboard/go.mod module Dependencies
~/.config/pi-dashboard.yaml user config Machine list, paths, polling interval
~/bin/pi-dashboard binary Built Go binary

What You Don't Need

  • A database (state files are JSON, small, temporary)
  • A daemon process (the viewer is stateless, polls files)
  • Node.js on the viewer machine (Go binary is self-contained)
  • Web framework (Phase 1 is TUI-only)
  • Herdr, Orca, Buzz integration (dashboard is agnostic)

Open Question for You

The task list integration: do you want the task board to be a separate screen (Tab to toggle between agent view and task board), or inline within the agent table (tasks shown under each agent row)?