pi-lot

a desktop gui for ai coding agents — 248 commits of slop creep

Overview

pi-lot was a desktop GUI for the pi coding agent. An Electron app that spawned pi as a subprocess and communicated over JSON-RPC, giving you streaming chat, tool execution display, model selection, session management, and analytics in a native window.

99% vibe coded. 248 commits in 10 days. Then shelved. The full retrospective is in the blog post.

The numbers

MetricValue
Commits248 across 9 active days
Lines of code~57,000 across 339 files
Agent sessions160
API cost$389.65
Tokens consumed525 million
Tool calls9,806
Hand-written code~1%

Architecture

Process model

Standard Electron two-process architecture with pi spawned as a JSON-RPC subprocess. This avoided the nightmare of bundling pi's ESM modules into Electron's CommonJS main process — pi runs exactly as it would in a terminal.

Electron App External spawn + stdin/stdout read/write child_process stdout JSON events stdin JSON-RPC contextBridge IPC bridge Main ProcessNode.js Preload ScriptcontextBridge Renderer ProcessReact + Vite Pi Agent--mode rpc File Systemworkspaces, sessions, config Gitdiff, status, log

RPC communication flow

The main process manages pi's lifecycle through PiRpcClient, which wraps a child process with JSON-RPC over stdin/stdout. Streaming events flow back through IPC to the renderer.

loop [Streaming response] Type message IPC: session:send stdin: JSON-RPC request stdout: message_start IPC: session:event Render streaming markdown stdout: content_block_delta IPC: session:event Update content read/write/edit/bash stdout: tool_use + tool_result IPC: session:event Render structured tool output stdout: message_stop IPC: session:event Message complete Tool execution User Renderer(React) Main Process(Node.js) Pi Agent(RPC mode)

IPC handler architecture

IPC handlers were split into domain-specific modules to keep the main process organized. Each module registers its own handlers through a shared context.

Main Process sessions.tsopen, send, abort,steer, fork, compact workspaces.tsadd, list, open,remove, pin settings.tspi config, auth,keybindings, providers git.tsdiff, status, log,branches analytics.tssession stats,cost aggregation app.tswindow controls,dialog, path utils auto-commit.tscommit staging registerAllIpcHandlers Shared ContextmainWindow, sessionManager,sendToRenderer

Session management

SessionManager in the main process tracks all open pi sessions, each backed by its own PiRpcClient subprocess. It handles lifecycle (open, send, abort, fork, compact, dispose) and routes events back through a callback.

Per Session Capabilities manages manages manages spawn spawn spawn onSessionEvent callback SessionManager Session APiRpcClient Session BPiRpcClient Session CPiRpcClient pi --mode rpccwd: /project-a pi --mode rpccwd: /project-b pi --mode rpccwd: /project-c Main ProcesssendToRenderer send message abort generation steer model/thinking fork session tree compact context cycle model

State management — domain store architecture

The client-side state went through a major refactor (SR-TASK series). The monolithic session store was split into four focused domain stores, with a compatibility facade preserving the original API.

Domain Stores React Components Event Pipeline reads from reads from reads from reads from session-store.tsCompatibility Facadecomposes openSessions Map session-registry-storeidentity, file paths,workspace, active pointer session-runtime-storestreaming, connected,model, thinking, retry session-transcript-storemessages, tool executions,content blocks session-tree-storeraw content, UI leaf ID,conversation branching Chat View Sidebar Toolbar Status Bar session-events-reducer.tsPure functions: event to mutation descriptor Dispatcherapplies descriptors to stores

The event pipeline used pure reducer functions — each event maps to a typed mutation descriptor with no store access or side effects. A dispatcher applies these descriptors to the appropriate stores. This pattern enabled comprehensive regression testing.

Frontend feature structure

Routes — TanStack Router Features UI Components — shadcn/ui /_app routemain layout /_review routereview layout /settings/*settings pages chat/message rendering,adapters, markdown sessions/events, resolver,tree utils, identity model-selector/dynamic model switching thinking/thinking level controls review/file diff panel analytics/session cost tracking workspaces/folder management status-bar/token usage, cost auto-commit/commit staging sidebar command palette popover scroll-area toast notifications

Key features at time of shelving

  • Streaming chat with markdown rendering in a native window
  • Tool execution display — structured rendering of file reads, writes, edits, bash commands
  • Model selector with dynamic model switching per active session
  • Session management — multi-session with workspace-scoped sidebar navigation
  • Session forking — branch conversation trees at any point
  • Context compaction — trigger pi's compaction from the UI
  • Analytics route — session cost tracking and aggregation
  • Review route — file diff panel for reviewing agent changes and submitting feedback back to the agent
  • Git integration — diff, status, log, branch info surfaced in the UI
  • Auto-commit — commit staging from the app
  • Full theme system — dark/light mode with design tokens
  • Structured logging with validation and event schemas
  • Regression test harnesses for session UX failure modes
  • Settings — pi provider config, keybindings editor, auth management

What was left on the roadmap

  • Session persistence and resume across app restarts
  • Multiple workspace tabs
  • File references (@file mentions in chat)
  • Image paste support
  • Keyboard shortcuts system

Why it was shelved

Read the full story: pi-lot: a slop creep journey

What came after

The project split into two layers that belong in different places:

  • agents — agent-facing: extensions, skills, themes, knowledge base. How agents work.
  • ariadne — human-facing: session analytics, cost tracking, file hotspots, session replay. What agents did.

Media