A macOS menu bar companion for the Busy Bar β control your bar over USB or Wi-Fi, automate your busy status, and turn the little LED display into a proper developer peripheral.
Core device control needs no BarKeep cloud, account, or telemetry: BarKeep
talks directly to the bar's local HTTP API over USB
(http://10.0.4.20/api, no authentication) or Wi-Fi (the bar's local IP
address and local HTTP API password). Optional Slack sync, weather, and update
checks contact their respective external services only when you enable or
request those features.
BarKeep is free and open-source software under the MIT License. You are welcome to use it, fork it, modify it, redistribute it, or build your own project from it. Contributions are welcome.
BarKeep was built with substantial assistance from generative AI tools, primarily OpenAI ChatGPT/Codex and Anthropic Claude. AI assisted with product exploration, implementation, debugging, tests, documentation, and release automation.
Brian Phillips is the human maintainer and reviews, tests, signs, and takes responsibility for every official release. This disclosure describes how the software was developed: BarKeep does not require or contact an AI service during normal operation. Its optional hooks and MCP server only connect to AI tools when you explicitly configure them.
Menu bar app (tabbed popover: Device / Message / Timers / Arcade / Settings)
- π Auto On-Call β flips the bar to On Air the moment any app opens your microphone (Teams, Zoom, FaceTimeβ¦), clears when the mic goes idle. Uses CoreAudio device state β no microphone permission needed, no audio ever captured.
- πΊ Live preview β see what's on the bar's display, right in the popover.
- π¬ Messages β send scrolling text in the bar's bitmap fonts, with a searchable full-emoji picker (emoji render to images on your Mac). Save presets, fire them in one click.
- π¨ Pixel canvas β draw on a true-to-device 72Γ16 grid and send it to the display.
- π Timers β Pomodoro (work/rest/cycles) and simple countdowns, driven by the bar's native timer engine.
- π Calendar β auto-busy during calendar events; one-click countdown-to-next-meeting on the bar.
- π Notification forwarding β scroll macOS notifications (Teams by default, any app by filter) across the bar with per-app LED colors, optional chime, and queue-during-calls replay.
- π Ambient widgets β live ping latency badge and local weather (icon + temperature) in the corners of the display.
- πΉ Busy Bar Arcade β play Snake, Tetris, Pong, and Breakout on the physical 72Γ16 display using your Mac keyboard. The Mac preview is optional and off by default.
- π€ Slack sync β bar goes busy β your Slack status becomes "π§ On a call" + DND; clears after.
- βοΈ Brightness/volume control, device rename, firmware update check, launch at login.
Developer tools
- π₯
barkeepCLI βbarkeep send "build done" -c green,barkeep busy on -T coding,barkeep timer 45,barkeep pomodoroβ¦ zero dependencies, scriptable from anything. - π€ Claude Code hooks β the bar becomes your agent status light: green scroll + chime when a long task finishes, red flash when Claude waits on input.
- π MCP server β exposes the bar as tools (
bar_send_message,bar_set_busy,bar_start_timer, β¦) so Claude, Codex, and ChatGPT desktop can drive it directly.
Requires macOS 14+ and a Busy Bar connected via USB or reachable on the same Wi-Fi network.
Grab BarKeep-x.y.z.zip from Releases, unzip, and move BarKeep.app to /Applications.
Release builds are signed with a Developer ID certificate and notarized by Apple, so they open normally through Gatekeeper. If you'd rather build it yourself, use the source instructions below.
brew tap unipheas/barkeep
brew install --cask barkeepHomebrew installs BarKeep.app directly into /Applications. To also install
the barkeep CLI, MCP server, and Claude Code hooks:
brew install barkeep-cliWhen upgrading, quit the running menu-bar app first so macOS does not keep the old executable in memory:
osascript -e 'quit app "BarKeep"' 2>/dev/null || true
brew upgrade --cask barkeep
open -a BarKeepThe running app version is shown at the bottom-right of its menu.
USB works at the fixed address 10.0.4.20 and does not require a password.
For Wi-Fi:
- Open the Busy Bar's web interface and go to Network β HTTP API.
- Enable HTTP API access and set its local numeric password.
- In BarKeep β Settings, enter the bar's Wi-Fi IP address and that same password in Wi-Fi password.
The password is the one configured on the physical bar. Tokens created at
cloud.busy.app are for the cloud API and will be rejected by the local
device API.
git clone https://github.com/unipheas/barkeep.git
cd barkeep
./make-app.shThis builds and launches dist/BarKeep.app (menu bar only, no Dock icon).
Signing prefers a Developer ID Application identity, then Apple Development,
or $BARKEEP_SIGN_IDENTITY when explicitly set; otherwise it falls back to
ad-hoc.
Optional extras:
ln -s "$PWD/bin/barkeep" /opt/homebrew/bin/barkeep # CLI on PATH
claude mcp add --scope user barkeep -- /usr/bin/python3 "$PWD/mcp/barkeep_mcp.py" # MCP serverClaude Code hooks: see hooks/ β wire them up in ~/.claude/settings.json (UserPromptSubmit β claude-prompt-submit.sh, Stop β claude-stop.sh, Notification β claude-notification.sh).
The ChatGPT desktop app, Codex CLI, and Codex IDE extension share local MCP configuration. Install the developer tools, then register BarKeep:
brew install barkeep-cli
codex mcp add barkeep -- /usr/bin/python3 "$(brew --prefix barkeep-cli)/libexec/barkeep_mcp.py"For a Busy Bar reached over Wi-Fi:
codex mcp add barkeep \
--env BARKEEP_HOST=YOUR_BAR_IP \
--env BARKEEP_TOKEN=YOUR_HTTP_API_PASSWORD \
-- /usr/bin/python3 "$(brew --prefix barkeep-cli)/libexec/barkeep_mcp.py"Restart ChatGPT desktop, Codex, or the IDE extension after adding the server.
Use /mcp to confirm that barkeep is connected.
To notify the Busy Bar whenever Codex or ChatGPT desktop finishes a turn and
waits for you, add this top-level setting to ~/.codex/config.toml:
# Apple Silicon Homebrew
notify = ["/opt/homebrew/opt/barkeep-cli/share/barkeep-cli/hooks/codex-notify.sh"]On an Intel Mac, use
/usr/local/opt/barkeep-cli/share/barkeep-cli/hooks/codex-notify.sh instead.
The notifier also forwards the event to Codex Computer Use when that helper is
installed. Restart Codex/ChatGPT desktop after changing the setting.
For permission-request signals and long-task timing, merge
hooks/codex-hooks.json into
~/.codex/hooks.json, restart the app, then open /hooks and trust the three
BarKeep commands.
| Feature | Permission | Why |
|---|---|---|
| Busy Bar connection | Local Network | Required for the bar's local HTTP API over both its USB network interface and Wi-Fi. BarKeep asks on first launch. |
| Notification forwarding | Full Disk Access | macOS stores delivered notifications in a TCC-protected SQLite DB (~/Library/Group Containers/group.com.apple.usernoted/db2/db). BarKeep polls it read-only; only titles/bodies matching your app filter are read, and they go straight to the bar over your local USB or Wi-Fi connection. |
| Calendar auto-busy | Calendar (full access) | To know when you're in an event. |
| Microphone detection | None | Mic detection reads CoreAudio device state, not audio. |
Grant Full Disk Access in System Settings β Privacy & Security β Full Disk
Access β add the installed BarKeep.app. Official release builds use a stable
Developer ID signature so the grant persists across upgrades. Locally rebuilt,
ad-hoc-signed copies may require the permission to be granted again.
- Create an app at https://api.slack.com/apps β From scratch
- OAuth & Permissions β User Token Scopes:
users.profile:write,dnd:write - Install to Workspace, copy the User OAuth Token (
xoxp-β¦) - Paste into BarKeep β Settings β Slack
Open BarKeep β Arcade, then choose a game. BarKeep captures keyboard input in a transparent input-only window, so the physical Busy Bar is the game display and no game window needs to remain visible on the Mac.
| Key | Action |
|---|---|
1 / 2 / 3 / 4 |
Switch to Snake / Tetris / Pong / Breakout |
| Arrow keys | Move (all games) |
W / S |
Alternate Pong controls |
β |
Rotate a Tetris piece |
β |
Soft-drop a Tetris piece |
| Space | Hard-drop a Tetris piece |
R |
Restart the current game |
| Escape | Stop the arcade and return keyboard focus to the previous Mac app |
Enable Show preview in BarKeep if you want a troubleshooting preview in the Arcade tab. Games cannot run while a native busy/timer session is active, because Busy Bar firmware rejects custom drawing during those sessions. Starting an on-call session stops the arcade automatically.
If another Mac app takes keyboard focus, the game remains active on the Busy Bar. Return to the Arcade tab and click Capture Keyboard to resume controls.
Everything is configured in the app's Settings tab β device host, local HTTP API password (needed for Wi-Fi), busy theme, notification filter, Slack token, ping target, weather unit and location (type a city, it's geocoded for you; leave empty for automatic IP-based location). No config files, no terminal required.
CLI env: BARKEEP_HOST (device address, default 10.0.4.20),
BARKEEP_TOKEN (the local HTTP API password for Wi-Fi), and
BARKEEP_THEME (busy theme, default on_air).
- Unreachable over USB: reconnect the cable, wait a few seconds for the
USB network interface, and leave the host set to
10.0.4.20. - Unreachable over Wi-Fi: confirm the Mac and Busy Bar can communicate on the same network. Guest networks and some phone hotspots isolate clients.
- Token rejected / HTTP 403: use the local numeric HTTP API password from
the bar's own web interface, not a token from
cloud.busy.app. - No Local Network prompt: open System Settings β Privacy & Security β Local Network and enable BarKeep. If it is already enabled, toggle it off and back on, then relaunch BarKeep.
- Pasted a full URL: BarKeep accepts either an IP/hostname or a URL such as
http://busy-bar.local/loginand normalizes it to the device host.
Verified against firmware 1.0.2 / API 24.3.0 (official local HTTP API docs):
- Over USB the API is served at
http://10.0.4.20/api/*with no authentication. Over Wi-Fi, enable HTTP API access in the bar's local web interface, configure its numeric password, then enter that same password in BarKeep Settings. BarKeep sends it using the firmware API's documentedX-API-Tokenheader. API tokens generated atcloud.busy.appare for the internet API and do not authenticate requests to a local IP address. The docs'/busybar/*prefix is for the cloud proxy; BarKeep communicates with the device locally. - Text elements accept printable ASCII only (bitmap fonts); BarKeep renders emoji/unicode to PNGs and uploads them as assets.
/api/screenreturns base64 of raw GRB pixel data (LED byte order), 72Γ16Γ3.- The firmware rejects all draw requests while a busy session is active, regardless of priority.
- Busy themes are directories on device storage (
/ext/apps_assets/busy/themes) β BarKeep discovers them dynamically. - Notification DB
rec_ids are recycled after deletions; BarKeep diffs by notification UUID.
swift test # run the test suite
swift build # debug build
./make-app.sh # signed release build + launchThe icon is generated: cd assets && swift gen_icon.swift 1024 icon.png (see gen_icon.swift for the pixel grid).
Release packaging verifies the signed app before archiving and verifies a
freshly extracted copy with
scripts/verify-release-archive.sh, so a
damaged release archive fails before publication.
Bug reports, feature ideas, documentation improvements, code contributions, and personal forks are welcome. See CONTRIBUTING.md for the development workflow and pull-request checklist.
Please report potential vulnerabilities privately using GitHub's security advisory form; see SECURITY.md for details.
BarKeep is released under the MIT License. In practical terms, you may use, copy, modify, merge, publish, distribute, sublicense, and sell copies of the software. Keep the copyright and license notice with copies or substantial portions of the project.
Contributions submitted to this repository are licensed under the same MIT terms.
Not affiliated with Busy Inc. Busy Bar is a product of https://busy.app.