notifycat

module
v0.22.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 7, 2026 License: MIT

README

Notifycat

Notifycat logo

CI Release Go Version Go Report Card Conventional Commits

Low-noise pull request notifications for Slack. One pull request gets one Slack message: as the PR opens, gets reviewed, merges, or closes, that message updates in place and collects reactions instead of posting again. The channel becomes a status board, not an event log.

A Slack channel where every pull request is one updating message

Three things it's built around:

  • Quiet — state changes are message updates and emoji, not new posts; dependency bumps collapse to one compact line; bot reviews can be marked or muted.
  • Nothing slips through — a morning digest resurfaces PRs nobody touched yesterday, and the "Start review" button shows who's already on it.
  • Easy to own — one Go binary, one declarative config.yaml, one SQLite file. The server validates its whole configuration against Slack and your git host before it will boot, and runtime needs only a webhook secret plus a Slack bot token — no GitHub App, no OAuth.

Documentation

Please visit https://mptooling.github.io/notifycat/

Quick start

You'll need a host with Docker installed, a domain name pointing at it, inbound ports 80/443 open, and a Slack app installed in your workspace (setup). In about 10 minutes you'll have Notifycat running behind automatic HTTPS and posting PR updates to Slack.

curl -fsSL https://github.com/mptooling/notifycat/releases/latest/download/install.sh | sh
cd notifycat
./notifycat setup          # interactive wizard — writes .env and config.yaml
docker compose up -d       # start Notifycat + Caddy (HTTPS via Let's Encrypt)
./notifycat doctor         # verify setup

The installer downloads a pinned, checksum-verified bundle into ./notifycat. The setup wizard prompts for your domain, Slack token, webhook secret, and first mapping. For the full walkthrough — webhook registration, a delivery smoke test, and verifying with a real PR — see Install with Docker Compose, then run through the Security & permissions checklist before go-live.

Alternative: run from source (contributors)

Most users want the one-command path above. Build from source if you're contributing or want to run without Docker.

Requires:

  • Go 1.25.10 or newer (go version to check).
  • git to clone the repository.
  • sh and curl for the helper scripts under scripts/.
  • A public URL (ngrok or Cloudflare Tunnel) only if you want your git host to deliver real webhooks to your laptop. Local CLI commands (validate / doctor) don't need one.

Six commands from "nothing" to "running":

git clone https://github.com/mptooling/notifycat.git && cd notifycat
cp .env.example .env                       # then edit: set GITHUB_WEBHOOK_SECRET, SLACK_BOT_TOKEN
cp config.example.yaml config.yaml        # then edit: database.url and real Slack channel IDs

go run ./cmd/notifycat-config validate
go run ./cmd/notifycat-doctor
go run ./cmd/notifycat-server

The binaries pick up .env from the current working directory and default to ./config.yaml and ./data/notifycat.db. See Run from source for the end-to-end walkthrough including the tunnel + webhook setup.

What you see in Slack

One message per PR: opening it posts the message, reviews land on it as reactions (✅ 💬 ❗), and merging strikes the title through. A Start review button shows who's already reviewing. Dependabot and Renovate bumps collapse to one compact line, and a morning digest resurfaces the PRs nobody touched yesterday. The full tour, message by message: What you see in Slack.

Git Provider Support

Feature GitHub Bitbucket
Webhook signature verification (HMAC-SHA256) Yes Yes
Per-path / monorepo routing Yes (requires GITHUB_TOKEN) Yes (requires BITBUCKET_TOKEN)
Stuck-PR digest Yes Yes
Reactions & review flow Yes Yes
Token auth Fine-grained PAT (Bearer) Access token (Bearer) or scoped Atlassian API token (Basic, Free-plan fallback)
App passwords n/a Not supported — removed by Atlassian 2026-07-28; use access tokens

A deployment serves one git host, and routing lives in the mappings: section of config.yaml — per-repository tiers with an org-wide "*" catch-all. See Configuration basics.

Development

The project includes a justfile for common development commands. Install just (brew install just on macOS), then run:

just
just check
just serve

just is a developer tool only. It is not part of the Go module, the Docker runtime image, or production dependencies.

The underlying checks are:

go vet ./...
golangci-lint run ./...
govulncheck ./...
go test -race ./...
go build ./...

See CONTRIBUTING.md for contributor setup, pull request expectations, and issue reporting guidance.

Community

License

MIT. See LICENSE.

Directories

