Skip to main content

gh2discord

PyPI tests CodeQL OpenSSF Scorecard Python

Wire GitHub repos to Discord channels with one command.

Discord can render GitHub webhook payloads natively — no bot, no middleware. The only friction is the manual setup: create a Discord webhook, copy the URL, open every repo's settings, paste the URL with a magic /github suffix. gh2discord automates the GitHub side and remembers your Discord channels, so tracking a new repo becomes:

gh2discord track owner/repo

Install

pipx install gh2discord   # recommended
# or
pip install gh2discord

Zero runtime dependencies. Python 3.10+.

Setup (once)

  1. In Discord: Channel settings → Integrations → Webhooks → New Webhook, copy the webhook URL.
  2. Register it:
gh2discord channel add general https://discord.com/api/webhooks/<id>/<token> --default
  1. Authenticate with GitHub — any one of:

    • gh CLI already logged in (nothing to do; the token is picked up automatically), or
    • GITHUB_TOKEN / GH_TOKEN environment variable.
      • Classic PAT: repo or admin:repo_hook scope.
      • Fine-grained PAT: Webhooks (write) + Metadata (read) on the repos you track.

    If both are present, GITHUB_TOKEN / GH_TOKEN take precedence over the gh CLI login, so a stale variable wins over a working gh session.

You can only track repos you administer — GitHub allows webhook management for repo admins only.

Usage

gh2discord track owner/repo                     # default channel, default events (see Notes)
gh2discord track owner/repo --events push,release,issues,pull_request
gh2discord track owner/repo --channel alerts    # per-repo channel
gh2discord list                                 # tracked repos
gh2discord status                               # live hook health; exits 1 if any hook is unhealthy
gh2discord status owner/repo                    # one repo only
gh2discord ping owner/repo                      # end-to-end delivery test
gh2discord untrack owner/repo                   # remove the hook
gh2discord --version

Repo arguments also accept GitHub URLs (https://github.com/owner/repo, git@github.com:owner/repo.git).

track is idempotent: run it twice and you get one hook, not two. It also repairs broken hooks in place (wrong content type or disabled). Without --events it never changes the events of a hook that already exists; pass --events to change them. If the repo already posts to a different Discord webhook, track stops with an error and changes nothing; --force retargets that hook and deletes any other Discord hooks. If the correct hook exists alongside extra Discord hooks, track warns, and --force deletes the extras.

Multiple channels work without any bot: register each channel's webhook once (channel add), then route repos with --channel.

gh2discord channel add releases https://discord.com/api/webhooks/<id>/<token>
gh2discord track owner/lib --channel releases --events release
gh2discord channel list                # registered channels (URLs masked, * = default)
gh2discord channel default releases    # change the default channel
gh2discord channel remove releases     # refused while a tracked repo still uses it

Notes

  • Config lives at %APPDATA%\gh2discord\config.json (Windows) or $XDG_CONFIG_HOME/gh2discord/config.json (Linux/macOS; defaults to ~/.config/gh2discord/config.json). Discord webhook URLs are secrets — the file is written with owner-only permissions on POSIX; don't commit it anywhere.
  • New hooks get the default events (--events default): push, pull_request, pull_request_review, issues, issue_comment and release. --events all subscribes to everything GitHub sends, including CI. Discord renders check_run and check_suite as one message per CI job, and it rate-limits each webhook (observed: 5 requests per 2 seconds), counting the events it doesn't render, such as workflow_job, as well. On a repo with a CI matrix, a single pull request can exceed that limit: Discord answers HTTP 429, GitHub doesn't retry, and the notifications you wanted get dropped. Use all only on quiet repos. For other events Discord renders (such as discussion or pull_request_review_comment), pass the full list, e.g. --events push,pull_request,pull_request_review,issues,issue_comment,release,discussion.
  • GitHub returns 404 (not 403) when your token lacks webhook access to a repo — if a repo you own reports "not found", check your token scopes first.

Upgrading from 0.1.x

0.1.x subscribed every hook to all events (*). Upgrading changes no hooks: track without --events keeps an existing hook's events. For a hook that still sends everything, track and status print a warning with the exact command to run (including --channel when the repo isn't on the default channel):

gh2discord track owner/repo --events default   # switch to the default events
gh2discord track owner/repo --events all       # keep every event and silence the warning

Security

This tool is built to be easy to audit and hard to abuse:

  • Zero runtime dependencies — pure Python standard library; the whole source is six small files (about 800 lines).
  • Single network destination — only https://api.github.com, over HTTPS, with silent redirects disabled.
  • Your token never leaves your machine — read from the environment or the gh CLI at runtime, never stored, never logged.
  • Webhook URLs are treated as secrets — stored locally with owner-only file permissions and masked (***) in every command output.
  • No telemetry, no analytics, no phone-home.
  • Verifiable releases — published to PyPI exclusively by GitHub Actions via Trusted Publishing with PEP 740 attestations; check the provenance on the PyPI page. Each GitHub release carries the wheel and sdist with their Sigstore signatures, and releases are immutable once published. No human ever uploads a build by hand, and no long-lived PyPI token exists.
  • Hardened CI — all Actions pinned to full commit SHAs (enforced by a repository setting), hash-pinned build and test tools, CodeQL scanning, OpenSSF Scorecard, Dependabot updates, secret-scanning push protection, and a protected main branch (no force pushes, no deletion).

Found a vulnerability? See SECURITY.md — please use private reporting, not a public issue.

Roadmap

  • --bot mode: create the Discord channel + webhook automatically (bot token).
  • Polling mode for repos you don't administer (releases/commits feeds).
  • Org-wide webhook helper for organization accounts.

License & Attribution

MIT © Ozan Eski — free for everyone and every use, personal or commercial. The one requirement (per the MIT license terms): if you copy, modify, or redistribute this code or a substantial portion of it, you must keep the copyright notice — credit Ozan Eski / gh2discord and link back to this repository.

Metadata

Release files for gh2discord 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for gh2discord 0.2.0
File Size Uploaded
gh2discord-0.2.0.tar.gz 34.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for gh2discord 0.2.0
File Interpreter ABI Platform
gh2discord-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 50.0 kB

Release files / gh2discord-0.2.0.tar.gz

Download URL gh2discord-0.2.0.tar.gz
Size 34.6 kB
Tags Source
SHA-256 checksum
How to use checksums
47ccbb987914ba761fd9bb15fb25ece1731553146a464457f25a0b74ba30b3cf
BLAKE2b-256 checksum
How to use checksums
32e3925876148a82d2ba3d9d862163124788d090fbc40c30d737fc0832beb57b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release files / gh2discord-0.2.0-py3-none-any.whl

Download URL gh2discord-0.2.0-py3-none-any.whl
Size 15.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a621f5fc134ea9836603ffd517a9273b43a98022c0dcafd9073da244a30a8507
BLAKE2b-256 checksum
How to use checksums
e9678125ff44876a98fa604bc8d002d5c130aefed620cf66e8031ccc3839bd79
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 14, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page