agent-notify-core 0.2.0

Core notification config and provider implementation for agent-notify.
Documentation

agent-notify

Crates.io Rust: 1.85+ License: MIT

A notification CLI for AI agents and automation scripts.

hero

agent-notify provides the notify command for sending messages and generated files through configured notification channels.

notify send --channel personal --title "Task completed" --body "The report is ready." --file ./report.pdf

Supported Channels

  • file-log
  • telegram
  • discord-webhook
  • discord-bot
  • ntfy
  • webhook

The CLI can load, check, and send through the channel types above. External channel types require their configured service credentials or environment variables.

Installation

Install from crates.io:

cargo install agent-notify

This installs the notify binary.

To build from this repository instead:

cargo build --release

The local build writes the binary to:

target/release/notify

Quick Start

Create notify.toml:

default_channel = "local"

[channels.local]
type = "file-log"
path = "./notify-log"

Send a notification:

notify send --title "Hello" --body "Hello from agent-notify."

This writes a local JSONL log under ./notify-log.

Concepts

A channel is the configured destination name that users and agents select, such as personal, team, phone, local, or automation.

A channel has a type, which controls how the notification is delivered:

telegram
discord-webhook
discord-bot
ntfy
webhook
file-log

Agents should use channel names and should not need to know service credentials or provider-specific API details.

Configuration

notify looks for configuration in this order:

  1. --config <path>
  2. ./notify.toml
  3. ~/.config/agent-notify/config.toml

Example:

default_channel = "personal"

[channels.personal]
type = "telegram"
bot_token_env = "NOTIFY_TELEGRAM_BOT_TOKEN"
chat_id_env = "NOTIFY_TELEGRAM_CHAT_ID"
parse_mode = "plain"

[channels.team]
type = "discord-webhook"
webhook_url_env = "NOTIFY_DISCORD_WEBHOOK_URL"
username = "Agent Notify"
allow_mentions = false

[channels.bot_team]
type = "discord-bot"
bot_token_env = "NOTIFY_DISCORD_BOT_TOKEN"
channel_id_env = "NOTIFY_DISCORD_CHANNEL_ID"
allow_mentions = false

[channels.phone]
type = "ntfy"
server = "https://ntfy.sh"
topic_env = "NOTIFY_NTFY_TOPIC"
token_env = "NOTIFY_NTFY_TOKEN"

[channels.automation]
type = "webhook"
url_env = "NOTIFY_WEBHOOK_URL"
auth_header_env = "NOTIFY_WEBHOOK_AUTH_HEADER"

[channels.local]
type = "file-log"
path = "./notify-log"

Sample files are included under:

examples/notify.toml
examples/notify.env.example

Secrets

Secret-like values can be configured inline or through environment variables.

Recommended:

[channels.team]
type = "discord-webhook"
webhook_url_env = "NOTIFY_DISCORD_WEBHOOK_URL"
export NOTIFY_DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."

Quick setup:

[channels.team]
type = "discord-webhook"
webhook_url = "https://discord.com/api/webhooks/..."

Environment variables are recommended for shared repositories, CI, and agent workflows.

Secrets are not accepted as CLI arguments.

Invalid:

notify send --webhook-url "https://discord.com/api/webhooks/..." --title "Hello" --body "World"

Also invalid:

webhook_url = "https://discord.com/api/webhooks/..."
webhook_url_env = "NOTIFY_DISCORD_WEBHOOK_URL"

Use either the inline field or the _env field, not both.

Commands

notify send

Send a notification.

notify send --channel personal --title "Task completed" --body "The report was generated successfully."

Use the default channel:

notify send --title "Task completed" --body "Done."

Send to multiple channels:

notify send --channel personal --channel team --title "Task completed" --body "Done."

Attach a file:

notify send \
  --channel local \
  --title "Chart ready" \
  --body "Attached chart image." \
  --file ./chart.png

Read body from a file:

notify send \
  --channel local \
  --title "Error summary" \
  --body-file ./error-summary.md

Dry run:

notify send \
  --channel local \
  --title "Chart ready" \
  --body "Attached chart image." \
  --file ./chart.png \
  --dry-run

Common options:

--channel <name>       Channel name. Can be repeated. Uses default_channel if omitted.
--title <text>         Notification title.
--body <text>          Notification body.
--body-file <path>     Read body from a file.
--file <path>          Attach a file. Can be used multiple times.
--priority <level>     info | success | warning | error | critical
--format <format>      text | markdown
--tag <tag>            Add a tag. Can be used multiple times.
--dry-run              Resolve and display the notification without sending it.
--json                 Emit JSON output.
--config <path>        Use a specific config file.

notify channels

List configured channels.

notify channels

Example:

