pi-focus-bell
Rings the terminal bell when a pi session finishes and is waiting on you, staying quiet when you're already looking at its tmux pane.
Package details
Install pi-focus-bell from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-focus-bell- Package
pi-focus-bell- Version
0.1.0- Published
- Jul 9, 2026
- Downloads
- 24/mo · 24/wk
- Author
- thmtz
- License
- MIT
- Types
- extension
- Size
- 8.9 KB
- Dependencies
- 0 dependencies · 0 peers
Pi manifest JSON
{
"extensions": [
"./focus-bell.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-focus-bell
Rings your terminal bell when a pi session finishes and is waiting on you. Leave a session running, go do something else, and get pulled back the moment it needs input instead of babysitting it.
The core behavior is simple: on agent_end (pi has finished a turn and is idle), it emits a terminal bell (BEL, \a).
On top of that it is tmux-aware. If the pane running the session is the one you are already looking at, there is nothing to alert you to, so it stays quiet. It only rings when that pane is out of focus. Outside tmux, where focus can't be determined, it rings on every turn end.
Why a bell instead of a desktop notification?
The bell isn't just cosmetic. A raw BEL propagates through the whole stack: tmux forwards it (bell-action any, visual-bell off) up the ssh session to the outer terminal, which turns it into audio. One bell covers the local-terminal, tmux, and remote-over-ssh cases with no per-hop config, and works even where no notification daemon exists. (pi's bundled notify.ts example takes the other route: OSC desktop notifications, fired on every turn regardless of focus.)
Install
pi install npm:pi-focus-bell
Or drop focus-bell.ts directly into your global extensions directory (~/.pi/agent/extensions/), which pi auto-loads.
Requirements for the audio relay
The extension only emits the BEL. For it to become an audible sound over tmux + ssh, the outer layers must be configured to carry and play it:
tmux (.tmux.conf):
set -g bell-action any
set -g visual-bell off
setw -g monitor-bell on
visual-bell off matters: with it on, tmux swallows the audible bell and only flashes the status line.
Your terminal must play a sound on BEL. For example, Ghostty:
bell-features = audio
bell-audio-path = /System/Library/Sounds/Funk.aiff
bell-audio-volume = 0.8
Configuration
Two optional environment variables:
PI_BELL_ALWAYS: if set, skip focus gating and ring on every turn end, even when you're looking at pi's pane.PI_BELL_DEBUG: if set to a file path, append one line per event describing what the extension decided (rang, gated, or failed). Handy for answering "is it even firing?"
PI_BELL_DEBUG=/tmp/pi-bell.log pi
Testing it
The bell only rings when pi's pane is unfocused, so you have to switch away before the turn ends:
- Start
piin a tmux pane. - Give it a prompt that takes a few seconds and hit Enter.
- Immediately switch to another tmux pane or window.
- When pi finishes, the terminal should ring.
If it stays silent while you are looking at pi's pane, that's the focus gate working as intended.
Known limitations
pi computes an internal willRetry flag when a turn ends but does not currently expose it to extension events. So when pi hits a transient error (e.g. a 429) and is about to auto-retry, this extension can't tell that apart from a turn that's genuinely waiting on you, and may ring once during the retry backoff. The clean fix is upstream: pi exposing willRetry on the extension agent_end event.
License
MIT