pi-notifi
Pi extension that sends focus-aware desktop notifications when pi finishes a task.
Package details
Install pi-notifi from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-notifi- Package
pi-notifi- Version
0.1.5- Published
- May 20, 2026
- Downloads
- not available
- Author
- kaioqb
- License
- unknown
- Types
- extension
- Size
- 24.5 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./index.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-notifi
A focus-aware desktop notification package for pi. It sends a notification when an interactive pi task finishes, but skips the notification if the tmux window containing that pi agent is already visible in Hyprland.
Notifications include a Focus action that jumps back to the originating pi
agent by restoring the saved Hyprland/Ghostty/tmux target.
This package is intentionally developed for an Arch + Hyprland + Ghostty + tmux + dunst workflow. If your setup differs, copy/fork it and adapt the small focus script.
Requirements
- Linux with Hyprland
- Ghostty
- tmux
- dunst or another notification daemon compatible with
notify-sendactions notify-sendfromlibnotifydunstctlif using the example keybindsjq
On Arch:
sudo pacman -S libnotify dunst jq
Your pi shell should be running inside tmux, and that tmux client should be inside a Hyprland-managed Ghostty window.
Install
From npm, once published:
pi install npm:pi-notifi
From git:
pi install git:github.com/<you>/pi-notifi
For a one-off test without installing:
pi -e git:github.com/<you>/pi-notifi
For local development from this checkout:
pi -e /absolute/path/to/pi-notifi
The package manifest loads:
index.ts
No manual symlink is required. The extension invokes the packaged focus helper at:
scripts/notifi-focus
My dunst / Hyprland setup
Hyprland binds:
bind = SUPER, X, exec, dunstctl close
bind = SUPER, N, exec, dunstctl action
Dunst mouse behavior:
mouse_left_click = do_action, close_current
mouse_right_click = close_current
Behavior:
SUPER X/ right click: close the current notification without action.SUPER N/ left click: invoke the notification action. Dunst closes actioned notifications automatically.- For notifi notifications, the action jumps to the Ghostty/tmux location that produced that specific notification.
Commands
Inside pi:
/notifi status
/notifi test
/notifi on|enable
/notifi off|disable
on / off are persisted into the current pi session.
Configuration
Configuration is read from the first valid JSON file that exists:
<project>/.pi/notifi.json~/.pi/agent/notifi.json~/.pi/agent/extensions/notifi.json
Example:
{
"disabled": false,
"urgency": "normal",
"expireTime": 0,
"notifyOnError": true
}
Available JSON fields:
| Field | Default | Description |
|---|---|---|
disabled |
false |
Start disabled |
title |
<tmux-session>:<window-index> or pi |
Notification title |
body |
Task Finished / Task Failed |
Notification body |
urgency |
normal / critical |
notify-send urgency |
expireTime |
0 |
notify-send expire time in ms; 0 requests persist until dismissed |
notifyOnError |
true |
Notify when a task fails |
Environment variables with the old PI_NOTIFI_* names override JSON for quick
one-off changes. Invalid JSON config files are ignored so a bad config does not
break notification delivery.
Behavior
Notification is suppressed only when all of these are true:
- pi is running inside tmux.
- notifi identifies the tmux session/window containing the pi pane.
- an attached tmux client is currently viewing that same tmux window.
- that tmux client maps through its process tree to a Hyprland window.
- that Hyprland window is on a workspace visible on a monitor.
Pane focus does not matter for notification suppression. If the pi pane is anywhere in the visible tmux window, no notification is sent. Notification actions still try to focus the original pi pane after switching to the saved tmux session/window.
If the tmux window is not visible, notifi sends a persistent notification with a
Focus action:
<title: tmux-session:window-index>
<body: Task Finished | Task Failed>
<action: Focus>
Headless/print-mode pi runs do not notify.
Action target cache
Each notification gets a unique UUID target id. The extension writes that notification's jump target to:
${XDG_CACHE_HOME:-~/.cache}/notifi/targets/<target-id>.json
Each notification action captures its own target id, so multiple concurrent pi agents and long-lived notifications do not overwrite each other.
scripts/notifi-focus <target-id>:
- validates the target id
- reads the target file
- deletes the consumed target file
- prunes target files older than 24 hours
- switches Hyprland to the saved Ghostty workspace/window when possible
- switches tmux to the saved session/window
- focuses the original pi pane if it still exists
If no existing Ghostty/tmux client can be mapped back to Hyprland but the tmux session/window still exists, the action opens Ghostty attached to that tmux session/window. If the tmux session/window no longer exists, it exits successfully and does nothing.
Target files for notifications dismissed without action are cleaned up the next time a notifi action is consumed.
Edge cases
- If multiple Ghostty windows are attached to tmux, notifi prefers one already viewing the target window, then one in the target session, then any usable tmux client it can map back to Hyprland.
- If no saved/reusable Ghostty/Hyprland window exists, notifi falls back to opening Ghostty attached to the saved tmux session/window.
- If the saved tmux session or window no longer exists, the action exits successfully and does nothing.
- If the saved tmux pane no longer exists, the action still switches to the saved tmux window and skips pane focus.
- If the target file is missing, malformed, or older than 24 hours when pruning runs, the action exits successfully and/or removes stale metadata.