A native desktop UI for Claude Code — chat, edit, and review code changes in one window.
Getting Started · Features · Architecture · Contributing
Claude Code is powerful, but it lives in the terminal. Bifrost gives it a visual home — a native desktop app where you can chat with Claude, watch it edit your code in real-time, review diffs, manage sessions, and switch between projects. All backed by the same Claude Code CLI you already use.
| Feature | Description |
|---|---|
| Live Streaming | Real-time WebSocket connection to Claude Code CLI with token-by-token streaming |
| Diff Viewer | Collapsible git diff panel that auto-updates as Claude edits files, with Shiki syntax highlighting |
| Session History | Browse and resume any previous Claude Code session — discovers sessions from ~/.claude/projects/ |
| Project Sidebar | Sessions grouped by project with collapsible navigation |
| Tool Progress | Live indicators for Read, Edit, Bash, and other tool executions |
| Tool Approval | Auto-approve mode or manual approve/deny toggle for each tool use |
| Model Selector | Switch between Opus, Sonnet, and Haiku — persisted across sessions |
| Rich Rendering | Markdown, code blocks, Mermaid diagrams, tables, and inline code |
| AskUserQuestion | Interactive multiple-choice prompts when Claude needs input |
| Code Review | Inline comment threads on diff lines with reply and resolve |
| Light/Dark Theme | Toggle with Cmd+D, persisted to localStorage |
┌─────────────────────────────────────────────────────────┐
│ Electron Main Process │
│ │
│ ┌──────────────┐ WebSocket ┌──────────────────┐ │
│ │ WsBridge │◄──── NDJSON ───►│ Claude CLI │ │
│ │ (ws server) │ │ --sdk-url │ │
│ └──────┬───────┘ │ --resume <id> │ │
│ │ └──────────────────┘ │
│ │ IPC │
│ ┌──────┴───────┐ ┌──────────────────┐ │
│ │ SessionManager│ │ GitWatcher │ │
│ │ (spawn/kill) │ │ (chokidar) │ │
│ └──────────────┘ │ → git diff │ │
│ └────────┬─────────┘ │
├──────────────── IPC ────────────────────────┼───────────┤
│ Renderer (React) │ │
│ │ │
│ ┌─────┐ ┌────────────┐ ┌──────────────┐ │ │
│ │Side │ │ ChatPanel │ │ DiffPanel │◄──┘ │
│ │bar │ │ streaming │ │ live diffs │ │
│ └─────┘ └────────────┘ └──────────────┘ │
└─────────────────────────────────────────────────────────┘
- Bifrost starts a WebSocket server in the Electron main process
- Claude Code CLI connects via
--sdk-url ws://localhost:PORT - Messages flow bidirectionally — user prompts go to CLI, streaming responses come back as NDJSON events
- Tool approvals are handled automatically or surfaced to the user
- Git diffs update in real-time via chokidar file watching
- Sessions are discoverable — scans
~/.claude/projects/for JSONL history files
- Claude Code CLI v2.0+ installed and authenticated
- Node.js 20+
- macOS, Windows, or Linux
git clone https://github.com/pyalwin/bifrost.git
cd bifrost
npm install
npm run devClick New thread in the sidebar, select a project directory, and start chatting.
brew tap pyalwin/bifrost https://github.com/pyalwin/bifrost
brew install --cask pyalwin/bifrost/bifrostThe tap is hosted in this repository, so the full GitHub URL is required when tapping.
Because Bifrost is currently distributed without Apple Developer ID signing or notarization, macOS will usually block the first launch with a message like:
Apple could not verify "Bifrost" is free of malware that may harm your Mac or compromise your privacy.
If that happens:
- Try to open
Bifrost.app - Open System Settings > Privacy & Security
- Click Open Anyway for Bifrost
- Confirm the follow-up prompt
That approval is only needed once per Mac.
| Layer | Technology | Purpose |
|---|---|---|
| Runtime | Electron | Native desktop app |
| Framework | React 18 + TypeScript | UI components |
| Build | electron-vite | Fast HMR development |
| Styling | Tailwind CSS v4 + shadcn/ui | Design system |
| CLI Bridge | ws (WebSocket) | Real-time communication with Claude Code |
| Diff Parsing | parse-diff | Git unified diff → structured data |
| Syntax | Shiki | VS Code-grade highlighting |
| Markdown | react-markdown + remark-gfm | Rich content rendering |
| Diagrams | Mermaid | Flowcharts, sequence diagrams |
| File Watch | chokidar | Live git change detection |
src/
├── main/ # Electron main process
│ ├── ws-bridge.ts # WebSocket server for CLI
│ ├── session-manager.ts # CLI process lifecycle
│ ├── git-watcher.ts # File watching + diff updates
│ ├── diff-parser.ts # Unified diff → DiffFileData[]
│ ├── session-discovery.ts # Scan ~/.claude for sessions
│ ├── session-history.ts # Load JSONL conversation history
│ └── cli-discovery.ts # Find claude binary
├── preload/ # IPC bridge (contextBridge)
└── renderer/ # React UI
├── features/
│ ├── sidebar/ # Project-grouped session list
│ ├── chat/ # Messages, streaming, tools
│ ├── diff/ # Git diff viewer
│ ├── title-bar/ # Status, branch, controls
│ └── start-screen/ # Project picker
├── hooks/
│ ├── use-claude.ts # CLI state management
│ ├── use-theme.ts # Light/dark toggle
│ └── use-auto-scroll.ts
└── types/ # Shared type definitions
npm run dev # Development with hot reload
npm run typecheck # Type check (node + web)
npm run lint # ESLint
npm run build # Production buildFor a local dry run, build the macOS zip artifacts and regenerate the Homebrew cask from those local files:
npm run build:mac
npm run generate:caskThis updates Casks/bifrost.rb using the local zip artifacts and the GitHub origin remote. For real releases, CI regenerates the cask from the published GitHub release assets so the published tap matches the exact files Homebrew downloads.
Push a tag like v1.0.5 after committing the updated version. .github/workflows/release.yml builds and publishes the macOS zip artifacts. After the release is published, .github/workflows/update-homebrew-cask.yml downloads those exact release assets, regenerates Casks/bifrost.rb, and opens a PR with the cask update.
For the full manual checklist, see docs/release-checklist.md.
Contributions are welcome! Please open an issue first to discuss what you'd like to change.
- Fork the repo
- Create your feature branch (
git checkout -b feat/amazing-feature) - Commit your changes (
git commit -m 'feat: add amazing feature') - Push to the branch (
git push origin feat/amazing-feature) - Open a Pull Request
- Powered by Claude Code by Anthropic
- UI components from shadcn/ui
- Icons from Lucide
