A translucent always-on-top Windows overlay that shows live state of your AI coding agents. v0.1 covers Codex Desktop, Cursor, and Claude Code (user-level hooks).
v0.1 — Milestone A. Codex Desktop, Cursor, and Claude Code (user-level hooks). Compact pill plus expanded hover detail on pill or fleet bar. Dogfood build.
Near-term polish is tracked in ROADMAP.md. Hover panel layout and activity feed behavior are summarized in HOVER_PANEL.md.
- Fleet bar — One dot per agent session (Codex, Cursor, or Claude; up to eight visible, then
+Noverflow). Dots reflect status: idle, working, done, errored (working dots use a subtle pulse). - Primary line — App label (
Codex/Cursor/Claude), project folder name, and the current action (Editing …,Running: …, or a Done summary with diff totals when the run has finished). - Done queue — If more than one session is Done and not yet acknowledged, the primary line is prefixed with
✓ N done ·before the usual Done summary for the frontmost completion. - Status badge — Elapsed time while working; just now / ago after Done.
- Hooks disconnected hint — If no agent hooks are installed, the pill shows Connect in Settings to get started (click opens Settings). When sessions exist but hooks are still off, a small hollow amber dot appears after the fleet; click it to open Settings.
Primary selection — Auto-priority: errored → unacknowledged Done → most recently active. Single-click a fleet dot to temporarily switch the primary line to that session (clears when the overlay loses focus). Clicking the pill body clears that temporary selection.
The pill row is draggable (data-tauri-drag-region). Tray: Show, Settings…, Quit. Single instance — launching again focuses the existing overlay.
Opens when the pointer is over the pill or fleet bar (expands the window to ~380×300). The card is interactive — buttons do not steal drag from the pill.
- Context row —
You asked: …from the last prompt submit (truncated; full text in tooltip), or New session. Right side:project · Codex|Cursor|Claudeand model name when known. - While working — Bold
currentActionfrom the latestPreToolUse(patch targets, bash labels, MCP tools). Below that, a short activity feed (up to eight recent lines) built from hook events:- Per-turn buffer: parallel tool calls in one turn flush as
Parallel: A · B · C(with+N morewhen capped). - Bash commands are classified (git, npm/cargo, rg, gh, PowerShell
Get-Contentranges, heredoc/pipe-to-node, etc.) with dedupe within a turn. PostToolUseadds lines for test results (green/red), ripgrep matches, git log/blame,ghPR/issue JSON, nodeCASE:probes, and commit hashes when the last bash was a commit/push-style command.- Repeated identical summaries in the same turn bump a
×Ncounter on the newest line.
- Per-turn buffer: parallel tool calls in one turn flush as
- When Done — Prefer a one- or two-line assistant summary from
Stopwhen present; otherwise diff totals and a scrollable per-file list (basename++adds / −dels), or No files changed / Pushed {hash} when only a commit was recorded. - Action strip — Elapsed label (
Running …/Finished …; hover title shows absolute start/finish time). Open Codex / Open Cursor / Open Claude (by session app) and Dismiss (acknowledges Done without focusing) as appropriate.
Acknowledged Done sessions are removed from the fleet after about seven seconds (scheduled in the frontend when acknowledgedDone flips true).
- Connect Codex — Installs or removes managed hook entries in
~/.codex/config.toml(with backup). Restart Codex after toggling. - Connect Cursor — Installs or removes managed hook entries in
~/.cursor/hooks.json(with backup). Restart Cursor after toggling. - Connect Claude — Installs or removes managed async command hooks in
~/.claude/settings.json(with backup). Restart Claude Code after toggling. - Position — Corners of the primary monitor (top-left / top-right / bottom-left / bottom-right).
- Opacity — Slider updates in-app state (full visual wiring is still on the roadmap).
When the overlay regains focus, it refreshes corner and hook installed state from disk so changes from Settings stay in sync.
Two binaries:
overlay-app.exe— the Tauri app: Rust core (HTTP listener + session store) + React WebView UI + system trayoverlay-hook.exe— a tiny stdin-to-HTTP relay that Codex, Cursor, and Claude Code hooks point at
Codex / Cursor / Claude Code session
|
| spawns per hook event, JSON on stdin
v
overlay-hook.exe -- POST http://127.0.0.1:47611/event (200ms fire-and-forget) --> overlay-app.exe
|
| stdout always `{}` on exit 0
v
agent continues
Hook events are normalized in apps/overlay/src-tauri/src/session.rs (Session::apply): status, currentAction, file diffs, recentActivity, doneSummary, lastPrompt, model, and commit hash hints. Cursor handling includes UTF-8 BOM strip in overlay-hook.exe, Shell / Set-Location command labeling, tool_output JSON unwrap, conversation_id / generation_id, and afterFileEdit for diffs. Claude Code sessions are detected via transcript_path under ~/.claude/projects/; hooks use PascalCase event names (SessionStart, StopFailure, …), Edit/Write for file diffs, and last_assistant_message on Stop. Activity lines use per-turn buffering, parallel flush (Parallel: A · B · C), and bash/output classifiers (see HOVER_PANEL.md). The UI polls session snapshots via Tauri commands.
If overlay-app.exe is closed or crashed, the hook POST times out in 200ms and the Codex session is never blocked.
- Windows 10 or 11
- Rust stable, with the
x86_64-pc-windows-msvctarget - Microsoft C++ Build Tools — install from the Visual Studio Build Tools page and select the "Desktop development with C++" workload. This provides
link.exe, which Rust uses to link Tauri. WebView2 is shipped with Windows 11 and recent Windows 10. - Node 20+ and npm 10+
cd apps\overlay
npm install
npm run app:devapp:dev first builds overlay-hook.exe in release mode, then launches cargo tauri dev, which starts Vite for hot-reload UI and the Rust app. The overlay window appears in the chosen corner of the primary monitor; the tray icon shows up next to the clock.
Open Settings… from the tray and toggle Connect Codex, Connect Cursor, and/or Connect Claude. Codex entries go into ~/.codex/config.toml (backup config.toml.overlay-backup). Cursor entries go into ~/.cursor/hooks.json (backup hooks.json.overlay-backup). Claude entries go into ~/.claude/settings.json (backup settings.json.overlay-backup). Restart each app after toggling. Disconnecting removes only entries we added (overlay_managed).
You do not need npm run app:dev for day-to-day use. Build once, then double-click the release binary (or pin it to the taskbar).
Prerequisites: same as Prerequisites (Rust MSVC target, Node for the one-time frontend build, WebView2 on Windows).
cd apps\overlay
npm install
npm run app:buildWhere the .exe lands
| Artifact | Path (from repo root overlay-app/) |
|---|---|
| Overlay app (run this) | apps\overlay\src-tauri\target\release\overlay-app.exe |
| Hook relay (installed by Settings) | target\release\overlay-hook.exe |
| Installer bundles (optional) | apps\overlay\src-tauri\target\release\bundle\ (.msi / NSIS) |
First run
- Double-click
overlay-app.exe(or run it from PowerShell). A tray icon appears; the pill shows in the chosen corner. - Tray → Settings… → Connect Codex / Connect Cursor (writes managed hooks; restart each agent app).
- Start a Cursor or Codex session — hooks POST to
http://127.0.0.1:47611/eventwith the same 200 ms timeout as in dev.
The release build embeds the Vite UI; no localhost:5173 process is required. Rebuild with npm run app:build after code changes.
Every overlay launch writes a JSONL trace under:
- Windows:
%LOCALAPPDATA%\Glint\logs\(e.g.C:\Users\<you>\AppData\Local\Glint\logs\) - macOS/Linux fallback:
~/.glint/logs/
Per-run file: glint-<run_id>.jsonl (one file per time you start the app).
On startup the console prints the exact path: Glint session logs: …
Disable (optional): $env:GLINT_LOG = "0" before launch.
What each line type records
type |
When | Use for |
|---|---|---|
run_start |
App launch | version, exe path, log file path |
hook_event |
Every hook POST | Compare AI vs UI — see below |
snapshot |
After UI update | Full pill/hover state sent to the frontend |
hook_event fields (AI vs what you see)
| Field | Meaning |
|---|---|
ai.tool |
Raw tool invocation — e.g. Shell command, Read path, Task description |
ai.label_from_hook |
Label overlay derives from that hook (same rules as the pill) |
ui_shown.pill |
Exact pill text after this event |
ui_shown.status |
working / done / … |
ui_shown.hover_top_activity |
Top line in the hover activity feed |
pill_matches_ai_label |
false when pill text ≠ derived label (refinement signal) |
payload |
Full hook JSON from Cursor/Codex |
snapshot fields
Each session includes currentAction, status, and the last 5 recentActivity lines (what the hover panel shows).
Logging uses a background thread so hooks stay within the 200 ms budget.
Same as Run standalone: npm run app:build from apps\overlay.
overlay-app/
Cargo.toml # workspace
apps/
hook/ # overlay-hook.exe
src/main.rs
overlay/ # Tauri app
src/ # React frontend
src-tauri/ # Rust core + Tauri config
[features]
codex_hooks = true
[[hooks.SessionStart]]
overlay_managed = true
[[hooks.SessionStart.hooks]]
type = "command"
command = '"<abs path>\overlay-hook.exe" SessionStart'
# ... PreToolUse, PostToolUse, UserPromptSubmit, StopThe overlay_managed = true marker is what disconnect uses to find and remove only our entries; user-authored hook entries are preserved.
User-level ~/.cursor/hooks.json — nine events: sessionStart, sessionEnd, stop, preToolUse, postToolUse, beforeSubmitPrompt, afterFileEdit, subagentStart, subagentStop. Each entry is { "command": "<abs path>/overlay-hook.exe", "overlay_managed": true }. The hook strips a leading UTF-8 BOM on Windows stdin, reads hook_event_name from JSON (camelCase), and session.rs normalizes to the same internal event names as Codex. Multitask / background subagents: subagentStop does not mark Done (parent may still be working); sessionEnd and stop do.
User-level ~/.claude/settings.json — nested schema: hooks → EventName → [matcher groups] → { hooks: [...] }. We install async command hooks for: SessionStart, SessionEnd, UserPromptSubmit, PreToolUse, PostToolUse, Stop, StopFailure, SubagentStart, SubagentStop. Each handler is { "type": "command", "command": "<abs path>/overlay-hook.exe", "async": true, "overlay_managed": true }. Claude sends PascalCase hook_event_name and session_id; transcript_path under .claude/projects/ identifies Claude sessions (so they are not confused with Codex).
| Area | Codex | Cursor |
|---|---|---|
| Session id | session_id |
conversation_id (same value on sessionStart) |
| Project root | cwd |
cwd or workspace_roots[0] |
| Shell tool | Bash |
Shell |
| File edit tool | apply_patch |
Write + afterFileEdit |
| Tool output field | tool_response |
tool_response or tool_output |
| Turn id | turn_id |
generation_id |
| Stop | last_assistant_message |
status: completed / aborted / error |
| Area | Claude Code |
|---|---|
| Session id | session_id |
| Detect app | transcript_path contains .claude/projects/ |
| Project root | cwd |
| Shell tool | Bash |
| File edit tools | Write, Edit (PostToolUse) |
| Stop | last_assistant_message |
| Stop failure | StopFailure + error → errored |
| Model | model on SessionStart |
cargo tauri devlaunches a translucent always-on-top window in the chosen corner of the primary monitor with the Win11 acrylic surface.- Tray icon shows up;
Quitexits cleanly;Settings…opens settings window. - Toggling Connect Codex / Connect Cursor / Connect Claude writes managed hook entries (with backup); disconnect removes only
overlay_managedentries. - With Codex, Cursor, or Claude Code running and a fresh prompt, a session dot appears within about a second of the first hook firing.
- As the agent works, the primary line updates (
Editing X,Running: Y) and elapsed time ticks; the hover card shows activity lines when tools run. - On
Stop, the row shows Done styling with diff scope when available; the hover card lists touched files or an assistant summary (Codex) or status-based Done copy (Cursor). - Open Codex / Open Cursor / Open Claude / Dismiss in the hover card focus the agent or acknowledge Done; acknowledged sessions drop off the fleet after the delay.
- Killing
overlay-app.exemid-session does not block the agent (hook POST times out in 200ms). - Single-instance lock prevents a second copy from launching.
- Project-level
.cursor/hooks.json(user-level only today). - Project-level
.claude/settings.json(user-level only today). - Persisting corner and opacity to disk across restarts (
tauri-plugin-storeis present but not fully wired). - Stall detection, cost meter, sound alerts, installer, auto-update.
- Settings window chrome refresh (borderless dark window) per ROADMAP.
Codex reads ~/.codex/config.toml at startup; Cursor watches ~/.cursor/hooks.json on save but a full restart is safest after first connect; Claude Code reads ~/.claude/settings.json at startup — restart after first connect. After connecting or disconnecting in Settings, restart the relevant app.