Path Synopsis
cmd
notifycat-config command
Command notifycat-config is the CLI for the declarative config.yaml workflow: `list` prints the file, `validate` runs the cache-aware validation pipeline.
Command notifycat-config is the CLI for the declarative config.yaml workflow: `list` prints the file, `validate` runs the cache-aware validation pipeline.
notifycat-doctor command
Command notifycat-doctor runs end-to-end preflight diagnostics for a notifycat installation.
Command notifycat-doctor runs end-to-end preflight diagnostics for a notifycat installation.
notifycat-migrate command
Command notifycat-migrate applies the embedded database migrations.
Command notifycat-migrate applies the embedded database migrations.
notifycat-reconcile command
Command notifycat-reconcile is a one-time maintenance tool that marks slack_messages rows closed when their PR is no longer open on the git provider.
Command notifycat-reconcile is a one-time maintenance tool that marks slack_messages rows closed when their PR is no longer open on the git provider.
notifycat-server command
Command notifycat-server starts the HTTP server that receives GitHub webhooks and posts to Slack.
Command notifycat-server starts the HTTP server that receives GitHub webhooks and posts to Slack.
notifycat-smoke command
Command notifycat-smoke runs an end-to-end delivery test against the running notifycat stack.
Command notifycat-smoke runs an end-to-end delivery test against the running notifycat stack.
internal
diagnostics
Package diagnostics wires the diagnostics domain — doctor preflight checks, config-CLI validation, and smoke delivery tests — into an fx module.
Package diagnostics wires the diagnostics domain — doctor preflight checks, config-CLI validation, and smoke delivery tests — into an fx module.
diagnostics/application
Package application holds the diagnostics use cases — the doctor, the config list/validate CLI, and the smoke delivery — behind the domain's use-case interfaces.
Package application holds the diagnostics use cases — the doctor, the config list/validate CLI, and the smoke delivery — behind the domain's use-case interfaces.
diagnostics/domain
Package domain defines the diagnostics domain's ports, DTOs, and constants — the operator-tooling contracts (preflight doctor, config CLI, smoke delivery).
Package domain defines the diagnostics domain's ports, DTOs, and constants — the operator-tooling contracts (preflight doctor, config CLI, smoke delivery).
diagnostics/infrastructure
Package infrastructure holds the diagnostics adapters: the config snapshot and database probe, the routing lock gateway, the request signer, the webhook sender, the report writer, and the smoke store/Slack adapters.
Package infrastructure holds the diagnostics adapters: the config snapshot and database probe, the routing lock gateway, the request signer, the webhook sender, the report writer, and the smoke store/Slack adapters.
digest
Package digest wires the digest domain — the scheduled stuck-PR reminder — into an fx module.
Package digest wires the digest domain — the scheduled stuck-PR reminder — into an fx module.
digest/application
Package application holds the digest use cases — the stuck-PR reporter and the cron scheduler — behind the domain's use-case interfaces.
Package application holds the digest use cases — the stuck-PR reporter and the cron scheduler — behind the domain's use-case interfaces.
digest/domain
Package domain defines the digest domain's ports, DTOs, and constants — the scheduled stuck-PR reminder contracts.
Package domain defines the digest domain's ports, DTOs, and constants — the scheduled stuck-PR reminder contracts.
digest/infrastructure
Package infrastructure holds the digest adapters: a stuck-PR repository over the store and Slack composer/poster adapters over the platform client.
Package infrastructure holds the digest adapters: a stuck-PR repository over the store and Slack composer/poster adapters over the platform client.
kernel
Package kernel holds the shared domain value objects — PR, Message, Event, Sender, ReviewState — and the cross-domain enums used by the notification, review, and routing domains.
Package kernel holds the shared domain value objects — PR, Message, Event, Sender, ReviewState — and the cross-domain enums used by the notification, review, and routing domains.
maintenance
Package maintenance wires the maintenance domain — stale-message cleanup and PR reconcile — into an fx module.
Package maintenance wires the maintenance domain — stale-message cleanup and PR reconcile — into an fx module.
maintenance/application
Package application holds the maintenance use cases — stale-message cleanup and PR reconcile — implemented against the ports declared in the maintenance domain layer.
Package application holds the maintenance use cases — stale-message cleanup and PR reconcile — implemented against the ports declared in the maintenance domain layer.
maintenance/domain
Package domain holds the maintenance domain's contracts: the ports, DTOs, enums, and constants for stale-message cleanup and PR reconcile.
Package domain holds the maintenance domain's contracts: the ports, DTOs, enums, and constants for stale-message cleanup and PR reconcile.
maintenance/infrastructure
Package infrastructure holds the maintenance adapters: the store-backed PR repository and the GitHub PR-state checker, each implementing a maintenance domain port.
Package infrastructure holds the maintenance adapters: the store-backed PR repository and the GitHub PR-state checker, each implementing a maintenance domain port.
notification
Package notification wires the notification domain — the core PR-event → chat notification flow — into an fx module.
Package notification wires the notification domain — the core PR-event → chat notification flow — into an fx module.
notification/application
Package application holds the notification use cases — the PR-lifecycle handlers (open/close/draft and the review-reaction handlers) and the event dispatcher — behind the domain's Handler and use-case interfaces.
Package application holds the notification use cases — the PR-lifecycle handlers (open/close/draft and the review-reaction handlers) and the event dispatcher — behind the domain's Handler and use-case interfaces.
notification/domain
Package domain defines the notification domain's ports, DTOs, enums, and policies — the contracts for keeping one chat message per (PR, channel) in sync with GitHub PR events.
Package domain defines the notification domain's ports, DTOs, enums, and policies — the contracts for keeping one chat message per (PR, channel) in sync with GitHub PR events.
notification/infrastructure
Package infrastructure holds the notification adapters: the messages repository over the store, the Slack messenger over the platform client, and the GitHub inbound receiver.
Package infrastructure holds the notification adapters: the messages repository over the store, the Slack messenger over the platform client, and the GitHub inbound receiver.
platform/bitbucket
Package bitbucket is a minimal Bitbucket Cloud REST API client covering only the endpoints notifycat needs for validation and path routing.
Package bitbucket is a minimal Bitbucket Cloud REST API client covering only the endpoints notifycat needs for validation and path routing.
platform/config
Package config loads runtime configuration from a single config.yaml file.
Package config loads runtime configuration from a single config.yaml file.
platform/github
Package github is a minimal GitHub API client covering only the endpoints notifycat needs for validation.
Package github is a minimal GitHub API client covering only the endpoints notifycat needs for validation.
platform/httpx
Package httpx holds the HTTP plumbing shared by notifycat's signed-webhook receivers.
Package httpx holds the HTTP plumbing shared by notifycat's signed-webhook receivers.
platform/persistence
Package store owns the database schema, GORM models, repositories, and the goose-driven migration runner.
Package store owns the database schema, GORM models, repositories, and the goose-driven migration runner.
platform/security
Package security holds notifycat's inbound-request authentication: signature verifiers for the signed webhooks it receives.
Package security holds notifycat's inbound-request authentication: signature verifiers for the signed webhooks it receives.
platform/slack
Package slack talks to the Slack Web API for the PR notifier: posting, updating, and deleting messages, adding emoji reactions, and composing the blocks of the notification.
Package slack talks to the Slack Web API for the PR notifier: posting, updating, and deleting messages, adding emoji reactions, and composing the blocks of the notification.
review
Package review wires the review domain — the interactive "Start review" flow — into an fx module.
Package review wires the review domain — the interactive "Start review" flow — into an fx module.
review/application
Package application holds the review use cases — recording a reviewer and decorating the PR message on a "Start review" click — behind the domain's use-case interfaces.
Package application holds the review use cases — recording a reviewer and decorating the PR message on a "Start review" click — behind the domain's use-case interfaces.
review/domain
Package domain defines the review domain's ports, DTOs, and errors — the interactive "Start review" flow's contracts.
Package domain defines the review domain's ports, DTOs, and errors — the interactive "Start review" flow's contracts.
review/infrastructure
Package infrastructure holds the review adapters: the code-reviews repository over the store, the Slack message decorator, and the Slack interactions inbound receiver.
Package infrastructure holds the review adapters: the code-reviews repository over the store, the Slack message decorator, and the Slack interactions inbound receiver.
routing
Package routing wires the routing domain — repository→channel resolution across tiers and monorepo path rules — into an fx module.
Package routing wires the routing domain — repository→channel resolution across tiers and monorepo path rules — into an fx module.
routing/application
Package application holds the routing use cases: the provider (tier resolution and defaults merge) and the per-PR router (layering monorepo path rules over the base repo/org tier).
Package application holds the routing use cases: the provider (tier resolution and defaults merge) and the per-PR router (layering monorepo path rules over the base repo/org tier).
routing/domain
Package domain holds the routing domain's contracts: the ports, DTOs, enums, constants, and pure validation for resolving a repository (and a PR's changed files) to the Slack channel(s) and behavioural config that apply, across the global/org/repo tiers and monorepo path rules.
Package domain holds the routing domain's contracts: the ports, DTOs, enums, constants, and pure validation for resolving a repository (and a PR's changed files) to the Slack channel(s) and behavioural config that apply, across the global/org/repo tiers and monorepo path rules.
routing/infrastructure
Package infrastructure holds the routing adapters: the YAML loader for the mappings section of config.yaml, the config.lock read/write/diff/merge store, and the GitHub changed-files reader.
Package infrastructure holds the routing adapters: the YAML loader for the mappings section of config.yaml, the config.lock read/write/diff/merge store, and the GitHub changed-files reader.
runtime
Package runtime is the fx composition root for the notifycat server.
Package runtime is the fx composition root for the notifycat server.
validation
Package validation wires the validation domain — per-repository mapping checks against Slack and a git provider — into an fx module.
Package validation wires the validation domain — per-repository mapping checks against Slack and a git provider — into an fx module.
validation/application
Package application holds the validation use cases: the per-repository Validator and the entry runner that expands and validates mapping entries.
Package application holds the validation use cases: the per-repository Validator and the entry runner that expands and validates mapping entries.
validation/domain
Package domain holds the validation domain's contracts: the ports that infrastructure adapters satisfy, the DTOs and enums that describe a validation run, and the constants that define what "valid" means.
Package domain holds the validation domain's contracts: the ports that infrastructure adapters satisfy, the DTOs and enums that describe a validation run, and the constants that define what "valid" means.
validation/infrastructure
Package infrastructure holds the validation adapters that satisfy the domain ports over real clients — today, a Slack probe over the platform Slack client.
Package infrastructure holds the validation adapters that satisfy the domain ports over real clients — today, a Slack probe over the platform Slack client.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL