A lightweight macOS menu bar app that displays real-time status of your AI coding assistant sessions.
- Multi-Tool Support β Claude Code, Gemini CLI, Cursor, OpenCode
- Multi-Session β Monitor multiple AI sessions simultaneously
- Real-Time β Instant status updates via WebSocket/HTTP
- Floating Window β Always-on-top, visible across all desktops
- Native macOS β SF Symbols, system appearance
- Lightweight β Minimal CPU/memory, pauses when idle
Requirements: macOS 13+, uv
# Install uv (Python package runner)
curl -LsSf https://astral.sh/uv/install.sh | sh
# One-line install (Claude Code only)
curl -fsSL https://raw.githubusercontent.com/runkids/code-buddy/main/install-remote.sh | bashFull install (all tools):
git clone https://github.com/runkids/code-buddy.git
cd code-buddy
./Scripts/install.shThe installer will:
- Build and install the app
- Install hook scripts and wrappers
- Configure hooks for selected tools
- Optionally set up aliases (
gemini,opencode)
| Tool | Hook Type | Notes |
|---|---|---|
| Claude Code | Lifecycle hooks | Full support |
| Gemini CLI | Wrapper + hooks | Use gemini-buddy or alias |
| Cursor | Shell hooks | Shell commands only |
| OpenCode | Plugin + wrapper | Use opencode-buddy or alias |
Gemini CLI and OpenCode need wrappers for full session tracking. The installer can set up aliases:
# ~/.zshrc (added by installer)
alias gemini=gemini-buddy
alias opencode=opencode-buddyWithout wrappers, sessions appear only after the first tool execution.
| Status | Description |
|---|---|
| Idle | No active tool |
| Starting | Session started |
| Thinking | AI responding / Agent working |
| Executing | Running Bash command |
| Reading | Reading files |
| Writing | Writing/editing files |
| Searching | Grep/Glob operations |
| Done! | Tool completed |
| Failed | Tool failed |
| Compacting | Context compaction |
| Notifying | Permission request |
| Resting | Paused |
| Goodbye! | Session ended |
βββββββββββββββββββ ββββββββββββββββββββ
β Claude Code ββββstdin JSONββββ β
β Gemini CLI ββββββββββββββββββ Hook Script β
β Cursor β β (Python/uv) β
βββββββββββββββββββ ββββββββββ¬ββββββββββ
β
WebSocket
:8765
β
βββββββββββββββββββ βΌ
β OpenCode βββββHTTP POSTβββββΆβββββββββββββββββββ
β Wrappers β β Code Buddy β
βββββββββββββββββββ β (SwiftUI) β
βββββββββββββββββββ
- Hook Script: Normalizes events from Claude/Gemini/Cursor β WebSocket
- OpenCode Plugin: Sends tool events β HTTP POST
- Wrappers: Send session start/end events
- Server:
localhost:8765(WebSocket + HTTP)
Click to expand
git clone https://github.com/runkids/code-buddy.git
cd code-buddy
swift build -c releasemkdir -p ~/.local/bin
# App and scripts
cp .build/release/CodeBuddy ~/.local/bin/
cp Scripts/code-buddy-hook.py ~/.local/bin/
cp Scripts/gemini-buddy.sh ~/.local/bin/gemini-buddy
cp Scripts/opencode-buddy.sh ~/.local/bin/opencode-buddy
chmod +x ~/.local/bin/{CodeBuddy,code-buddy-hook.py,gemini-buddy,opencode-buddy}
# OpenCode plugin
mkdir -p ~/.config/opencode/plugins
cp Scripts/code-buddy-opencode-plugin.js ~/.config/opencode/plugins/Edit ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [{"matcher": "*", "hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py PreToolUse --source claude"}]}],
"PostToolUse": [{"matcher": "*", "hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py PostToolUse --source claude"}]}],
"SessionStart": [{"hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py SessionStart --source claude"}]}],
"SessionEnd": [{"hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py SessionEnd --source claude"}]}]
}
}Edit ~/.gemini/settings.json:
{
"hooks": {
"BeforeTool": [{"matcher": "*", "hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py BeforeTool --source gemini"}]}],
"AfterTool": [{"matcher": "*", "hooks": [{"type": "command", "command": "~/.local/bin/code-buddy-hook.py AfterTool --source gemini"}]}]
}
}Add alias to ~/.zshrc: alias gemini=gemini-buddy
Edit ~/.cursor/hooks.json:
{
"version": 1,
"hooks": {
"beforeShellExecution": [{"command": "~/.local/bin/code-buddy-hook.py beforeShellExecution --source cursor"}],
"afterShellExecution": [{"command": "~/.local/bin/code-buddy-hook.py afterShellExecution --source cursor"}]
}
}Plugin is already installed. Add alias to ~/.zshrc: alias opencode=opencode-buddy
~/.local/bin/CodeBuddy &Add to ~/.zshrc:
# Start Code Buddy if not running
pgrep -x CodeBuddy > /dev/null || nohup ~/.local/bin/CodeBuddy > /tmp/code-buddy.log 2>&1 &./Scripts/uninstall.shOr manually:
pkill -x CodeBuddy 2>/dev/null || true
rm -f ~/.local/bin/{CodeBuddy,code-buddy-hook.py,gemini-buddy,opencode-buddy}
rm -f ~/.config/opencode/plugins/code-buddy-opencode-plugin.js
# Remove aliases from ~/.zshrc
# Remove hooks from ~/.claude/settings.json, ~/.gemini/settings.json, ~/.cursor/hooks.json"Waiting for AI tools..."
- Check Code Buddy is running:
pgrep CodeBuddy - Check port is listening:
lsof -i :8765 - Restart your AI tool to reload hooks
Debug logs
tail -f /tmp/code-buddy.log
# Hook script (enable with CODE_BUDDY_DEBUG=1)
tail -f /tmp/code-buddy-hook.logswift build # Debug
swift run # Run
swift build -c release # ReleaseMIT β see LICENSE
- Fork β 2. Branch β 3. Commit β 4. PR
