feat: floating always-on-top agent status overlay#514
Merged
Conversation
A second frameless BrowserWindow that floats above other apps (Chrome,
editors) showing live agent status: a compact pill of activity-dot
counts that expands on click into per-agent rows. Clicking a row raises
Agent Code and focuses that agent's pane. Toggled from the command
palette ("Floating Agent Status"); enabled state, position, and
pill/list mode persist across restarts; auto-hides while Agent Code
itself is focused.
Architecture: the main renderer (which already owns all status
derivation) publishes a precomputed snapshot over agent-overlay:* IPC;
main caches and forwards it to the overlay window. The overlay stays a
dumb display, so no session IPC fan-out was needed and mainWindow.ts's
single-window assumption is untouched. dispatchActivity + palette
helpers moved out of DispatchAgentList.tsx into their own module so the
overlay bundle (8.5 kB) shares the activity vocabulary without
dragging in the Dispatch component graph.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…d, attention gate Fixes all findings from the two-agent review: 1. macOS activate/window-all-closed no longer confused by the second window: hasMainWindow() drives activation, and the overlay is destroyed with the main window (its data source) and recreated via syncAgentOverlayWindow on Dock re-activation. 2. Overlay now loads a dedicated least-privilege preload (overlay.mjs, four methods) instead of the full api bridge. 3. Navigation hardening on the overlay window (deny window.open, prevent will-navigate) matching the main window's stance. 4. IPC-vs-restore race serialized: toggle/get-enabled await the persisted-state load. 5. agent-overlay:report payload is runtime-validated and bounded (it is cached in main and replayed to the overlay on every load). 6. Persisted position and expand-resizes are clamped to the matching display work area so the overlay can never strand off-screen. 7. ready-to-show guards on enabled so a fast toggle off mid-load can't resurrect the window. 8. enabled/quit persistence is write-through (flush on toggle and before-quit); only drag positions stay debounced. 9. dispatchAttentionLabelFromConditions now applies the same visible:false gate as conditionRequiresAttention, so hidden permission prompts no longer pulse the overlay's waiting pill (fixed in the selector so Dispatch and the overlay agree). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This was referenced Jul 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
A floating agent-status overlay: a small frameless, always-on-top window that stays visible over other apps (Chrome, editors, fullscreen Spaces) and shows what your agents are doing at a glance.
no agentswhen empty.running Bash→ activity word).~/.config/<app>/agent-overlay.json).focusable: false,showInactive).How
The overlay deliberately does not consume session IPC. The main renderer — which already owns all status derivation (
dispatchActivity,dispatchAttentionLabelFromConditions,sessionTitle,buildVisibleDispatchRows) — publishes a precomputed snapshot (throttled 200ms, deduped on content) over newagent-overlay:*channels; main caches and forwards it to the overlay window. Consequences:sendToMainWindow/ the session forwarder / mainWindow.ts's single-window assumption are all untouched — no fan-out refactor.overlay.html), sharingstyles.css, the preload bundle, and the theme viaapplyThemeon an opaque settings pass-through.dispatchActivity+ palette helpers moved fromDispatchAgentList.tsxintoworkspace/dispatch/dispatchActivity.ts(re-exported for existing importers) so all three surfaces — Dispatch list, mini-list, overlay — share one activity vocabulary.Verification
tsc -b tsconfig.node.jsonandtsc -b tsconfig.web.jsonboth cleanelectron-vite buildpasses;out/renderer/overlay.html+ chunks emittedvitest run: 481 tests pass. One failing suite (agent-voice-dictationsubmodulehotkeyBinding.test.ts, "No test suite found" — it's anode:testfile) fails identically onmainat the same submodule SHA; pre-existing and unrelated.npm run devsession (didn't want to fight the state process lock with a running instance); worth a quick manual pass: toggle the command, drag the pill, expand, click a row from Chrome.🤖 Generated with Claude Code