Local Telegram notification service for Codex PR workflows.
This service sends a Telegram message when a pull request is genuinely ready: the PR exists, required checks have passed, the preview environment has been validated, and telemetry has been checked or explicitly skipped.
The notifier keeps that last-mile notification out of individual app repos. Any
project can use it by posting the same small JSON payload to a localhost HTTP
endpoint. The xpenser $pr-workflow skill is configured to call this service at
the end of its completion workflow.
- Runs as a TypeScript Node service built with Cleverbrush Framework.
- Binds to
127.0.0.1:8787by default. - Receives local HTTP requests only.
- Sends outbound Telegram messages through
node-telegram-bot-api. - Does not poll Telegram.
- Does not receive Telegram webhooks.
- Stores secrets only in environment variables.
Health check for local smoke tests and service monitors.
curl http://127.0.0.1:8787/healthExpected response:
{"ok":true}Sends a PR-ready Telegram notification.
Headers:
Authorization: Bearer <PR_NOTIFICATION_API_TOKEN>
Content-Type: application/json
Body:
{
"project": "xpenser",
"prUrl": "https://github.com/cleverbrush/xpenser/pull/123",
"environmentUrl": "https://xpenser-pr-123.cleverbrush.com",
"summary": "Added Telegram notification support to the PR workflow."
}Success response:
{"ok":true,"messageId":123}Create /root/projects/telegram-notifier/.env from .env.example.
Required for the notifier service:
PR_NOTIFICATION_TELEGRAM_BOT_TOKEN=your_botfather_token
PR_NOTIFICATION_TELEGRAM_CHAT_ID=your_target_chat_id
PR_NOTIFICATION_API_TOKEN=your_random_32_plus_character_api_tokenUseful defaults:
NODE_ENV=production
HOST=127.0.0.1
PORT=8787
LOG_LEVEL=information
OTEL_SERVICE_NAME=telegram-pr-notifier-bot
OTEL_EXPORTER_OTLP_ENDPOINT=http://10.30.1.21:4318Required where Codex runs, using the same API token:
PR_NOTIFICATION_API_TOKEN=your_random_32_plus_character_api_tokenOptional Codex override:
PR_NOTIFICATION_URL=http://127.0.0.1:8787/v1/pr-readyKeep .env uncommitted. Rotate PR_NOTIFICATION_API_TOKEN if it is exposed in
logs, shell history, or chat.
Install dependencies:
npm installBuild the service:
npm run buildStart the built service:
npm startRun in watch mode for development:
npm run devValidate before deploying changes:
npm run lint
npm run typecheck
npm test
npm run buildStart the service:
cd /root/projects/telegram-notifier
npm run build
npm startIn another shell:
curl http://127.0.0.1:8787/healthThen send a test notification:
curl -sS -X POST http://127.0.0.1:8787/v1/pr-ready \
-H "Authorization: Bearer $PR_NOTIFICATION_API_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"project": "xpenser",
"prUrl": "https://github.com/cleverbrush/xpenser/pull/123",
"environmentUrl": "https://xpenser-pr-123.cleverbrush.com",
"summary": "Smoke-tested the PR Telegram notifier."
}'If the request succeeds, Telegram should receive one concise message with the project name, summary, PR link, and environment link.
A sample unit lives at deploy/telegram-notifier.service.
Install and start:
cp /root/projects/telegram-notifier/deploy/telegram-notifier.service /etc/systemd/system/telegram-notifier.service
systemctl daemon-reload
systemctl enable --now telegram-notifier
systemctl status telegram-notifierFollow logs:
journalctl -u telegram-notifier -fRestart after rebuilding:
npm run build
systemctl restart telegram-notifier- Missing Telegram env vars: make sure
npm startis running from/root/projects/telegram-notifierand.envcontainsPR_NOTIFICATION_TELEGRAM_BOT_TOKENandPR_NOTIFICATION_TELEGRAM_CHAT_ID. 401 Unauthorized: the caller'sPR_NOTIFICATION_API_TOKENdoes not match the notifier service token.- No Telegram message but HTTP 200: verify the target chat ID and that the bot is allowed to message that chat.
- Telegram API failure: check
journalctl -u telegram-notifier -f; token or chat permissions are usually the cause. - Port conflict: change
PORTin.envand set CodexPR_NOTIFICATION_URLto the matching URL. - OTel export issues: confirm
OTEL_EXPORTER_OTLP_ENDPOINTis reachable from this host. The default ishttp://10.30.1.21:4318. - Codex did not notify: confirm
$pr-workflowreached its completion step,PR_NOTIFICATION_API_TOKENis present in the Codex environment, and the notifier is healthy.
- Rebuild with
npm run buildafter source changes before restarting the systemd service. - Keep this service project-agnostic; project-specific PR rules belong in each repo's PR workflow documentation.
- The Telegram dependency matches the xpenser reference Telegram bot stack.
- Do not add Telegram polling or webhook receiving unless the service gains a real inbound Telegram workflow.
- Update this README whenever the endpoint contract, env vars, or startup model changes.