A tiny Rust command wrapper that pushes the result of any command to your phone via Pushover.
notify + bird → a carrier pigeon. When the command exits, the pigeon takes off.
Languages: English · 简体中文 · 繁體中文
Long-running tasks (builds, tests, training jobs, deploys, rsync) still need someone to notice when they finish. notibird turns any command into “I'll tap your phone when I'm done” — go do something else.
cargo install --path .
# or: cargo install --git https://github.com/wangyuyan-agent/notibirdFirst, grab Pushover credentials:
export PUSHOVER_TOKEN=your_app_token
export PUSHOVER_USER=your_user_keyThen wrap any command:
# Basic: push when it finishes
notibird -- cargo build --release
# Only on failure (success stays silent)
notibird --only-on-fail -- make test
# Only if it ran for ≥ 60 s (skip short noise)
notibird --min-duration 60 -- rsync -av src/ dst/
# Tag the host so multi-machine pushes stay readable
notibird --title-prefix mac-mini -- long-job.sh
# High priority (bypasses silent mode on the phone)
notibird --priority 1 -- ./deploy.sh prod
# Force a language (en / zh-CN / zh-TW)
notibird --lang zh-TW -- cargo buildThe leading
--is clap's separator: everything after it is treated as the wrapped command and not parsed as a flag. Always include it to avoid conflicts with notibird's own options.
| Flag | Description | Default |
|---|---|---|
--only-on-fail |
Notify only when the command exits non-zero | false |
--min-duration <SECS> |
Notify only when duration ≥ N seconds | 0 |
--title-prefix <PREFIX> |
Prepend a prefix to the notification title | none |
--priority <N> |
Pushover priority (-2..2) |
none |
--lang <CODE> |
Notification language — en / zh / zh-CN / zh-TW |
auto (from $LANG) |
PUSHOVER_TOKEN(required) — Pushover application API tokenPUSHOVER_USER(required) — Pushover user keyLANG/LC_ALL— auto-detects language:zh_TW/zh-Hant→ Traditional, any otherzh*→ Simplified, otherwise English
notibird propagates the wrapped command's exit code. If the process fails to spawn at all, it exits 127.
All user-facing strings live in locales/app.yml, loaded at compile time by rust-i18n. Adding another language takes three steps:
- Add a new column (e.g.
ja:) to every entry inlocales/app.yml. - Add a
Lang::Javariant tosrc/lang.rs(parse,detect,code). - Rebuild — no runtime code changes needed.
MIT
🕊️ Pigeons always land.