A self-hosted Discord bot that forwards GitHub events to your Discord server as rich embeds. Supports multiple repositories, per-repo webhook secrets, automatic channel creation, and a guided DM setup flow for repo owners.
- π¦ Push / commits β branch, commit list with links and authors
- π Pull requests β open, merge, close, review requested
- π Issues β opened, closed, commented, reopened
- π Releases β new release published
- β Stars & forks β community activity
- β GitHub Actions β workflow pass/fail notifications
- ποΈ Multi-repo β monitor unlimited repositories, each with its own channel and secret
- π Per-repo webhook secrets β auto-generated HMAC-SHA256 secret per repository
- π¬ Guided DM setup β admin tags a repo owner; they receive step-by-step instructions via DM with a confirm button
- π Ping verification β GitHub's first ping posts a live confirmation embed in the repo's channel
- π Event muting β silence any event type for 15 minβ24 h without disabling it
- π Live digest β scrollable feed of recent events with outcomes
- π Interactive embeds β refresh, dismiss, undo, and confirm flows throughout
- Node.js v18 or higher
- A Discord server where you have admin permissions
- ngrok (for local development) or a public server
git clone https://github.com/YOUR_USERNAME/discord-github-bot.git
cd discord-github-bot
npm install- Go to the Discord Developer Portal
- Click New Application β give it a name
- Go to Bot β click Add Bot
- Under Token β click Reset Token and copy it
- Enable Server Members Intent and Message Content Intent
- Go to OAuth2 β URL Generator
- Check Scopes:
bot - Check Permissions:
Send Messages,Embed Links,View Channels,Manage Channels - Copy the generated URL and open it in your browser
Manage Channelsis needed so the bot can auto-create a channel per repository.
- In Discord go to Settings β Advanced and enable Developer Mode
- Right-click your server icon β Copy Server ID
cp .env.example .env| Variable | Description |
|---|---|
DISCORD_TOKEN |
Discord Developer Portal β Your App β Bot β Token |
DISCORD_GUILD_ID |
Right-click your server β Copy Server ID |
WEBHOOK_PORT |
Port for the Express server (default 3000) |
WEBHOOK_BASE_URL |
Your public URL β ngrok or permanent domain (see below) |
GITHUB_WEBHOOK_SECRET |
Legacy single-webhook secret (optional, V2 compat) |
ngrok http 3000Copy the https://xxxx.ngrok-free.app URL and set it in your .env:
WEBHOOK_BASE_URL=https://xxxx.ngrok-free.app
Tip: The free ngrok plan gives you a new URL on every restart. Get a free static domain so your URL never changes:
ngrok http --domain=your-static-domain.ngrok-free.app 3000
npm startYou should see:
β
GitBot V3 logged in as YourBot#1234
π Webhook server on port 3000
π Webhook base URL: https://xxxx.ngrok-free.app
In Discord, run:
/repo add repository:owner/repo user:@RepoOwner
- The bot creates a
#github-owner-repochannel automatically - You (admin) get a server reply with the Payload URL and Secret
- The repo owner gets a DM with numbered setup steps and a "I've added the webhook" button
The DM walks them through:
- Go to the repo β Settings β Webhooks β Add webhook
- Paste the Payload URL (e.g.
https://xxxx.ngrok-free.app/webhook/1) - Set Content type to
application/json - Paste the Secret
- Choose events and click Add webhook
- Click "I've added the webhook" in the DM
When GitHub saves the webhook it sends a ping β the bot immediately posts a π GitHub Ping Received embed in the repo's channel to confirm the connection is live. When the user clicks the button:
- The channel gets a
β Webhook Connectedconfirmation embed - You (admin) receive a DM: "[username] has added the webhook for owner/repo"
- The setup DM is automatically deleted
| Command | Description |
|---|---|
/repo add repository:owner/repo [channel:#name] [user:@user] |
Add a repo to monitor. Creates a channel, generates a secret, and optionally DMs setup instructions to the repo owner. |
/repo remove repository:owner/repo |
Permanently remove a repository |
/repo list [detailed:true] |
List all monitored repositories |
/repo info repository:owner/repo |
Show full details with Enable/Disable and Delete buttons |
/repo enable repository:owner/repo enable:true|false |
Toggle a repository on or off |
| Command | Description |
|---|---|
/admin add user:@user |
Grant admin access to a user |
/admin remove user:@user |
Revoke admin access |
/admin list |
List all admins |
Any Discord user with the Administrator permission is automatically treated as an admin.
| Command | Description |
|---|---|
/ping |
Latency check with colour-coded bars |
/status |
Uptime, WS ping, event counters, active mutes |
/events |
Bar chart breakdown of event types since startup |
/digest [count:5β25] |
Scrollable feed of recent GitHub events |
/test [channel:#name] |
Send a test embed to verify bot permissions |
| Command | Description |
|---|---|
/mute event:push [reason:...] |
Silence an event type β duration picker: 15 min / 1 h / 6 h / 24 h |
/watchlist |
View active mutes with one-click Unmute buttons |
| Command | Description |
|---|---|
/clear-stats |
Reset all event counters (with confirmation) |
/help |
Browse full documentation with category dropdown |
| Menu item | Description |
|---|---|
| π Pin to GitHub log | Reposts the message to #github-log with an Acknowledged button |
| π Resend this embed | Re-sends a GitBot embed to any configured channel |
| GitHub Event | What triggers it |
|---|---|
push |
Commits pushed to any branch |
pull_request |
PR opened, merged, closed, review requested |
issues |
Issue opened, closed, reopened |
issue_comment |
New comment on an issue |
pull_request_review |
PR review submitted |
create |
Branch or tag created |
delete |
Branch or tag deleted |
release |
Release published |
star |
Repo starred or unstarred |
fork |
Repo forked |
workflow_run |
GitHub Actions workflow completed |
check_run |
CI check failed or anomalous (successes are silent) |
deployment_status |
Deployment status updated |
ping |
GitHub connectivity test β posts confirmation in repo channel |
- Push this repo to GitHub
- Go to railway.app β New Project β Deploy from GitHub
- Add your environment variables in the Variables tab β set
WEBHOOK_BASE_URLto the auto-generated Railway URL - Use that same URL when running
/repo add
- Push to GitHub β render.com β New Web Service β connect repo
- Add environment variables including
WEBHOOK_BASE_URL
Render's free tier spins down after inactivity (~30 s wake time on first webhook).
git clone https://github.com/YOUR_USERNAME/discord-github-bot.git
cd discord-github-bot
npm install
cp .env.example .env && nano .env # fill in all values including WEBHOOK_BASE_URL
npm install -g pm2
pm2 start index.js --name gitbot
pm2 save && pm2 startupdiscord-github-bot/
βββ index.js # Entry point: Discord client, slash commands, button handlers
βββ multiWebhook.js # Express webhook router β per-repo routing + ping handler
βββ repoCommands.js # /repo and /admin slash commands + DM setup flow
βββ embeds.js # GitHub event β Discord embed formatters
βββ database.js # SQLite store (repositories, admins, tokens)
βββ poller.js # GitHub API polling for repos without webhooks
βββ digest.js # In-memory ring buffer of recent events
βββ mutes.js # In-memory event mute store
βββ help.js # /help command with category dropdown + pagination
βββ config.json # Legacy channel routing (V2 compat, hot-reloaded)
βββ .env # Your secrets β never commit this!
βββ .env.example # Template
βββ .gitignore
βββ package.json
GET http://localhost:3000/health
Returns bot status, version, repo count, active mutes, and event stats.
Pull requests are welcome! To add support for a new GitHub event:
- Add a
formatEventName(payload)function inembeds.js - Add a
casefor it in thebuildEmbed()switch inembeds.js - Add it to
EVENT_CHOICESinindex.jsso it appears in/mute - Add it to the supported events table in this README
MIT β do whatever you want with it.