all repos — dingger @ 0f8438547e50e10b3c09f17356b1d88b93718b79

Watches the AI coding agents in your tmux panes on macOS and tells you which need you, from the menu bar, a floating panel, the status line and notifications; jumps to them, and restores tmux sessions and agents after a crash

floating panel: always-on-top agent HUD with a global shortcut

a non-activating HUD panel (every Space, over full-screen apps, never takes
focus) listing the agents waiting for you, with working and idle summarized
on one line; rows jump to the agent, drag moves the panel and it remembers
its place. modes: when agents are waiting (default), always, off; ctrl+opt+
cmd+e shows or hides it on top of the mode, and a manual hide lasts until
another agent starts waiting. the shortcut is a carbon hotkey (no
accessibility permission; clashes are reported in the menu) configured in
~/.config/dingger/config.toml, reloaded on save. the menu bar app is split
into model, panel, hotkey and main.

tested: --selftest checks the visibility rules (it fails if a newly waiting
agent no longer re-shows a dismissed panel); e2e step 13 checks the panel
content through the real binary.
Igor Soarez igor@soarez.org
Tue, 20 Oct 2026 14:24:11 +0300
commit

0f8438547e50e10b3c09f17356b1d88b93718b79

parent

6bccc5f786c479a335c55ad83487e077195cff44

6 files changed, 830 insertions(+), 215 deletions(-)

jump to
M README.md → README.md

@@ -38,6 +38,16 @@

- **Menu bar** (`menubar/main.swift`): `×1 ✓3 ◐2` in herdr's colors; the menu lists every agent in priority order, oldest waiting first. Clicking a row jumps to that pane. +- **Floating panel** (`menubar/panel.swift`): an always-on-top HUD that never + takes focus, on every Space and over full-screen apps. It lists the agents + waiting for you (blocked, done) and summarizes the rest + (`◐ 2 working · ○ 15 idle`); click a row to jump there, drag to move it. + **⌃⌥⌘E** shows or hides it from anywhere. Modes (menu bar, "Show Panel + Automatically"): *When agents are waiting* (default; appears when + something is blocked or done, hides when you have attended to everything), + *Always*, *Off*. Hiding it with the shortcut lasts until another agent + starts waiting. Change the shortcut in `~/.config/dingger/config.toml` + (menu bar, Settings…); it reloads when you save. - **tmux status line** (`packaging/tmux/dingger.tmux`): the same summary after the clock. Clicking it jumps to the top waiting agent (the menu's top row), skipping the window you already look at.

@@ -71,8 +81,8 @@ ```bash

cargo build --release cp target/release/dingger ~/.local/bin/dingger # do not strip: invalidates codesign --force --sign - ~/.local/bin/dingger # the signature, macOS kills it -swiftc -O -o target/dingger-menu menubar/main.swift # menu bar, bundled as - # ~/Applications/dingger.app +swiftc -O -o target/dingger-menu menubar/*.swift # menu bar + panel, bundled + # as ~/Applications/dingger.app ``` - launchd agents (start at login, restart on exit):

@@ -94,7 +104,8 @@ `tests/e2e.sh` starts its own tmux server, its own daemon (polling only every

30 s, so everything asserted must arrive through events), fake agents driven over the hook protocol, and a real tmux client whose focus it controls. It asserts every status transition, attendance by navigation, both click paths -(including the real menu bar binary), the status-line segment, latency with a +(including the real menu bar binary), the floating panel's visibility rules +and content, the status-line segment, latency with a deliberately slow notifier, and state surviving a daemon restart. It never touches your tmux server.

@@ -102,6 +113,7 @@ ## Layout

- `crates/detect-core`: the detection engine and 22 manifests, from herdr. - `crates/dinggerd`: the `dingger` binary (watcher, hooks, focus, CLI). -- `menubar/`: the menu bar app. +- `menubar/`: the menu bar app (`model.swift` rows and colors, `panel.swift` + the floating panel, `hotkey.swift` the global shortcut and settings). - `packaging/`: launchd agents and the tmux snippet. - `tests/e2e.sh`: the end-to-end suite.
M tests/e2e.sh → tests/e2e.sh

@@ -282,6 +282,20 @@ else

fail "node not found; cannot test the pi extension" fi +# --- 13. the floating panel: visibility rules and compact content ----------- +echo "13. floating panel" +if [ -x "$MENUBAR" ]; then + mb() { DINGGER_TMUX_SOCKET="$SOCK" DINGGER_BIN="$DINGGER" "$MENUBAR" "$@"; } + expect "panel visibility rules (selftest)" "mb --selftest | tail -1" "selftest ok" + expect "panel lists the waiting agent" "mb --print-panel | head -1 | cut -f1,2 | tr '\t' '|'" "✓ done|pi" + expect "panel summarizes the rest" "mb --print-panel | tail -1" "○ 3 idle" + DINGGER_TMUX_SOCKET="$SOCK" "$DINGGER" focus --client "$CLIENT" --pane "$A2" + expect "A2 idle after the jump" "opt $A2 @agent_state" idle + expect "panel with nothing waiting" "mb --print-panel" "Nothing waiting · ○ 4 idle" +else + fail "menu bar binary not found at $MENUBAR" +fi + echo echo "$PASSES passed, $FAILS failed" [ "$FAILS" -eq 0 ] || { echo "--- daemon log tail"; tail -30 "$DIR/daemon.log"; exit 1; }