This guide covers deploying your own instance of the reviewGOOSE Discord bot.
- A Google Cloud Platform project (for Cloud Run deployment)
- Access to create Discord applications
- Access to create GitHub Apps
- Go to the Discord Developer Portal
- Click "New Application" and give it a name (e.g., "reviewGOOSE")
- Note down the Application ID (also called Client ID)
- In your application, go to the "Bot" section
- Click "Add Bot"
- Under "Privileged Gateway Intents", enable:
- Server Members Intent (for user lookups)
- Message Content Intent (for commands)
- Click "Reset Token" and copy the Bot Token — save this securely
Go to "OAuth2" -> "URL Generator":
- Scopes:
bot,applications.commands - Bot Permissions:
- Send Messages
- Create Public Threads
- Send Messages in Threads
- Embed Links
- Read Message History
- Use Slash Commands
The permissions integer is 2147485696.
Create a GitHub App for repository access. See the GitHub App documentation.
Required permissions:
- Repository contents: Read
- Pull requests: Read
- Metadata: Read
Subscribe to webhook events:
- Pull requests
- Pull request reviews
- Check runs
# GitHub App credentials
GITHUB_APP_ID=123456
GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
# Discord Bot token
DISCORD_BOT_TOKEN=MTIz...# Port to listen on (default: 9119)
PORT=9119
# GCP project for Secret Manager
GCP_PROJECT=my-project
# Sprinkler WebSocket URL (default: production)
SPRINKLER_URL=wss://webhook.github.codegroove.app/ws
# Turn API URL (default: production)
TURN_URL=https://turn.github.codegroove.app
# Allow personal GitHub accounts (default: false)
ALLOW_PERSONAL_ACCOUNTS=false# Set your GCP project
export GCP_PROJECT=my-project
# Deploy
./hacks/deploy.sh# Build
docker build -t discordian .
# Run (uses local filesystem for persistence outside Cloud Run)
docker run -p 9119:9119 \
-e GITHUB_APP_ID=... \
-e GITHUB_PRIVATE_KEY=... \
-e DISCORD_BOT_TOKEN=... \
discordian# Set environment variables
export GITHUB_APP_ID=...
export GITHUB_PRIVATE_KEY=...
export DISCORD_BOT_TOKEN=...
# Run
go run ./cmd/serverThe bot automatically reads secrets from Google Cloud Secret Manager. Environment variables take precedence if set.
# Create secrets (use the exact names as environment variables)
echo -n "your-bot-token" | gcloud secrets create DISCORD_BOT_TOKEN --data-file=-
echo -n "your-private-key" | gcloud secrets create GITHUB_PRIVATE_KEY --data-file=-
# Grant access to service account
for secret in DISCORD_BOT_TOKEN GITHUB_PRIVATE_KEY; do
gcloud secrets add-iam-policy-binding $secret \
--member="serviceAccount:discordian@${GCP_PROJECT}.iam.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"
doneSecrets loaded from Secret Manager:
DISCORD_BOT_TOKEN- Discord bot tokenGITHUB_PRIVATE_KEY- GitHub App private key
The bot uses Google Cloud Datastore for persistent state. You must create these databases before deploying:
# Create required Datastore databases
for db in discordian-threads discordian-dms discordian-dmusers discordian-reports discordian-pending discordian-events discordian-claims; do
gcloud firestore databases create --database=$db --location=nam5 --type=datastore-mode
doneDatabases:
| Database | Purpose | TTL |
|---|---|---|
discordian-threads |
PR to Discord thread/message mapping | 30 days |
discordian-dms |
DM message tracking | 7 days |
discordian-dmusers |
DM user lists (prURL → user IDs) | 7 days |
discordian-reports |
Daily report tracking | 36 hours |
discordian-pending |
Pending DM queue | 4 hours |
discordian-events |
Event deduplication (cross-instance safety) | 2 hours |
discordian-claims |
Distributed claims (prevents duplicate threads) | 10 seconds |
Optional: Enable TTL for automatic cleanup
for db in discordian-threads discordian-dms discordian-dmusers discordian-reports discordian-pending discordian-events discordian-claims; do
gcloud firestore fields ttls update expiry \
--collection-group=CacheEntry \
--enable-ttl \
--database=$db
doneThis automatically deletes expired entries within 24 hours.
GitHub Webhooks
|
v
Sprinkler (WebSocket hub)
|
v
Discordian
|
+---> Turn API (PR analysis)
|
+---> Discord API
The bot:
- Connects to Sprinkler via WebSocket for real-time GitHub events
- Discovers all orgs with the GitHub App installed
- For each org with
.codeGROOVE/discord.yaml, starts monitoring PRs - Posts/updates notifications to configured Discord channels
- Queues DM reminders with configurable delays
- Persists state to Datastore (Cloud Run) or local filesystem (development)
Persistence: State survives restarts via fido cache with Datastore backend. This includes:
- Thread/message IDs (so updates go to existing messages)
- Pending DM queue (delayed notifications survive restarts)
- Daily report tracking (prevents duplicate reports)
- Event deduplication (prevents duplicate processing across instances)
- Distributed claims (prevents duplicate threads during rolling deployments)
- sprinkler - WebSocket hub for GitHub webhooks
- turnturnturn - PR state analysis
- discordgo - Discord API library
- fido - High-performance cache with Datastore persistence
make fmt # Format code
make lint # Run linters
make test # Run tests
make build # Build binary- Check that the GitHub App is installed on the target orgs
- Look for "discovered GitHub installation" in logs
- Verify
GITHUB_APP_IDandGITHUB_PRIVATE_KEYare correct
- Check
SPRINKLER_URLis correct - Look for WebSocket connection errors in logs
- Verify network connectivity to the Sprinkler service