Skip to content

tanRdev/pi-desktop

Repository files navigation

Pi Desktop

Pi Desktop

Alpha

Native macOS agentic coding harness for the Pi coding agent.

Electron React TypeScript Release License Status

Overview · Quick Start · Installation · Usage · Architecture · Development · Contributing

Caution

Alpha software. Expect breaking changes, incomplete features, and rough edges. Not ready for daily use.

Tip

Download the latest DMG from GitHub Releases and drag Pi Desktop.app into your Applications folder.

Overview

Pi Desktop is an agentic coding harness that wraps the Pi coding agent in a hardened macOS application. It provides a native interface for managing repositories, creating isolated Git worktrees, running terminals, handling packages, and chatting with the agent—all without leaving the desktop.

Built with Electron 41, React 19, and TypeScript 5.9, it runs the agent locally through multiple runtime modes (mock, CLI, Pi SDK) and ships as a signed DMG for macOS 11+.

Quick Start

git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run build
bun run dev

This launches Pi Desktop in development mode with hot reload.

Installation

macOS DMG (Recommended)

Download the latest Pi Desktop-<version>-arm64.dmg from GitHub Releases.

  1. Open the DMG file.
  2. Drag Pi Desktop.app into your Applications folder.
  3. Launch from Applications or Spotlight.

From Source

git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run build

Requirements

  • macOS 11 or later
  • Bun 1.3+
  • Node.js 24.13.1+

Note

The app requires Electron 41 and native dependencies (node-pty). Run bun install to rebuild native modules after upgrading Electron.

Usage

  1. Launch Pi Desktop from Applications.
  2. Browse and manage local repositories.
  3. Create isolated Git worktrees for parallel development.
  4. Open integrated terminals in any project.
  5. Chat with the Pi coding agent directly in the app.
  6. View and manage project dependencies.

Agent Runtime Modes

Mode Description
Mock Simulated responses for UI development
CLI Wraps the Pi agent CLI binary
Pi SDK Direct integration with the Pi agent SDK

Features

Feature Description
Repository Management Browse, clone, and organize local repositories
Worktree Isolation Create and switch between Git worktrees for parallel branches
Integrated Terminal Full terminal emulator powered by node-pty
Package Management View and manage project dependencies
Agent Chat Interactive chat interface with the Pi coding agent
Sandboxed Architecture Electron main process with secure preload bridge
Native macOS App Signed DMG distribution, runs as a proper desktop application

Architecture

System Overview

Pi Desktop is built on Electron's multi-process architecture with a strict security boundary between the main process (Node.js) and the renderer process (Chromium). The codebase is organized as a monorepo with clear separation between application code and shared packages.

pi-desktop/
├── apps/desktop/         # Electron application
│   ├── src/main/         # Main process: windows, IPC, native integrations
│   ├── src/preload/      # Preload bridge: secure API exposure
│   └── src/renderer/     # Renderer: React 19 UI
├── packages/
│   ├── shared/           # Shared models, IPC constants, and utilities
│   ├── agent-host/       # Agent runtime abstractions
│   ├── shell-model/      # State management logic
│   └── ui/               # Shared React components
└── tests/                # Cross-package integration tests

Process Architecture

Main Process (apps/desktop/src/main/) The main process is the authority for all native operations. It manages:

  • Window lifecycle and native menus
  • File system operations through catalog classes
  • Git operations via GitWorktreeService
  • Terminal management via node-pty
  • Agent host sessions in isolated processes
  • IPC handler registration and routing

The main process is written in TypeScript with the effect library, which provides typed, composable async operations with explicit error handling.

Preload Bridge (apps/desktop/src/preload/) The preload script runs in an isolated context with access to both Node.js and the renderer's DOM. It exposes a minimal, typed API to the renderer through Electron's contextBridge. This prevents Node.js APIs from leaking into the renderer while enabling secure communication.

Renderer Process (apps/desktop/src/renderer/) The renderer is a React 19 application built with:

  • Zustand for state management
  • Tailwind CSS for styling
  • Radix UI for accessible primitives

The renderer has no direct access to Node.js APIs; all native operations go through the preload bridge via typed IPC channels.

Data Layer

Catalogs The desktop app persists repository, thread, workspace, and preference state through catalog classes in apps/desktop/src/main/. For the current repo-hygiene and refactor direction, see REFACTOR.md.