personal     telegram          ready
team         discord-webhook   ready
phone        ntfy              ready
local        file-log          ready
automation   webhook           ready

notify check

Validate configuration.

notify check

Check one channel:

notify check --channel personal

notify test

Send a test notification.

notify test --channel local

Channel Configuration

file-log

Stores notifications in a local JSONL file and copies attachments under a child directory.

[channels.local]
type = "file-log"
path = "./notify-log"

Use this for local testing or CI verification.

telegram

[channels.personal]
type = "telegram"
bot_token_env = "NOTIFY_TELEGRAM_BOT_TOKEN"
chat_id_env = "NOTIFY_TELEGRAM_CHAT_ID"
parse_mode = "plain"

Inline:

[channels.personal]
type = "telegram"
bot_token = "123456:ABC..."
chat_id = "123456789"
parse_mode = "plain"

Supported parse_mode values:

plain
html
markdown-v2

discord-webhook

[channels.team]
type = "discord-webhook"
webhook_url_env = "NOTIFY_DISCORD_WEBHOOK_URL"
username = "Agent Notify"
allow_mentions = false

Inline:

[channels.team]
type = "discord-webhook"
webhook_url = "https://discord.com/api/webhooks/..."

discord-bot

[channels.bot_team]
type = "discord-bot"
bot_token_env = "NOTIFY_DISCORD_BOT_TOKEN"
channel_id_env = "NOTIFY_DISCORD_CHANNEL_ID"
allow_mentions = false

Inline:

[channels.bot_team]
type = "discord-bot"
bot_token = "..."
channel_id = "123456789012345678"
allow_mentions = false

ntfy

[channels.phone]
type = "ntfy"
server = "https://ntfy.sh"
topic_env = "NOTIFY_NTFY_TOPIC"
token_env = "NOTIFY_NTFY_TOKEN"

Inline:

[channels.phone]
type = "ntfy"
server = "https://ntfy.sh"
topic = "my-topic"
token = "..."

token is optional, depending on your ntfy server and topic configuration.

webhook

[channels.automation]
type = "webhook"
url_env = "NOTIFY_WEBHOOK_URL"
auth_header_env = "NOTIFY_WEBHOOK_AUTH_HEADER"
timeout_seconds = 15

Inline:

[channels.automation]
type = "webhook"
url = "https://example.com/notify"
auth_header = "Bearer secret"
timeout_seconds = 15

The webhook channel uses the project-defined webhook protocol. The v1 payload format is defined in SPEC.md.

Webhook Protocol v1

The webhook channel sends the agent-notify webhook protocol v1 payload.

Without attachments, the request is application/json. With attachments, the request is multipart/form-data with a payload JSON part and file parts named file0, file1, and so on.

The full protocol is documented in:

docs/webhook-v1.md

Examples

Local test

default_channel = "local"

[channels.local]
type = "file-log"
path = "./notify-log"
notify send --title "Local test" --body "This notification is stored locally."

Discord webhook

default_channel = "team"

[channels.team]
type = "discord-webhook"
webhook_url_env = "NOTIFY_DISCORD_WEBHOOK_URL"
export NOTIFY_DISCORD_WEBHOOK_URL="https://discord.com/api/webhooks/..."

notify send --title "Deployment complete" --body "The deployment finished successfully."

Telegram

default_channel = "personal"

[channels.personal]
type = "telegram"
bot_token_env = "NOTIFY_TELEGRAM_BOT_TOKEN"
chat_id_env = "NOTIFY_TELEGRAM_CHAT_ID"
export NOTIFY_TELEGRAM_BOT_TOKEN="123456:ABC..."
export NOTIFY_TELEGRAM_CHAT_ID="123456789"

notify send --title "Job failed" --priority error --body "The nightly job failed."

ntfy

default_channel = "phone"

[channels.phone]
type = "ntfy"
server = "https://ntfy.sh"
topic_env = "NOTIFY_NTFY_TOPIC"
export NOTIFY_NTFY_TOPIC="my-private-topic"

notify send --title "Attention needed" --priority warning --body "The agent needs attention."

Webhook

default_channel = "automation"

[channels.automation]
type = "webhook"
url_env = "NOTIFY_WEBHOOK_URL"
auth_header_env = "NOTIFY_WEBHOOK_AUTH_HEADER"
export NOTIFY_WEBHOOK_URL="https://example.com/notify"
export NOTIFY_WEBHOOK_AUTH_HEADER="Bearer secret"

notify send --title "Report ready" --body "The report is ready." --file ./report.pdf

Agent Skill

This repository includes an Agent Skill under:

skills/notification/

Use it when installing agent-notify into an AI agent environment.

Install the CLI first:

cargo install agent-notify