You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+63-18Lines changed: 63 additions & 18 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -16,7 +16,7 @@
16
16
| Codex | ✅ *(experimental)*|
17
17
| Any hooks-capable agent | ✅ — point it at `notify.sh`|
18
18
19
-
**Platforms:** macOS (native banners + click-to-focus) · Linux (PulseAudio / ALSA / libnotify) · Windows (Git Bash / WSL)
19
+
**Platforms:** macOS — full app with panel, click-to-focus banners, auto-update, quota tracking, voice. Linux (PulseAudio / ALSA / libnotify) and Windows (Git Bash / WSL) get audio + basic notifications via `notify.sh` only.
20
20
21
21
## Install
22
22
@@ -28,9 +28,9 @@ cd stack-nudge
28
28
./install.sh
29
29
```
30
30
31
-
The installer auto-detects which agents you have configured (`~/.claude`, `~/.cursor`, `~/.gemini`) and wires up their hooks.
31
+
The installer auto-wires hooks for **Claude Code**(`~/.claude/settings.json`) and **Cursor** (`~/.cursor/hooks.json`). Gemini CLI and Codex are supported through the same `notify.sh` entry-point, but their hooks must be wired manually — see [Manual setup](#manual-setup) below.
32
32
33
-
On macOS it also installs the native `stack-nudge.app` for click-to-focus banners. Without the binary, macOS falls back to `osascript` notifications (no click-to-focus).
33
+
On macOS it also installs the native `stack-nudge.app`, which provides the floating panel, click-to-focus banners, auto-update, and quota tracking. The first launch will show a welcome screen with a "Grant permissions" button — taking that step up-front unlocks click-to-focus and the keystroke-based "Allow" approvals.
34
34
35
35
## How it works
36
36
@@ -72,18 +72,15 @@ Add that to your shell profile.
72
72
73
73
### Keyboard-native panel (macOS)
74
74
75
-
If you'd rather not click banners with the mouse, stack-nudge can run a small floating panel that you summon with a hotkey. It has three tabs — **Events**, **Sessions**, and **Settings** — and is fully keyboard-driven.
75
+
If you'd rather not click banners with the mouse, stack-nudge runs a small floating panel that you summon with a hotkey. It has four tabs — **Events**, **Sessions**, **Usage**, and **Settings** — and is fully keyboard-driven.
76
76
77
-
Enable it in `~/.stack-nudge/config`:
77
+
The panel is installed and registered as a launchd agent by `./install.sh` — no opt-in needed. To run quietly without macOS banners (panel-only):
78
78
79
79
```bash
80
-
STACKNUDGE_PANEL=true
81
80
STACKNUDGE_BANNER=false # optional — suppress macOS banners when using the panel
82
81
```
83
82
84
-
Default hotkey is `cmd+opt+n`. Hit it from anywhere to summon the panel; hit it again while focused to hide. Switch tabs with `Cmd+1` (Events), `Cmd+2` (Sessions), `Cmd+3` (Settings) — or click them.
85
-
86
-
The panel registers a launchd agent so it starts at login when enabled. Banner and panel can run together, alone, or both off — the sound and voice still fire as passive signals.
83
+
Default hotkey is `cmd+opt+n`. Hit it from anywhere to summon the panel; hit it again while focused to hide. Switch tabs with `Cmd+1` (Events), `Cmd+2` (Sessions), `Cmd+3` (Usage), `Cmd+4` (Settings) — or click them. Banner and panel can run together, alone, or both off — the sound and voice still fire as passive signals.
87
84
88
85
#### Events tab
89
86
@@ -111,9 +108,31 @@ Live list of running agent processes (`claude`, `gemini`, `codex` — including
111
108
|`⌫`| Send SIGTERM to the agent process |
112
109
|`Esc`| Hide the panel |
113
110
111
+
#### Usage tab
112
+
113
+
Reachable from the tab strip or `Cmd+3`. Renders your Claude Code subscription quota — the same numbers `claude /usage` shows in the terminal — but always available without typing the command:
114
+
115
+
-**Current session** (5-hour rolling window)
116
+
-**Current week (all models)**
117
+
-**Current week (Opus only)***(when your plan has the tier)*
118
+
-**Current week (Sonnet only)***(when your plan has the tier)*
119
+
120
+
Bars are color-coded: green below 50%, yellow 50–80%, red 80%+. Reset times shown per tier.
121
+
122
+
Data is fetched from the same endpoint Claude Code's own statusline uses (`/api/oauth/usage`), reading your OAuth token from the macOS Keychain. **The first time stack-nudge polls you'll see a keychain dialog — click "Always Allow"** to grant access (one-time, per release).
123
+
124
+
Polls every 60 seconds while the panel is visible, or every 5 minutes (`STACKNUDGE_USAGE_POLL_MIN`) in the background.
125
+
126
+
#### Threshold-crossing notifications
127
+
128
+
When any tier reaches your configured threshold, stack-nudge fires a banner — *"Weekly quota at 85% — resets May 17"* — once per period per tier, so you get a heads-up before hitting the cap. Configure in Settings → Usage:
Reachable from the tab strip or `Cmd+3`. Keyboard-driven rows for hotkey, banner/voice toggles, sound picks (with preview-on-cycle), voice picker (with preview-on-cycle using a random conversational phrase), speed, and shortcuts to the permissions checker, config file, and quit.
135
+
Reachable from the tab strip or `Cmd+4`. Keyboard-driven rows for hotkey, banner/voice toggles, sound picks (with preview-on-cycle), voice picker (with preview-on-cycle using a random conversational phrase), speed, quota alert config, and shortcuts to the permissions checker, config file, phrase editor, and quit.
117
136
118
137
| Key | Action |
119
138
|-----|--------|
@@ -164,6 +183,27 @@ stack-nudge's apps are **ad-hoc signed**, so every rebuild produces a new cdhash
164
183
165
184
If approval has stopped working after a rebuild, hit **Reset & prompt** in the permissions checker. It runs `tccutil reset`, then triggers a fresh dialog bound to the current cdhash.
166
185
186
+
### Auto-update
187
+
188
+
stack-nudge polls GitHub Releases on launch and every 6 hours. When a newer release exists, the Settings tab gets a small accent dot and an "Update available · vX.Y.Z" row at the top of the list. Click it (or press Enter while it's selected) for a confirmation view with the release notes, then "Update Now" runs the install:
189
+
190
+
1. Clones the repo to `/tmp`
191
+
2. Runs `install.sh` against the cloned source (rebuild + replace `~/Applications/stack-nudge.app` + reload launchd)
192
+
3. After completion, the panel auto-quits; launchd brings up the new bundle
193
+
4. The new bundle's first launch shows a welcome-style "Updated to vX.Y.Z" screen with the release notes
194
+
195
+
While the StackOne stack-nudge repo is private the auto-updater falls back to your local `gh` CLI auth (`gh api`) to read the release metadata; the in-app git clone uses your existing git credentials (keychain or SSH). Org members with `gh` configured see no friction.
196
+
197
+
### Phrase editor
198
+
199
+
The phrase pools that power [Voice notifications](#voice-notifications) can be customised in-app. Settings → "Edit phrases…" opens a keyboard-driven editor where you can:
200
+
201
+
- Toggle individual built-in phrases on or off (`Space`)
202
+
- Add your own custom phrases (typed inline, `Enter` to commit)
203
+
- Remove custom phrases (`⌫`)
204
+
205
+
Per-pool customisations are stored in `~/.stack-nudge/phrases.user.json` and merged with the built-in pools at notification time. Disable a built-in phrase you find too cheery, add ones in your own voice — the same random-selection logic still applies.
206
+
167
207
### Voice notifications
168
208
169
209
stack-nudge uses [stackvox](https://github.com/StackOneHQ/stackvox), an offline Kokoro-82M TTS engine that speaks notifications aloud with ~13 ms latency. `./install.sh` pip-installs it from PyPI into an isolated venv at `~/.stack-nudge/venv` — no separate setup needed.
@@ -215,10 +255,16 @@ The Settings tab exposes the same picks with audio preview on each change.
215
255
## Uninstall
216
256
217
257
```bash
258
+
git pull # if you cloned a while back — older uninstall.sh lacks hook cleanup
218
259
./uninstall.sh
219
260
```
220
261
221
-
Removes the hooks from each agent's config and deletes `~/.stack-nudge/`.
262
+
Cleans up:
263
+
264
+
- Hook entries in `~/.claude/settings.json`, `~/.cursor/hooks.json`, and `~/.gemini/settings.json`
265
+
- The launchd agents (`com.stackonehq.stack-nudge`, `…-daemon`)
266
+
-`~/Applications/stack-nudge.app`
267
+
-`~/.stack-nudge/` (including the Python venv and `notify.sh`)
222
268
223
269
## Manual setup
224
270
@@ -240,22 +286,21 @@ Every supported agent just needs a hook that runs `notify.sh <agent-name> <event
240
286
## Development
241
287
242
288
```bash
243
-
make build # builds both .app bundles into build/
289
+
make build # builds stack-nudge.app into build/
244
290
make install # full install (build + copy + register hooks + launchd)
make reload # rebuild + replace installed app + refresh notify.sh + bounce the daemon
246
292
make dev # watch sources; auto-reload on .swift / Info.plist / notify.sh / phrase changes
247
-
make uninstall # remove apps, hooks, launchd agents, ~/.stack-nudge/
293
+
make uninstall # remove app, hooks, launchd agents, ~/.stack-nudge/
248
294
```
249
295
250
296
`make dev` is the inner-loop tool — leave it running in another terminal, save a Swift file or `notify.sh`, and the daemon bounces with the new build in ~2 seconds.
251
297
252
298
Source layout:
253
299
254
-
-`notifier/` — the transient banner-renderer that fires per nudge and exits
255
-
-`panel/` — the persistent floating-panel daemon (hotkey, NSPanel, socket listener, menu bar, sessions list, settings, permissions window)
256
-
-`shared/` — code shared by both binaries (currently `AppActivator.swift`)
300
+
-`panel/` — the single persistent `stack-nudge.app` binary: hotkey, floating NSPanel, socket listener for incoming events, macOS banner posting via `UNUserNotificationCenter`, sessions list, settings, permissions window, auto-updater, quota probe
301
+
-`shared/` — code shared with the standalone Linux/Windows surfaces (currently `AppActivator.swift`)
257
302
-`phrases/` — per-language voice phrase pools sourced by `notify.sh` at hook time
258
-
-`notify.sh` — the shell entry-point CC/Cursor/Gemini hooks invoke; routes events to banner / panel / voice surfaces
303
+
-`notify.sh` — the shell entry-point CC/Cursor/Gemini hooks invoke; on macOS posts events to the running app via Unix-domain socket, on Linux/Windows handles audio + libnotify directly
259
304
260
305
Swift compiled with `swiftc` directly. No Xcode, no SPM, no dependencies.
0 commit comments