{"id":50755268,"url":"https://github.com/escoffier-labs/agent-notify","last_synced_at":"2026-06-11T04:02:45.350Z","repository":{"id":363750900,"uuid":"1247800499","full_name":"escoffier-labs/agent-notify","owner":"escoffier-labs","description":"Privacy-first push notifications for AI coding agents to Discord, Telegram, and Signal. Zero telemetry, single Go binary.","archived":false,"fork":false,"pushed_at":"2026-06-10T06:52:29.000Z","size":57,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T08:21:44.815Z","etag":null,"topics":["ai-agents","claude-code","cli","discord","go","notifications","signal","telegram"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/escoffier-labs.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-23T19:52:44.000Z","updated_at":"2026-06-10T06:51:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/escoffier-labs/agent-notify","commit_stats":null,"previous_names":["escoffier-labs/agent-notify"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/escoffier-labs/agent-notify","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escoffier-labs%2Fagent-notify","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escoffier-labs%2Fagent-notify/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escoffier-labs%2Fagent-notify/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escoffier-labs%2Fagent-notify/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/escoffier-labs","download_url":"https://codeload.github.com/escoffier-labs/agent-notify/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/escoffier-labs%2Fagent-notify/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34181555,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-11T02:00:06.485Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","claude-code","cli","discord","go","notifications","signal","telegram"],"created_at":"2026-06-11T04:02:44.657Z","updated_at":"2026-06-11T04:02:45.342Z","avatar_url":"https://github.com/escoffier-labs.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# agent-notify\n\n\u003cp\u003e\n  \u003ca href=\"https://github.com/escoffier-labs/agent-notify/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://img.shields.io/github/actions/workflow/status/escoffier-labs/agent-notify/ci.yml?branch=main\u0026style=for-the-badge\u0026label=ci\" alt=\"CI status\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/escoffier-labs/agent-notify/releases\"\u003e\u003cimg src=\"https://img.shields.io/github/v/release/escoffier-labs/agent-notify?style=for-the-badge\u0026label=release\" alt=\"Latest release\"\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/go-1.22%2B-00ADD8?style=for-the-badge\u0026logo=go\u0026logoColor=white\" alt=\"Go 1.22+\"\u003e\n  \u003cimg src=\"https://img.shields.io/badge/license-MIT-green?style=for-the-badge\" alt=\"MIT license\"\u003e\n\u003c/p\u003e\n\nA privacy-first notification dispatcher for AI coding agents and any other host process. Sends to Discord, Telegram, and Signal - no telemetry, no third-party push infrastructure, no Anthropic / OpenAI involvement.\n\nBuilt for engineers running an always-on agent stack who want push notifications when the agent finishes or needs input, without routing real-time session activity through a vendor's notification service.\n\n## Why this exists\n\nIf you set `DISABLE_TELEMETRY=1` to keep your agent harness from phoning home, you've also disabled the harness's built-in mobile push feature (which routes through the same telemetry plumbing). `agent-notify` gives you the same UX with zero data flow you didn't ask for: messages go from your machine directly to Discord's API, the Telegram Bot API, or your self-hosted Signal CLI - and nowhere else.\n\n## Privacy posture\n\n- No telemetry endpoints. Ever.\n- No update checks at startup or runtime.\n- No persistent state. No state file. No log file. No cache.\n- Outbound HTTP only to channel URLs you configured.\n- Test `cmd/agent-notify/privacy_test.go` asserts the above.\n\n## Install\n\nInstall the latest tagged release with `go install`:\n\n```bash\ngo install github.com/escoffier-labs/agent-notify/cmd/agent-notify@latest\n```\n\nOr build from source:\n\n```bash\ngit clone https://github.com/escoffier-labs/agent-notify.git\ncd agent-notify\nmake install   # builds and copies to ~/bin/agent-notify\n```\n\nPrebuilt binaries (linux, macOS, windows for amd64 and arm64) plus a `checksums.txt` are attached to each [release](https://github.com/escoffier-labs/agent-notify/releases). Download the archive for your platform, verify the checksum, extract, and drop the binary in `~/bin/` or `/usr/local/bin/`:\n\n```bash\ntar -xzf agent-notify_*_linux_amd64.tar.gz\ninstall -m 0755 agent-notify_*_linux_amd64/agent-notify ~/bin/agent-notify\n```\n\nConfirm the installed binary:\n\n```bash\nagent-notify version\n```\n\n## Quickstart (no config file)\n\nSet env vars for the channel(s) you want and run:\n\n```bash\nexport DISCORD_WEBHOOK_URL='https://discord.com/api/webhooks/...'\nagent-notify \"hello from agent-notify\"\n```\n\nThe explicit subcommand form is equivalent:\n\n```bash\nagent-notify send \"hello from agent-notify\"\n```\n\nMultiple channels at once:\n\n```bash\nexport DISCORD_WEBHOOK_URL='...'\nexport TELEGRAM_BOT_TOKEN='...'\nexport TELEGRAM_CHAT_ID='...'\nagent-notify \"build finished\"   # fans out to both\n```\n\n## Config file (when you outgrow env-only)\n\nGenerate a starter config:\n\n```bash\nagent-notify init\n```\n\nOr create `~/.config/agent-notify/config.toml` manually:\n\n```toml\n[channels.tg-personal]\ntype = \"telegram\"\nbot_token_env = \"TELEGRAM_BOT_TOKEN\"\nchat_id_env   = \"TELEGRAM_CHAT_ID\"\n\n[channels.discord-main]\ntype = \"discord\"\nwebhook_url_env = \"DISCORD_WEBHOOK_URL\"\n\n[channels.signal-personal]\ntype = \"signal\"\nurl_env  = \"SIGNAL_CLI_URL\"\nfrom_env = \"SIGNAL_FROM\"\nto_env   = \"SIGNAL_TO\"\n\n[profiles.agent-stop]\nchannels = [\"tg-personal\", \"discord-main\"]\ndefault  = true\n\n[profiles.error]\nchannels = [\"tg-personal\", \"discord-main\", \"signal-personal\"]\nprefix   = \"🚨 \"\n```\n\nSecrets stay in env vars (the config references env-var names, not literal tokens).\n\nValidate the wiring without sending a live notification:\n\n```bash\nagent-notify status --json\nagent-notify doctor\nagent-notify doctor --json\n```\n\n## Routing precedence\n\n1. `--to \u003cnames\u003e` (explicit, comma-separated) - overrides everything else.\n2. `--profile \u003cname\u003e` - channels from the named profile in config.\n3. Profile in config with `default = true`.\n4. All configured channels.\n\n`--skip \u003cnames\u003e` filters from any of the above.\n\n```bash\nagent-notify \"build done\"                              # default profile or all channels\nagent-notify --profile error \"5 critical alerts\"       # error profile\nagent-notify --to tg-personal \"ack\"                    # only Telegram\nagent-notify --profile error --skip signal \"minor\"     # error profile minus Signal\n```\n\n## Hook integrations\n\n### Claude Code (`~/.claude/settings.json`)\n\nGenerate the snippet:\n\n```bash\nagent-notify hooks print claude-code --profile agent-stop\n```\n\n```json\n{\n  \"hooks\": {\n    \"Stop\": [{\n      \"hooks\": [\n        { \"type\": \"command\", \"command\": \"agent-notify --hook claude-code-stop --profile agent-stop\" }\n      ]\n    }],\n    \"Notification\": [{\n      \"hooks\": [\n        { \"type\": \"command\", \"command\": \"agent-notify --hook claude-code-notification --profile agent-stop\" }\n      ]\n    }]\n  }\n}\n```\n\n### Claude Desktop\n\nNot applicable - Claude Desktop does not expose a hook surface that runs local commands. Use the Claude Code integration instead, or call `agent-notify` from a shortcut/script bound to whatever event you care about.\n\n### OpenClaw\n\nOpenClaw has its own multi-channel delivery built in, so you typically would not wire `agent-notify` for OpenClaw's own events. If you do want to use it (e.g., uniformity across all your agents), call it from a plugin's `agent_end` hook:\n\n```typescript\napi.on(\"agent_end\", async (event, ctx) =\u003e {\n  const proc = spawn(\"agent-notify\", [\"--hook\", \"custom\", \"--profile\", \"agent-stop\"]);\n  proc.stdin.write(JSON.stringify({\n    title: \"OpenClaw session ended\",\n    body: `Session ${event.sessionId} done`,\n    source: \"openclaw\",\n  }));\n  proc.stdin.end();\n});\n```\n\n### Hermes Agent\n\nSame pattern as OpenClaw - wire `agent-notify` to whichever scheduled-task or session-end hook Hermes exposes in your version. Pass canonical JSON via stdin and use `--hook custom` (the default).\n\n### Codex CLI (`~/.codex/config.toml`)\n\nGenerate the snippet:\n\n```bash\nagent-notify hooks print codex --profile agent-stop\n```\n\n```toml\nnotify = [\"agent-notify\", \"--hook\", \"codex-notify\", \"--profile\", \"agent-stop\"]\n```\n\n## Adding a custom hook source (escape hatch)\n\nIf a built-in adapter ever breaks because an upstream tool changes its event schema, write a small shell wrapper that extracts the fields you want and pipes canonical JSON to `agent-notify`:\n\n```bash\n#!/usr/bin/env bash\n# my-tool-notify.sh - wrapper for some-future-agent\nevent=$(cat)\nbody=$(echo \"$event\" | jq -r '.message_field // \"(no message)\"')\ntitle=$(echo \"$event\" | jq -r '.title_field // \"MyTool\"')\njq -n --arg t \"$title\" --arg b \"$body\" \\\n  '{title: $t, body: $b, source: \"my-tool\"}' \\\n  | agent-notify --profile agent-stop\n```\n\nThen point the upstream tool's hook config at `my-tool-notify.sh` instead.\n\n## Exit codes\n\n- `0` - all sends succeeded\n- `1+` - number of channel sends that failed (other channels still received the message)\n- `2` - config or input error before any send was attempted\n\n## Channel formatting\n\n| Channel | Format |\n|---------|--------|\n| Discord | Embed with title + body. Color by level (info=blue, warn=yellow, error=red, success=green). Tags as inline fields. Source as footer. |\n| Telegram | Markdown V2. Level emoji prefix (ℹ️ / ⚠️ / 🚨 / ✅). Title bolded. Tags as italicized footer. |\n| Signal | Plain text. Level emoji prefix. Title on its own line. Tags as `[tag1, tag2]` footer. |\n\n## Limitations (v1)\n\n- No retry queue. A rate-limited or down channel means dropped notification.\n- No templating. The canonical message goes through as-is.\n- Three channels only. Adding more is straightforward (one file in `internal/channels/`).\n\n## License\n\nMIT - see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescoffier-labs%2Fagent-notify","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fescoffier-labs%2Fagent-notify","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fescoffier-labs%2Fagent-notify/lists"}