Skip to content

Commit 669e7c3

Browse files
committed
fix badge priority, update CC docs
1 parent c8b9291 commit 669e7c3

3 files changed

Lines changed: 59 additions & 16 deletions

File tree

docs/docs/claude-code.mdx

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,16 @@ id: "claude-code"
44
title: "Claude Code Integration"
55
---
66

7-
# Claude Code Tab Badges
7+
import { VersionBadge } from "@site/src/components/versionbadge";
8+
9+
# Claude Code Tab Badges <VersionBadge version="v0.14.2" />
810

911
When you run multiple Claude Code sessions in parallel — one per feature, one per repo, a few long-running tasks — it gets hard to know which tabs need your attention without clicking through each one. Wave's badge system solves this: hooks in Claude Code write a small visual indicator to the tab header whenever something important happens, so you can see at a glance which sessions are waiting, done, or in trouble.
1012

13+
:::info
14+
tl;dr You can copy and paste this page directly into Claude Code and it will help you set everything up!
15+
:::
16+
1117
## How it works
1218

1319
Claude Code supports [lifecycle hooks](https://code.claude.com/docs/en/hooks) — shell commands that run automatically at specific points in a session. Wave's `wsh badge` command sets or clears a visual indicator on the current block or tab. By wiring these together, you get ambient awareness across all your sessions without watching any of them.
@@ -38,6 +44,15 @@ Add the following to `~/.claude/settings.json`. If you already have a `hooks` ke
3844
"command": "wsh badge bell-exclamation --color '#e0b956' --priority 20 --beep"
3945
}
4046
]
47+
},
48+
{
49+
"matcher": "elicitation_dialog",
50+
"hooks": [
51+
{
52+
"type": "command",
53+
"command": "wsh badge message-question --color '#e0b956' --priority 20 --beep"
54+
}
55+
]
4156
}
4257
],
4358
"Stop": [
@@ -49,43 +64,62 @@ Add the following to `~/.claude/settings.json`. If you already have a `hooks` ke
4964
}
5065
]
5166
}
67+
],
68+
"PreToolUse": [
69+
{
70+
"matcher": "AskUserQuestion",
71+
"hooks": [
72+
{
73+
"type": "command",
74+
"command": "wsh badge message-question --color '#e0b965' --priority 20 --beep"
75+
}
76+
]
77+
}
5278
]
5379
}
5480
}
5581
```
5682

5783
That's it. Restart any running Claude Code sessions for the hooks to take effect.
5884

85+
:::warning Known Issue
86+
There is a known issue in Claude Code where `Notification` hooks may be delayed by several seconds before firing. This delay is unrelated to Wave — it occurs in Claude Code itself. See [#5186](https://github.com/anthropics/claude-code/issues/5186) and [#19627](https://github.com/anthropics/claude-code/issues/19627) for details.
87+
:::
88+
5989
## What each hook does
6090

61-
### Permission prompt — `circle-exclamation` gold, priority 20
91+
### Permission prompt — `bell-exclamation` gold, priority 20
6292

6393
Claude Code occasionally needs your approval before it can continue — to run a command, write a file outside the project, or use a tool that requires explicit permission. When it hits one of these, it stops and waits. Without a signal, you might not notice for minutes.
6494

6595
This hook fires on the `permission_prompt` notification type and sets a high-priority gold badge with an audible beep. Priority 20 means it beats any other badge on that tab, so a waiting session always surfaces above a finished one.
6696

6797
When you click into the tab and approve or deny the request, the badge clears automatically.
6898

69-
### Session complete — `circle-check` green, priority 10
99+
### Session complete — `check` green, priority 10
70100

71101
When Claude Code finishes responding, this hook sets a green check badge. It's a low-key signal: glance at the tab bar, see which sessions are done, review their output in whatever order you like.
72102

73-
The `stop_hook_active` guard in the command prevents the hook from firing recursively if you have other `Stop` hooks that keep Claude running.
103+
### AskUserQuestion — `message-question` gold, priority 20
104+
105+
When Claude Code uses the `AskUserQuestion` tool, it's paused and waiting for you to respond before it can proceed. This `PreToolUse` hook fires just before that tool call and sets the same high-priority gold badge as the permission prompt.
106+
107+
`PreToolUse` hooks can match any tool by name, so you can add badges for other tools as well — for example, to get a signal whenever Claude runs a shell command (`Bash`) or edits a file (`Edit`). Any tool name Claude Code supports can be used as a matcher.
74108

75109
## Choosing your own icons and colors
76110

77-
Icon names are [Font Awesome](https://fontawesome.com/icons) icon names without the `fa-` prefix. Colors are any valid CSS color — named colors like `gold` and `green`, hex values like `#f59e0b`, or anything else CSS accepts.
111+
Icon names are [Font Awesome](https://fontawesome.com/icons) icon names without the `fa-` prefix. Colors are any valid CSS color — hex values, named colors, or anything else CSS accepts.
78112

79-
Some alternatives to consider:
113+
Some icon and color ideas:
80114

81115
| Situation | Icon | Color |
82116
|-----------|------|-------|
83-
| Permission needed | `circle-exclamation` | `gold` |
84-
| Session complete | `circle-check` | `green` |
85-
| Custom high-priority alert | `triangle-exclamation` | `red` |
86-
| Neutral / informational | `circle-info` | `steelblue` |
117+
| Custom high-priority alert | `triangle-exclamation` | `#FF453A` |
118+
| Blocked / waiting on input | `hourglass-half` | `#FF9500` |
119+
| Neutral / informational | `circle-info` | `#429DFF` |
120+
| Background task running | `spinner` | `#00FFDB` |
87121

88-
To target a specific block or tab instead of the current one, add `-b <blockid>` or `-b tab`. See the [`wsh badge` reference](/reference/wsh-cmd/badge) for all available flags.
122+
See the [`wsh badge` reference](/reference/wsh-cmd/badge) for all available flags.
89123

90124
## Adjusting priorities
91125

frontend/app/store/badge.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,7 @@ function getTabBadgeAtom(tabId: string, env?: TabBadgesEnv): Atom<Badge[]> {
123123
}
124124
const tabOref = WOS.makeORef("tab", tabId);
125125
const tabBadgeAtom = getBadgeAtom(tabOref);
126-
const tabAtom =
127-
env != null ? env.wos.getWaveObjectAtom<Tab>(tabOref) : WOS.getWaveObjectAtom<Tab>(tabOref);
126+
const tabAtom = env != null ? env.wos.getWaveObjectAtom<Tab>(tabOref) : WOS.getWaveObjectAtom<Tab>(tabOref);
128127
rtn = atom((get) => {
129128
const tab = get(tabAtom);
130129
const blockIds = tab?.blockids ?? [];
@@ -213,7 +212,13 @@ function setupBadgesSubscription() {
213212
}
214213
return;
215214
}
216-
globalStore.set(curAtom, data.clear ? null : (data.badge ?? null));
215+
if (data.clear) {
216+
globalStore.set(curAtom, null);
217+
} else if (data.badge != null) {
218+
const existing = globalStore.get(curAtom);
219+
const candidates = existing != null ? [existing, data.badge] : [data.badge];
220+
globalStore.set(curAtom, sortBadges(candidates)[0]);
221+
}
217222
},
218223
});
219224
}

pkg/wcore/badge.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,12 @@ func setBadge(oref waveobj.ORef, data baseds.BadgeEvent) {
9494
delete(globalBadgeStore.transient, orefStr)
9595
log.Printf("badge store: badge cleared: oref=%s\n", orefStr)
9696
} else {
97-
globalBadgeStore.transient[orefStr] = *data.Badge
98-
log.Printf("badge store: badge set: oref=%s badge=%+v\n", orefStr, *data.Badge)
97+
incoming := *data.Badge
98+
existing, hasExisting := globalBadgeStore.transient[orefStr]
99+
if !hasExisting || incoming.Priority > existing.Priority || (incoming.Priority == existing.Priority && incoming.BadgeId > existing.BadgeId) {
100+
globalBadgeStore.transient[orefStr] = incoming
101+
log.Printf("badge store: badge set: oref=%s badge=%+v\n", orefStr, incoming)
102+
}
99103
}
100104
}
101105

0 commit comments

Comments
 (0)