State Flow

User Action → Catalog.update() → PersistentJsonFile → Disk
                    ↓
              IPC Notification → Renderer Re-render

Agent Runtime

The agent layer is abstracted to support multiple runtime modes without changing the desktop's calling code.

Runtime Factory createAgentRuntime() instantiates the appropriate implementation:

  • MockAgentRuntime: Returns canned responses for UI development
  • PiCliRpcAgentRuntime: Spawns the Pi CLI and communicates via RPC
  • PiSdkAgentRuntime: Direct SDK integration (in-process)

All implementations conform to the same interface, allowing runtime selection via environment variables.

Session Lifecycle

  1. User selects a thread
  2. ContextSwitchController initiates the switch
  3. Previous session is torn down (unsubscribed, transport closed)
  4. New agent process spawned (if needed)
  5. Socket connection established
  6. Event subscription begins
  7. UI notified of state change

The controller uses versioned cancellation tokens to handle rapid context switches—if a user clicks three threads in quick succession, only the last one's setup completes.

IPC Design

All communication between main and renderer uses typed channels defined in @pi-desktop/shared:

// IPC_CHANNELS.agent.prompt
type PromptRequest = { text: string }
type PromptResponse = void

// IPC_CHANNELS.shell.getSnapshot
type SnapshotRequest = void
type SnapshotResponse = ShellSnapshot

Handlers are registered via registerIpcHandlers() and organized by domain (terminal, git, state, etc.). Errors are sanitized before crossing the boundary to prevent leaking internal details.

Error Handling

The main process uses the effect library for structured error handling:

Effect.tryPromise({
  try: () => gitService.createWorktree(options),
  catch: (error) => GitError.from(error)
}).pipe(
  Effect.tap(() => notifySessionChanged()),
  Effect.catchAll((error) => 
    Effect.sync(() => showErrorDialog(error))
  )
)

Benefits:

  • Errors are typed and must be handled
  • Async operations compose without callback hell
  • Resource cleanup is guaranteed via structured concurrency
  • Stack traces are preserved for debugging

Warning

The app bundles node-pty with native bindings. After upgrading Electron or Node.js, run bun install in apps/desktop to rebuild native modules, or use the postinstall script.

Development

Run locally

bun run dev

Starts the Electron app in development mode with hot reload for the renderer process.

Commands

Command Purpose
bun install Install workspace dependencies and rebuild native modules
bun run build Build all workspaces (main, preload, renderer)
bun run dev Start dev server with hot reload
bun run lint Run Biome linter
bun run format Apply Biome formatting
bun run prepare Configure Git to use the tracked .githooks/ hooks
bun run typecheck Type-check all workspaces
bun run test Run workspace Vitest tests, including tests/integration/

Test layout

  • apps/desktop/src/**/*.spec.{ts,tsx}: desktop unit and component tests
  • packages/**/*.spec.{ts,tsx}: package-local unit tests
  • tests/integration/**/*.spec.ts: cross-package and wiring tests

Build macOS release

cd apps/desktop
bun run dist:mac

Output lands in dist/release/ as:

  • Pi Desktop-<version>-arm64.dmg
  • Pi Desktop-<version>-arm64.zip

Quality

Before shipping, run the full quality suite:

bun run lint
bun run typecheck
bun run test
bun run build

Contributing

Contributions are welcome. Pi Desktop is open source under the MIT License.

Ways to Contribute

  • Report bugsOpen an issue with steps to reproduce
  • Suggest features — Describe the problem you're solving before proposing solutions
  • Improve documentation — Fix typos, clarify instructions, or add examples
  • Submit pull requests — Fork the repo, branch off main, and open a PR with a clear description

Development Setup

git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run dev

bun install runs the prepare script and configures the tracked pre-commit hook automatically. If your package manager skips lifecycle scripts, run bun run prepare or git config core.hooksPath .githooks once after cloning.

Code Standards

  • Follow existing TypeScript and React conventions
  • Use Biome for formatting and linting
  • Add tests for new functionality
  • Run bun run typecheck and bun run lint before opening a PR
  • Keep commits focused and descriptive

Resources

License

Pi Desktop is licensed under the MIT License. See the LICENSE file for details.

Getting Help