Skip to content
Conduit

skill

NotifyBot

A tiny multi-channel notification CLI (Telegram + webhooks) built for AI agents, with searchable send history

xm6661885/NotifyBotcommunitylistedunreviewed

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

Skills do not use an MCP config. Follow the steps in the README below.

README

synced Oct 22, 2026

NotifyBot

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

  • 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-file sidesteps shell-escaping bugs when an agent generates complex text.
  • --list-channels lets 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

KeyDescription
channelsList of channel objects. Each needs a unique name.

Telegram channel ("type": "telegram")

KeyDescription
bot_tokenBot token from @BotFather. Required.
user_idTarget chat/user ID. Required.
proxyOptional 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_attemptsMax attempts on connection/TLS/timeout errors (default 3).
retry_backoffInitial wait in seconds, doubled each retry (default 1).
blacklistKeywords that make this channel skip a message. [] = no filtering.
enabledSet false to disable the channel.

Getting the values

  1. Bot token — message @BotFather, send /newbot, follow the prompts, copy the token (looks like 123456789:ABCdef...).
  2. User ID — message @userinfobot; it replies with your numeric ID.
  3. 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 found otherwise).

Webhook channel ("type": "webhook")

KeyDescription
urlEndpoint URL. Required.
methodHTTP method (default POST).
headersObject of request headers.
bodyRequest body (object or string). String values anywhere inside it may use templates (below).
timeoutSeconds (default 30).
verifyTLS certificate verification (default true).
blacklist / enabledSame 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 / proxy fields and a top-level webhooks list 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:

  1. Agent skill — copy skills/notification/SKILL.md into 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-file for complex text, and how to search history. Edit the channel table in it to match your own config.json.
  2. 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-check bot_token and user_id.
  • Telegram unreachable — set proxy on that channel (HTTP or SOCKS5), and make sure the proxy is running.
  • Config not found — put config.json in the current directory or next to notify.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/bin is in PATH, or run ./notify from 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 runs notify.py with the repo venv.
  • TelegramNotifier talks to the Telegram Bot API through requests (text splitting, uploads, retries); WebhookNotifier sends templated HTTP requests.
  • MultiChannelNotifier selects channels, sends concurrently with a thread pool and records one history entry per logical send.

License

MIT. Issues and pull requests are welcome.

↑↓ navigate openesc close