skill
NotifyBot
A tiny multi-channel notification CLI (Telegram + webhooks) built for AI agents, with searchable send history
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/xm6661885/NotifyBot itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 22, 2026NotifyBot
English | 简体中文
A small, dependency-light command-line tool that lets AI agents (and humans, and shell scripts) send notifications. One command fans a message out to several channels at once — Telegram (text, images, files) and any generic HTTP webhook (text) — and every send is logged to a local SQLite history you can search later.
notify "✅ Deploy finished"
notify --image chart.png "Daily metrics"
notify --file report.pdf "Here's the report"
Table of contents
- Features
- Why it's agent-friendly
- Installation
- Configuration
- Usage
- Send history
- Using NotifyBot from an AI agent
- Command-line reference
- Troubleshooting
- How it works
- License
Features
- Multi-channel fan-out — send to several named channels concurrently; if any selected channel fails, the command fails (non-zero exit), so scripts and agents can detect it.
- Telegram — text, images (with caption) and files (with caption); long text is split automatically; optional per-channel HTTP/SOCKS proxy; automatic retry with exponential backoff on connection/TLS/timeout errors.
- Generic webhooks — configurable URL, method, headers and JSON body with
{{text}}-style templates, so it works with NapCat/OneBot (QQ), Slack-compatible endpoints, Feishu/Lark, DingTalk, ntfy-style services, your own API, etc. (text only). - Channel selection — every enabled channel by default;
--channel(repeatable / comma-separated) to pick specific ones. - Keyword blacklist per channel — skip a channel when the message contains certain keywords.
- Markdown (Telegram) via
--markdown. --text-file— read long or special-character text from a file, avoiding shell quoting problems.- Searchable history — every send (success or failure) is stored in SQLite; query by keyword, date range and channel without touching the network.
- Tiny footprint — a single Python file plus
requests.
Why it's agent-friendly
- One stable, non-interactive command (
notify "...") with meaningful exit codes. - Secrets live in
config.json, never on the command line or in prompts. --text-filesidesteps shell-escaping bugs when an agent generates complex text.--list-channelslets an agent discover available channels without ever printing tokens.- A ready-made agent skill (
skills/notification/SKILL.md) and a drop-in prompt snippet (prompt.txt) are included.
Installation
Requirements: Python 3.8+ and a POSIX shell (Linux/macOS/WSL).
Quick install (recommended)
git clone https://github.com/xm6661885/NotifyBot.git
cd NotifyBot
./setup.sh
setup.sh will create a venv, install requirements.txt, copy config.json.example to config.json if missing, and symlink notify to ~/.local/bin/notify. Make sure ~/.local/bin is on your PATH.
Manual install
git clone https://github.com/xm6661885/NotifyBot.git
cd NotifyBot
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
deactivate
cp config.json.example config.json
# optional: global command
mkdir -p ~/.local/bin
ln -sfn "$(pwd)/notify" ~/.local/bin/notify
The notify wrapper script resolves its own real path (following symlinks) and runs notify.py with the repository's venv, so it works from any directory.
Configuration
Copy config.json.example to config.json and edit it. config.json and history.db are git-ignored — never commit them.
config.json is looked up in the current working directory first, then next to the script. Use -c /path/to/config.json to point elsewhere.
{
"channels": [
{
"name": "telegram_push",
"type": "telegram",
"bot_token": "YOUR_BOT_TOKEN_HERE",
"user_id": "YOUR_USER_ID_HERE",
"proxy": "http://127.0.0.1:7890",
"retry_attempts": 3,
"retry_backoff": 1,
"blacklist": []
},
{
"name": "qq",
"type": "webhook",
"url": "http://127.0.0.1:3009/send_group_msg",
"method": "POST",
"headers": { "Content-Type": "application/json" },
"blacklist": [],
"body": {
"group_id": "123456789",
"message": "{{text}}",
"auto_escape": true
}
}
]
}
Top-level keys
| Key | Description |
|---|---|
channels | List of channel objects. Each needs a unique name. |
Telegram channel ("type": "telegram")
| Key | Description |
|---|---|
bot_token | Bot token from @BotFather. Required. |
user_id | Target chat/user ID. Required. |
proxy | Optional proxy URL, e.g. http://127.0.0.1:7890 or socks5://127.0.0.1:1080. Applies to this channel only. Omit if not needed. |
retry_attempts | Max attempts on connection/TLS/timeout errors (default 3). |
retry_backoff | Initial wait in seconds, doubled each retry (default 1). |
blacklist | Keywords that make this channel skip a message. [] = no filtering. |
enabled | Set false to disable the channel. |
Getting the values
- Bot token — message @BotFather, send
/newbot, follow the prompts, copy the token (looks like123456789:ABCdef...). - User ID — message @userinfobot; it replies with your numeric ID.
- Start the bot — open your new bot in Telegram and press START (or send
/start). A bot cannot message you until you've done this (chat not foundotherwise).
Webhook channel ("type": "webhook")
| Key | Description |
|---|---|
url | Endpoint URL. Required. |
method | HTTP method (default POST). |
headers | Object of request headers. |
body | Request body (object or string). String values anywhere inside it may use templates (below). |
timeout | Seconds (default 30). |
verify | TLS certificate verification (default true). |
blacklist / enabled | Same as Telegram. |
Template placeholders: {{text}}, {{message}}, {{type}}, {{caption}}, {{file}} (and {{path}}). Webhooks only receive text — images/files are skipped for them — and they connect directly (the Telegram proxy and environment proxy settings are not used). A webhook response that reports failure (e.g. "status": "failed" or a non-zero retcode, as OneBot returns) is treated as an error.
Backwards compatibility: the legacy top-level
bot_token/user_id/proxyfields and a top-levelwebhookslist are still read.
Blacklist semantics
Each channel's blacklist is a list of keywords. If the message text (or caption) contains any of them, that channel is skipped for this send (other channels are unaffected). An empty list means nothing is filtered.
Usage
# Text
notify "Hello from the CLI"
# Markdown (Telegram)
notify --markdown "*Bold*, _italic_, \`code\` and [a link](https://example.com)"
# Image / file (Telegram only; webhooks skip them), caption optional
notify --image /path/to/photo.jpg "Look at this"
notify --file /path/to/report.pdf "Monthly report"
# Long or special-character text: use a file
notify --text-file message.txt
notify --image chart.png --text-file caption.txt
# Channels
notify --list-channels # show channels (no secrets)
notify --channel qq "only qq"
notify -C telegram_push -C qq "two channels"
notify -C telegram_push,qq "two channels"
notify --all "every enabled channel"
# Custom config
notify --config /path/to/config.json "hello"
Limits and behaviour:
- Text over 4096 characters is split into multiple messages automatically.
- Image/file captions over 1024 characters are truncated; the overflow is sent as a follow-up text message.
- Telegram limits: images up to 10 MB, files up to 50 MB.
- Success prints
✓ ... sent successfully -> <channels>; failure prints✗ Failed to send ...with the cause and exits non-zero.
In shell scripts
./long_task.sh && notify "✅ Task succeeded" || notify "❌ Task failed"
Send history
Every send (text, photo, document; success or failure) is recorded in history.db (SQLite, created automatically next to notify.py) with timestamp, type, text/caption, file path, channels and status. History commands only read the local database and need no network or config.
notify --history # last 20 sends
notify --history 50 # last 50
notify --search "report" # search text/captions
notify --search "report" --limit 5
notify --since 2026-09-01 --until 2026-09-10 # YYYY-MM-DD or "YYYY-MM-DD HH:MM"
notify --search "report" --since 2026-09-01
notify --history 20 --channel telegram_push # filter by channel
history.db contains your message contents — it is git-ignored; keep it out of version control.
Using NotifyBot from an AI agent
Two ready-made options:
- Agent skill — copy
skills/notification/SKILL.mdinto your agent's skills directory (for Claude Code:~/.claude/skills/notification/SKILL.md). It tells the agent when to notify proactively (task finished, error, report/screenshot produced), how to choose channels, to prefer--text-filefor complex text, and how to search history. Edit the channel table in it to match your ownconfig.json. - Prompt snippet — paste the contents of
prompt.txt(Chinese) into your agent's system prompt, or use this English version:
You can send notifications with the `notify` command.
- Text: notify "message"
- Image: notify --image /path/to/img.png "optional caption"
- File: notify --file /path/to/file.pdf "optional caption"
- Markdown: notify --markdown "*bold* _italic_"
- Long/special text: write it to a file and use notify --text-file /path/to/msg.txt
- Channels: notify --list-channels; notify -C name1,name2 "msg"; notify --all "msg"
- History: notify --history, notify --search "keyword"
Notify the user proactively when a long-running task finishes, an error needs
attention, or a report/chart is ready. Keep messages short and specific, and
send one notification per logical outcome.
Command-line reference
usage: notify.py [-h] [-i PATH] [-f PATH] [-c PATH] [-m] [-C NAME] [-a] [-l]
[-t PATH] [--history [N]] [--search KEYWORD] [--since DATE]
[--until DATE] [--limit N]
[message]
message Message text to send
-i, --image PATH Send an image file
-f, --file PATH Send a document/file
-c, --config PATH Path to configuration file (default: config.json)
-m, --markdown Parse message as Markdown
-C, --channel NAME Only send to this channel (repeatable or comma-separated)
-a, --all Send to every enabled channel (same as no --channel)
-l, --list-channels List configured channels and exit
-t, --text-file PATH Read message/caption text from a file
--history [N] Show the last N sends (default 20) instead of sending
--search KEYWORD Search sent history for KEYWORD
--since DATE Only show history on/after this date
--until DATE Only show history on/before this date
--limit N Max results for --search (default 20)
Troubleshooting
chat not found/ Telegram send fails — open your bot and press START (/start) first; double-checkbot_tokenanduser_id.- Telegram unreachable — set
proxyon that channel (HTTP or SOCKS5), and make sure the proxy is running. - Config not found — put
config.jsonin the current directory or next tonotify.py, or pass-c. - Webhook fails — make sure the target service is actually running and reachable from this machine; check
url,method,headers,body. - Image/file fails — check the path exists and is readable, and the size is within Telegram's limits.
notify: command not found— ensure~/.local/binis inPATH, or run./notifyfrom the repo.Virtual environment not found— run./setup.sh.
How it works
notify.py— CLI, config normalization, channel abstraction, history.notify— shell wrapper that locates the repo (through symlinks) and runsnotify.pywith the repovenv.TelegramNotifiertalks to the Telegram Bot API throughrequests(text splitting, uploads, retries);WebhookNotifiersends templated HTTP requests.MultiChannelNotifierselects channels, sends concurrently with a thread pool and records one history entry per logical send.
License
MIT. Issues and pull requests are welcome.