pi-notifier
Lightweight macOS desktop notifications for pi when waiting for input or decision.
Package details
Install pi-notifier from npm and Pi will load the resources declared by the package manifest.
$ pi install npm:pi-notifier- Package
pi-notifier- Version
0.1.1- Published
- Apr 7, 2026
- Downloads
- 267/mo · 7/wk
- Author
- zheermao
- License
- MIT
- Types
- extension
- Size
- 19.3 KB
- Dependencies
- 0 dependencies · 1 peer
Pi manifest JSON
{
"extensions": [
"./extensions/notifier.ts"
]
}Security note
Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.
README
pi-notifier
Lightweight macOS desktop notifications for pi.
When pi finishes processing and is ready for your next input, you'll get a native macOS notification. Perfect for when pi is running a long task and you're working in another window.
Current notification format for waitingForInput:
- title:
pi-notification-<session_info> - content: pi 最后一轮输出内容(会自动压缩空白并截断)
Features
- Native macOS notifications via AppleScript (
osascript) - Telegram bot notifications via configurable bot token + chat ID
- Configurable sound - choose from system sounds like Glass, Hero, Ping, Submarine
- Deduplication - prevents notification spam with configurable minimum interval
- Zero dependencies - lightweight, no runtime dependencies required
- Per-project config - override global settings per project
Installation
Quick Test
Load temporarily without installing:
pi --extension /path/to/pi-notifier/extensions/notifier.ts
Install as pi Package
Globally:
pi install /path/to/pi-notifier
Project-local (shareable with your team):
pi install -l /path/to/pi-notifier
Configuration
Create a config file at ~/.pi/agent/pi-notifier.json (global) or .pi/pi-notifier.json (project).
Project config overrides global config.
Example Configuration
{
"enabled": true,
"desktop": {
"enabled": true
},
"telegram": {
"enabled": false,
"botToken": "123456:your-bot-token",
"chatId": "123456789"
},
"sound": {
"enabled": true,
"name": "Glass"
},
"events": {
"waitingForInput": true,
"waitingForDecision": true
},
"dedupe": {
"minIntervalMs": 2000
},
"messages": {
"waitingForInput": {
"title": "Pi",
"body": "Ready for input"
}
}
}
注意:
waitingForInput的实际通知标题和正文现在会动态生成。配置里的messages.waitingForInput.title/body仅作为无法获取最后一轮输出时的兜底文案。
Configuration Options
| Option | Type | Default | Description |
|---|---|---|---|
enabled |
boolean | true |
Master switch for all notifications |
desktop.enabled |
boolean | true |
Enable/disable desktop notifications |
telegram.enabled |
boolean | false |
Enable/disable Telegram bot notifications |
telegram.botToken |
string | undefined |
Telegram bot token from BotFather |
telegram.chatId |
string | undefined |
Target chat ID / user ID / group ID |
telegram.apiBaseUrl |
string | "https://api.telegram.org" |
Optional Telegram API base URL override |
sound.enabled |
boolean | true |
Enable/disable notification sound |
sound.name |
string | "Glass" |
System sound name (Glass, Hero, Ping, Submarine, etc.) |
events.waitingForInput |
boolean | true |
Notify when pi is ready for input |
events.waitingForDecision |
boolean | true |
Notify when waiting for user decision (future use) |
dedupe.minIntervalMs |
number | 2000 |
Minimum ms between notifications |
messages.waitingForInput.title |
string | "Pi" |
Fallback title only; normal waitingForInput notifications use pi-notification-<session_info> |
messages.waitingForInput.body |
string | "Ready for input" |
Fallback body only; normal waitingForInput notifications use the last Pi output |
Commands
Test Notification
Send a test notification to verify your configuration (desktop and/or Telegram):
/pi-notifier-test
/pi-notifier-test decision
Show Status
Display current configuration and effective settings:
/pi-notifier-status
How It Works
waitingForInput
Triggered when pi's agent finishes processing (via the agent_end event). This is the primary use case: you start a long-running task, switch to another app, and get notified when pi is ready for your next instruction.
For this event, the notifier now builds the message dynamically:
- title =
pi-notification-<session_info> - body = the last assistant output from Pi
If no assistant output can be extracted, it falls back to the configured messages.waitingForInput.body value.
waitingForDecision
This release includes the configuration and message structure for decision notifications, but does not automatically intercept other extensions' dialogs. Future versions may provide a helper function that extensions can call when awaiting user decisions.
Sound Notes
Sound playback is best-effort. macOS may ignore the requested sound based on:
- System notification permissions
- Notification Center settings for the app
- Whether the sound name is recognized
Common system sounds: Glass, Hero, Ping, Submarine, Pop, Purr, Blow, Bottle
Telegram Setup
- Create a bot with @BotFather and copy the bot token
- Start a chat with the bot (or add it to a group)
- Obtain the target
chatId- personal chat usually is your numeric user ID
- group chat usually is a negative number
- Add the config:
{
"telegram": {
"enabled": true,
"botToken": "123456:your-bot-token",
"chatId": "123456789"
}
}
When enabled, notifier sends:
pi-notification-<session_info>
<last assistant output>
Limitations
- Desktop notifications are macOS only (uses AppleScript)
- Telegram notifications require outbound network access and valid bot permissions
- No click-to-focus action (notification is informational only)
- Does not globally intercept all extension dialogs
Requirements
- macOS
- pi installed
License
MIT
Acknowledgments
Inspired by the notify.ts example from the pi-mono project.