Skip to content

Repository files navigation

Branchy

Clean GitHub notifications in Telegram.
Small Go service for repository events, subscriptions, and durable delivery.

latest version stable version go version license telegram bot

Quick Start · Using Branchy · How It Works · Configuration · Security · Docs


The Problem

GitHub notifications are useful, but raw webhook delivery becomes noisy fast: too many event types, duplicated formatting, fragile direct sends, and unclear group permissions.

Branchy keeps the MVP deliberately narrow:

Need Branchy approach
Focused event stream Supports only push, pull_request, and release
Telegram-first setup Uses /start plus inline buttons, with settings in DM
Safe group delivery Enables groups only after admin or creator verification
Reliable sending Stores notification jobs in PostgreSQL before delivery
Clean messages Renders compact, sanitized Rich HTML with bounded GitHub media

Result: one small service that turns GitHub activity into readable Telegram updates without expanding beyond the MVP.


Status

Channel Version Meaning
Latest v1.1.0 Stable Telegram Rich Messages release
Previous v1.0.3 Previous stable release using classic HTML delivery

The MVP has been live-tested with Telegram and GitHub. v1.1.0 is the current stable release and promotes the richer Telegram delivery path after a clean production soak and adversarial media/fallback testing.


Preview

Branchy messages keep one event, one repository, and the useful links up front.

Push Pull request Release
FreshLabDev/branchy
2 new commits · main

f2a07de fix Telegram layout
a4e7f27 clarify release flow

Pushed by amtiYo
Compare changes
FreshLabDev/branchy
Pull request opened

#42 Add branch filters
into main · by amtiYo

Description is rendered as a compact quote.
FreshLabDev/branchy
Release · v0.1.0

by amtiYo

Release notes render from GitHub Markdown.

Quick Start

You need Docker, PostgreSQL, a Telegram bot token from BotFather, a GitHub OAuth App, and a public HTTPS URL for OAuth callbacks and webhooks.

# 1. Copy local configuration
cp .env.example .env

# 2. Fill the required secrets and public URL
$EDITOR .env

# 3. Start Branchy and PostgreSQL
docker compose up --build

Create the GitHub OAuth App callback URL with the same public base URL:

${PUBLIC_BASE_URL}/oauth/github/callback

Branchy runs startup migrations from migrations/ and records completed versions in schema_migrations. Keep AUTO_MIGRATE=true for local development.

The bundled docker compose runs a local PostgreSQL and seeds a minimal shared core schema (deploy/core-init.sql) so migrations that reference core.person / core.chat boot cleanly. In the shared production deployment Branchy instead connects to the existing core-postgres.


Using Branchy

All user setup is button-driven inside Telegram.

  1. Open the bot in DM and send /start.
  2. Connect GitHub through OAuth.
  3. Pick repositories and subscribe to push, pull_request, or release.
  4. Configure the selected events: branches for branch-based events, pull request actions, and release type.
  5. Choose DM delivery or an eligible Telegram group.
  6. View, pause, edit, delete, or test subscriptions from the inline menus.

Groups become available only after Branchy has seen the group. Before group delivery is enabled, Branchy verifies that the Telegram user is a group creator or administrator.

In groups, /start is registered as a Bot API 10.2 ephemeral command. Its DM prompt is visible only to the user who invoked it; Branchy never posts a public fallback into the group.


How It Works

Branchy is one Go service with PostgreSQL as its only durable store. Branchy's own tables — subscriptions, the notification outbox, OAuth and runtime state — live in a branchy schema. Telegram identity and presence (users and chats) are delegated to a shared core schema (core.person, core.chat), which Branchy upserts via core.touch before any dependent write. In production that schema lives in the shared core-postgres database; local docker compose seeds a minimal core schema so development boots the same way.

telegram poller  -> inline-button UI
http server      -> OAuth callback and GitHub webhooks
outbox worker    -> Telegram delivery and retries

Webhook handling is intentionally fast:

verify signature -> dedupe delivery -> enqueue jobs -> return 200

Delivery happens outside the webhook request:

poll pending jobs with FOR UPDATE SKIP LOCKED
  -> send Telegram
  -> mark sent, retry, or failed

Temporary Telegram or GitHub failures retry with retry_at and attempts. Permanent delivery failures are marked failed.


MVP Scope

