Alpha
Native macOS agentic coding harness for the Pi coding agent.
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.
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+.
git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run build
bun run devThis launches Pi Desktop in development mode with hot reload.
Download the latest Pi Desktop-<version>-arm64.dmg from GitHub Releases.
- Open the DMG file.
- Drag Pi Desktop.app into your
Applicationsfolder. - Launch from Applications or Spotlight.
git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run build- 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.
- Launch Pi Desktop from Applications.
- Browse and manage local repositories.
- Create isolated Git worktrees for parallel development.
- Open integrated terminals in any project.
- Chat with the Pi coding agent directly in the app.
- View and manage project dependencies.
| Mode | Description |
|---|---|
| Mock | Simulated responses for UI development |
| CLI | Wraps the Pi agent CLI binary |
| Pi SDK | Direct integration with the Pi agent SDK |
| 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 |
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
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.
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
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 developmentPiCliRpcAgentRuntime: Spawns the Pi CLI and communicates via RPCPiSdkAgentRuntime: Direct SDK integration (in-process)
All implementations conform to the same interface, allowing runtime selection via environment variables.
Session Lifecycle
- User selects a thread
ContextSwitchControllerinitiates the switch- Previous session is torn down (unsubscribed, transport closed)
- New agent process spawned (if needed)
- Socket connection established
- Event subscription begins
- 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.
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 = ShellSnapshotHandlers are registered via registerIpcHandlers() and organized by domain (terminal, git, state, etc.). Errors are sanitized before crossing the boundary to prevent leaking internal details.
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.
bun run devStarts the Electron app in development mode with hot reload for the renderer process.
| 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/ |
apps/desktop/src/**/*.spec.{ts,tsx}: desktop unit and component testspackages/**/*.spec.{ts,tsx}: package-local unit teststests/integration/**/*.spec.ts: cross-package and wiring tests
cd apps/desktop
bun run dist:macOutput lands in dist/release/ as:
Pi Desktop-<version>-arm64.dmgPi Desktop-<version>-arm64.zip
Before shipping, run the full quality suite:
bun run lint
bun run typecheck
bun run test
bun run buildContributions are welcome. Pi Desktop is open source under the MIT License.
- Report bugs — Open 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
git clone https://github.com/tanRdev/pi-desktop.git
cd pi-desktop
bun install
bun run devbun 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.
- Follow existing TypeScript and React conventions
- Use Biome for formatting and linting
- Add tests for new functionality
- Run
bun run typecheckandbun run lintbefore opening a PR - Keep commits focused and descriptive
Pi Desktop is licensed under the MIT License. See the LICENSE file for details.