JR-Bar is a native macOS app for keeping track of coding agents. It shows which sessions are working, what finished while you were away, which agent needs an answer, and how much provider quota remains. Asks stay pinned until you answer them. Session state and quota can also drive the Screen Bar under the notch or optional SidePulse lights.
Current native panel rendered with synthetic demo sessions.
It is built to feel like the tools it sits beside: a glass panel off the status item, keyboard first, a Settings window that looks like System Settings, no web views. The app is Swift and SwiftUI; a Python daemon bundled inside it owns the facts.
Download the signed JR-Bar 0.9.16 installer
for an Apple silicon Mac running macOS 26 or newer. Open the PKG to install
JR-Bar in ~/Applications without an administrator password.
To build the current source instead, use Xcode Command Line Tools, Swift 6.2 or newer, and Python 3.12:
git clone https://github.com/JonathanRReed/JR-Bar.git && cd JR-Bar
make bootstrap
make package
make clean-installThis builds dist/JR-Bar-<version>.pkg, installs the app in
~/Applications, and opens it. Go to Settings > Providers to choose which
detected providers receive hooks. The quick start
covers the first useful checks.
- Knows which sessions are real. Every provider hook runs a 3 ms compiled shim. The daemon pairs each event with the agent's process, runs a liveness sweep on a 5 s tick that re-reads the process table at most every 15 s, reads Claude's per-process session files and tails Codex, pi and Gemini transcripts, so a session that died is marked ended within about 20 s instead of glowing all afternoon. Main sessions and their sub-agent workers are told apart; a finished task you have not looked at yet is different from one you have.
- Escalates only for real asks. A permission prompt, an input request or another ask turns the light amber. Asks are pinned at the top of the panel with Approve and Deny (⌘↩ / ⌘D) and arrive as banners with the same two actions. Left unanswered, an ask steps up: the light brightens after 30 s and the menu-bar icon pulses after 2 min. If you choose Chime or Take over in Settings > Alerts & Sounds > Advanced > Escalation > Loudest stage, a chime repeats every 30 s from 5 min on until you answer, and Take over also grows the ask out of the notch. By default it stops at the menu-bar pulse. The three delays are editable in the same group. A failed session is a red light, one banner and a short sound. It is not an ask and never escalates, and neither does a turn that merely ended with a question.
- The Screen Bar. A 4 pt band under the notch playing the same LEDS program as the strip, phase-locked to it, blended from eight samples into one gradient (never a row of segments). Hover shows the top session and a plain-language line about the light. Click the band to pin its card. Click the session mark on the left wing to open that session. It follows stays up over full-screen apps, and follows Alcove's capsule width when the Notch utility hands the notch to Alcove.
- Pro and Dot as one. When both are mounted they are written in one command from one presentation, and the Dot replays the strip's program at a fraction of its brightness, so the two read as a single instrument. Per device: display mode (agent status, battery, studio, quota runway), brightness with auto-brightness, provider pin, asks-only, and colour calibration with per-channel gains and resting glow previewed live.
- Usage with a forecast. The panel shows each provider's 5 h and 7 d windows with reset countdowns and a pace verdict; the Usage Center adds rings per window, a least-squares forecast of when the window runs out ("At this pace the 5h window runs out at 22:00"), and daily or hourly token and cost graphs from your local transcripts with the cache savings spelled out. Claude's official usage endpoint is opt-in.
- Studio. A library of motions (Breathe, Heartbeat, Chase, Gradient, Knight Rider, Comet, Twinkle, …) and data-only JSON packs, assignable by device, project, provider, scene or state, with parameters as native controls, a live strip preview, a 5 s preview on the real hardware, and import/export. Scene packs — a data-only bundle that re-themes every scene's effect policy at once — install, update and preview through the same machinery, migrated forward from older schema versions on the way in. Every program is clamped by the presentation compiler (2 Hz, 1 Hz for saturated red) before it reaches a strip or the screen.
- Lighting that knows the room. Auto-dim by schedule, by display brightness, or by the ambient light sensor; idle and sleep dimming; quiet hours; macOS Focus following with a dim rule per Focus; Mute, Dim, Pause, Asks-only and Dark modes for a while from the panel's Quiet… menu.
- Keeps the Mac awake for agents, and only for them. While agents work
the daemon holds a sleep assertion and lets go when they finish. With the
closed-lid policy on
agents, a smallpmsethelper (one sudoers rule) keeps a clamshell Mac running through a long task and lets it sleep when the task ends or the quota is gone. - Away from the desk. Calendar and Reminders glows; a webhook that POSTs JSON to ntfy, Home Assistant or anything with a URL when an ask reaches its last escalation stage, and optionally when a session finishes or fails, an ask opens or a quota is crossed; a read-only view of another Mac's sessions over Tailscale and SFTP; HMAC-signed usage sync between Macs; a loopback ingest listener so cloud-hosted agents can report in.
- Creator Micro 2 Control Center. Thirteen session keys with pins and banks, the dial and joystick, a compact rail on any screen edge, keymap apply and restore with a private backup of the pad's original. It works without the pad; the pad has so far been verified only powered off.
- History, doctor, updates. An activity window grouped by day with a
"while you were away" banner that measures from when you last looked;
a stuck or finished row can be dismissed until its session next speaks;
a Doctor checklist and
jrbar hooks doctor; Sparkle updates from this repository's releases, manual until you turn automatic checks on, with a beta channel. - Desktop utilities. Dock tools can hold or enhance the Dock, and Menu Bar tools can hide items behind JR-Bar's icon: hold ⌘ and drag an item left of the icon to hide it, right of it to show it. Menu Bar is enabled by default but hides nothing until you drag items over. One status line on its card says why hiding is paused or impossible and offers the fix; Show everything always shows everything. Dock enhancements and archive capture are opt-in. Each control explains its macOS permissions.
- Notch island, toys and the Overview. An optional island around the notch (the Notch utility, off until you turn it on) shows live counts, a hover card, event capsules, media and the shelf. The toys (Fold, Aquarium, Notch Buddy and Confetti) are all off until you turn them on in Settings > Utilities & Toys. The Overview window (⌘O from the panel or the status item's menu) lists every session by state, and ⇧⌘K opens the command palette.
![]() |
![]() |
| SidePulse Pro: eight LEDs on an SD card, for MacBook Pro. | SidePulse Dot: two LEDs on USB-C. |
Both mount as tiny volumes; JR-Bar writes a small program to LEDS.LED
atomically (the DSL is LEDS_FORMAT.md), so an eject
mid-write cannot leave the firmware a torn program. A first-batch Dot
mounts as PulseDot and is recognised as such. The
Creator Micro 2 speaks a vendor HID protocol
over USB or Bluetooth and is driven by the same daemon. Without any of
them, the Screen Bar is the light.
| Providers | |
|---|---|
| Supported (hooks, session truth, usage where the provider exposes it) | Claude Code, Codex (CLI and desktop), Gemini CLI, Pi, Grok, Devin, OpenCode, OpenClaw, Antigravity |
| Best effort (hook shapes known, not exercised on the author's Mac) | Cursor, Hermes Agent, Kiro |
| Neighbours, not providers | T3 Code (read-only session projection, docs/INTEGRATIONS.md); Alcove (the Screen Bar matches its capsule) |
The app detects providers without changing their configs. Install, reinstall, or remove hooks one provider at a time in Settings › Providers. On an upgrade, JR-Bar refreshes only hooks its detector can prove JR-Bar already manages; inactive hooks stay inactive and custom log paths stay in place. Codex's trust hash is recomputed locally for the exact command written. How each provider is read, and what its usage lanes mean, is in docs/NATIVE-PROVIDERS.md; adding one is docs/PROVIDER-ADAPTER-GUIDE.md.
Requirements: an Apple silicon Mac on macOS 26 or newer. JR-Bar is one signed app bundle carrying the daemon and the hook shim; nothing else is installed on the system. The download and the build from source are under Build and install above.
sudo installer -pkg dist/JR-Bar-<version>.pkg -target / puts it in
/Applications instead. On first launch the app starts its daemon, records
the installed build, and registers itself as a login item. It does not edit
provider hooks until you choose them in Settings › Providers. Click the icon for
the panel; right-click for the menu. The command
line lives inside the bundle; Settings › Shortcuts › Advanced › Command line ›
Install links it as ~/.local/bin/jrbar (put ~/.local/bin on your
PATH if it is not already). The link follows the app when you update it,
and Remove takes it away again.
jrbar usage # every provider's windows: "Claude 5h 42% used · resets in 2h 14m" (--json, --brief)
jrbar hooks doctor # what each provider's config runs today, and the sockets
jrbar doctor # daemon commit, memory, checks
jrbar status # sessions and asks right now (--json for scripts)
jrbar quiet 1h --mode dim # quiet JR-Bar; `jrbar quiet off` ends it
jrbar set global_brightness_scale 0.6 # any setting by dot-path (`jrbar get` reads one)
jrbar toggle dark # a quick toggle in the app; `jrbar awake 2h` keeps the Mac upThe app also answers jrbar:// links (Raycast Quicklinks, Alfred,
open in a script): jrbar://panel/toggle, jrbar://toggle/mic?on=1,
jrbar://awake?for=2h, jrbar://quiet?mode=dim&for=1h,
jrbar://session?id=<id>, jrbar://overview/graph (the Overview on its
Graph; jrbar://overview opens it where it was), jrbar://aquarium
(opens the tank, or brings it forward; it never closes it). Shortcuts
reaches every verb the same way: an Open URLs action with the link.
JR-Bar ships no Shortcuts actions of its own; the Command Line Tools
build can't write the metadata Shortcuts lists them from. Settings ›
Shortcuts lists the links and binds a global key to any action or
toggle. No link answers an ask.
The user guides, from usage hooks and Claude Code's status line to the xbar and Raycast examples, are indexed in docs/README.md.
To remove it: sudo ./scripts/uninstall-macos.sh takes out the hooks,
Claude Code's status line (putting back the one you had), the helpers,
the jrbar link and the app, wherever they were installed
(~/Applications or /Applications; ~/.local/bin or /usr/local/bin),
and leaves any file it did not put there alone. --dry-run shows the
steps without taking them, --keep-app keeps the app, --purge-state
also removes settings and history, and --purge-keychain also deletes the
provider keys JR-Bar saved in the login Keychain. By hand: quit the app, run
jrbar agent-monitor uninstall all (it also puts back Claude Code's
status line; it tries every provider, names any config it could not clean
and exits 1 after the last one), then delete JR-Bar.app.
The core panel works without extra grants. Features ask for the permissions they need when you turn them on.
| Permission | Unlocks | Asked when |
|---|---|---|
| Notifications | Ask and completion banners, with Approve / Deny on asks | The first time a banner is due, never at launch |
| Accessibility | Answering an ask by keystroke into the session's terminal (a Creator Micro 2 key, or Approve / Deny when the terminal is frontmost); Menu Bar tiles, search and click-through. The Screen Bar's read of Alcove's capsule uses it only if it is already granted | The first time a feature needs it |
| Automation | Opening a reviewed resume command in Terminal or iTerm2 when you choose Open | The first time you choose Open |
| Location Services | The Wi-Fi network name for Menu Bar rules that watch Wi-Fi; JR-Bar never reads or sends where you are | When you add a Wi-Fi rule |
| Calendar, Reminders | Event and reminder glows; the shelf's calendar row and reminder list | When you enable those signals |
| Camera | The notch card's Mirror row | When you turn the row on |
| Screen Recording | The Fold toy's desktop capture; live previews in the Dock and Menu Bar utilities | When you turn Fold on; the utilities fall back to icons without it |
| System Audio | The media row's live visualizer (a Core Audio tap on the playing app) | The first time the visualizer starts |
| Bluetooth | The notch's device-connect announcements | When the announcements run |
| Focus Status | Whether Focus is on, for React to Focus modes, Menu Bar rules and the status item's moon | When a feature that reads it is turned on |
| Full Disk Access | Names of active Focus modes for individual dimming, alert and calibration rules; the background helper needs access too | When you turn React to Focus modes on |
| An administrator password, once | The closed-lid sleep helper (/etc/sudoers.d/jrbar-disablesleep) |
When you set the closed-lid policy |
Grants are keyed to the signed JR-Bar.app; a development build signed
differently is a different app to macOS and asks again.
JR-Bar.app (Swift, app/) owns every pixel; jrbar-core (Python,
src/jrbar, frozen into Contents/Helpers/jrbar-core.app) owns every fact
and runs headless as the app's supervised child; jrbar-hook
(C, hook/) is the command every provider config runs. App and daemon
talk newline-delimited JSON over ~/.local/state/jrbar/core.sock: the
daemon pushes state, lights, settings and event documents, the app
sends commands (open_session, answer_ask, set_setting,
preview_program, deck_press, …) and replaces its model wholesale on
every frame. The contract is docs/CORE-PROTOCOL.md;
the process map, data paths and module map are
docs/ARCHITECTURE.md; the bundle and signing are
packaging/README.md.
./scripts/bootstrap-dev.sh # Python 3.12 venv at .venv, pinned tools
make fast # lint, imports, contract and focused tests
.venv/bin/python -m pytest tests # the full Python suite (about five minutes)
cd app && swift build && swift test # the Swift package and its suites
make package # the signed bundle, PKG and Sparkle archiveapp/README.md covers running the Swift app against a checkout's daemon
(JRBAR_CORE_EXEC=scripts/run-core.sh) or the mock daemon
(app/scripts/mock-core.py, on its own socket; never on the real one).
Releasing is docs/PRODUCTION-RELEASE.md; the
feature status is docs/FEATURE-MATRIX.md; what is
next is docs/ROADMAP.md. CI runs the same three checks on
a hosted macOS 26 runner. See CONTRIBUTING.md, and
AGENTS.md if a coding agent is doing the work.
0.8 is the first release under the JR-Bar name; earlier ones shipped as
SidePulse (sidepulse, SidePulse.app, io.sidepulse.*). Nothing has
to be done by hand:
- On first launch the daemon copies
~/.config/sidepulse,~/.local/state/sidepulse,~/.local/share/sidepulseand~/Library/Application Support/SidePulseinto their JR-Bar counterparts (copied, never moved; nothing already under a JR-Bar path is overwritten;~/.local/state/jrbar/migrated-from-sidepulse.jsonrecords it so it happens once). - Installers recognize legacy JR-Bar and SidePulse hook forms. Connecting
a provider replaces its owned legacy hooks with the bundled shim and
refreshes Codex's trust hash where applicable. Upgrades refresh owned
integrations while preserving disabled flags. The old
io.sidepulse.agentstatusandcom.sidepulse.agentstatusLaunchAgents are unloaded and removed; the app is a login item now, not a LaunchAgent. - Keychain secrets are copied forward on first read
(
io.sidepulse.provider.<id>→com.jonathanreed.jrbar.provider.<id>). SIDEPULSE_*environment variables remain fallback names for theirJRBAR_*counterparts. The oldsidepulsecommand and Python import aliases have been removed; usejrbar.
macOS keys permissions to the bundle identifier, so the grants above are
asked for again. Once the app is running and jrbar hooks doctor says
every provider runs the shim, the old ~/.config/sidepulse,
~/.local/state/sidepulse and ~/.local/share/sidepulse directories can
be deleted.
JR-Bar began as a fork of inteliwear/sidepulse, the companion app for the SidePulse hardware, and is fully divergent: hardware stays first-class, the UI is new, upstream work is ported behaviour by behaviour rather than merged. Many monitoring semantics and usage-tracking techniques were adopted, with citations in the code, from studying T3 Code and CodexBar. The LEDS format and the hardware are upstream's. Licensed under the MIT license, like upstream.