Included Excluded
GitHub OAuth through an OAuth App GitHub App installation flow
Telegram DM and verified groups Non-Telegram delivery channels
push, pull_request, release Issues, comments, deployments, workflow runs
PostgreSQL outbox delivery Direct sends inside webhook handlers
/healthz and /metrics operational health Billing or paid plans

Configuration

Variable Required Default Description
DATABASE_URL yes - PostgreSQL connection string; Branchy's tables live in the branchy schema, so a shared database needs search_path=branchy (append options=-csearch_path%3Dbranchy)
PUBLIC_BASE_URL yes - Public HTTPS base URL
TELEGRAM_BOT_TOKEN yes - Bot token from BotFather
GITHUB_CLIENT_ID yes - GitHub OAuth App client ID
GITHUB_CLIENT_SECRET yes - GitHub OAuth App client secret
GITHUB_WEBHOOK_SECRET yes - Secret for GitHub webhook signatures
APP_SECRET yes - Token encryption secret, 32+ characters
GITHUB_OAUTH_SCOPE no repo read:user OAuth scopes
HTTP_ADDR no :8080 HTTP listen address
MIGRATIONS_DIR no migrations Migration directory
AUTO_MIGRATE no true Run migrations on startup
OUTBOX_POLL_INTERVAL no 2s Outbox poll interval (Go duration)
OUTBOX_BATCH_SIZE no 20 Max jobs claimed per poll
OUTBOX_SEND_TIMEOUT no 20s Per-message Telegram send timeout
OUTBOX_LEASE no 2m Job processing lease duration
OUTBOX_RETENTION_DAYS no 7 Days to keep terminal jobs and dedupe records
NOTIFICATION_MAX_ATTEMPTS no 5 Delivery attempts before a job is failed
TELEGRAM_API_TIMEOUT no 30s Per-request Telegram API timeout (long polling adds its own headroom)
GITHUB_API_TIMEOUT no 20s Per-request GitHub API timeout
WEBHOOK_RATE_LIMIT no 30 Webhook endpoint rate limit, requests per second
WEBHOOK_RATE_BURST no 60 Webhook endpoint burst allowance

The default repo read:user scope is broad, but it supports private repository visibility and repository webhook management through the OAuth App flow.


Security

  • GitHub OAuth tokens are encrypted at rest with AES-GCM using APP_SECRET.
  • GitHub webhook signatures are verified over the raw body before JSON parsing.
  • GitHub delivery IDs are treated as idempotency keys.
  • OAuth state is single-use and expires.
  • GitHub notifications use Telegram Rich Messages (sendRichMessage). Branchy renders GitHub Markdown to allowlisted Rich HTML and strips unsafe or Telegram-specific tags, attributes, and URL schemes before delivery; bot UI keeps classic HTML parse mode.
  • Notification links are restricted to http(s) URLs.
  • Logs avoid Telegram bot tokens, GitHub tokens, webhook secrets, OAuth client secrets, raw authorization headers, and full Telegram Bot API URLs.

Deployment

Only two public routes are required:

/oauth/github/callback
/webhooks/github

Put HTTP_ADDR behind a TLS-terminating reverse proxy or tunnel and set PUBLIC_BASE_URL to the matching HTTPS URL.

/healthz reports database status, Telegram polling freshness, worker freshness, outbox counts, and the build version without exposing secrets. /metrics exposes Prometheus counters (webhook deliveries, notification outcomes, Telegram rate limits, automatic pauses). Both endpoints return counts only; restrict them at your reverse proxy if you do not want them public.


Testing

docker run --rm -v "$PWD":/src -w /src golang:1.26.5-alpine go test ./...
docker run --rm -v "$PWD":/src -w /src golang:1.26.5-alpine go vet ./...
docker compose config

Docs

Document Purpose
Architecture Service structure and core decisions
GitHub integration OAuth, scopes, and repository webhooks
Telegram behavior Bot interaction rules and group delivery
Versioning Pre-release and stable version line
Release process Changelog and GitHub Release rules

Releases · Changelog · Apache-2.0 · NOTICE

Branchy is open source software by FreshLab.
Copyright 2026 FreshLab.

About

🌿 Minimal Telegram bot for GitHub notifications. Clean push, pull request and release alerts in your DM or group, with per-repo and per-branch filters.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages