Step-by-step setup for organizations deploying Gitcord
Use this guide from start to finish. For a shorter overview, see README.md. For Docker details, see docs/DOCKER.md. For environment variables, see environment_variables.md.
- Prerequisites
- Step 1: Create GitHub Token (PAT)
- Step 2: Create Discord Bot
- Step 3: Invite Bot to Discord Server
- Step 4: Get the Code
- Step 5: Choose Installation Method
- Step 6: Configure Gitcord
- Step 7: Run Gitcord
- Step 8: Enable Active Mode (after testing)
- Security Best Practices
- Troubleshooting
- Quick Reference
Before starting, ensure you have:
| Requirement | Docker install | Local install |
|---|---|---|
| Git | ✅ | ✅ |
| Docker Engine + Docker Compose v2 | ✅ | — |
| Python 3.11+ | — | ✅ |
| GitHub org access and a fine-grained PAT | ✅ | ✅ |
| Discord server admin access | ✅ | ✅ |
| Discord Developer Portal access | ✅ | ✅ |
Windows users: Use WSL2 (Ubuntu) for the local Python path. Docker Desktop on Windows is supported when the project lives on the WSL filesystem.
- Go to GitHub → Settings → Developer Settings
- Click Personal Access Tokens → Fine-grained tokens
- Click Generate new token
Token name: Gitcord Bot (or your preferred name)
Expiration: Set appropriate expiration (recommended: 90 days or custom)
Resource owner: Select your organization (not only your personal account) if Gitcord will scan org repositories.
Repository access:
- Only select repositories (recommended), or
- All repositories (org-wide access)
| Permission | Access level | Why |
|---|---|---|
| Contents | Read (Write if using snapshots) | Repo metadata; Write for GitHub snapshots |
| Issues | Read & Write | Issue assignment |
| Pull requests | Read & Write | Review requests, merge status |
| Metadata | Read | Required automatically by GitHub |
For initial dry-run testing, Read on Contents/Issues/PRs is enough. Enable Write before active mode if you need assignments or snapshots.
- Click Generate token
- Copy the token immediately (you will not see it again)
- Save it securely — you will add it to
.envin Step 6
- Go to Discord Developer Portal
- Click New Application
- Enter application name:
Gitcord(or your preferred name) - Click Create
Use the official Gitcord icon so members recognize the bot in your server:
| File | Use |
|---|---|
public/gitcord-discord-icon-large.png |
App Icon and Bot Icon (1024×1024 PNG) |
public/gitcord-white-bg.png |
Optional alternate (white background) |
- In the Developer Portal, open General Information
- Under App Icon, click the upload area and select
public/gitcord-discord-icon-large.png - Save changes
- Open Bot (left sidebar) → under Icon, upload the same file (App Icon alone does not always update the in-server avatar)
Discord accepts PNG/JPG; square 512×512 or 1024×1024 works best.
- Open the Bot section (left sidebar)
- Click Add Bot → Yes, do it!
- Public Bot: off (unless you want others to invite it)
- Requires OAuth2 Code Grant: off
Under Bot → Privileged Gateway Intents:
| Intent | Required? |
|---|---|
| Server Members Intent | ✅ Yes — member listing for role planning |
| Presence Intent | ❌ No |
| Message Content Intent | ❌ No (only if you enable pr_preview_channels in config) |
- Click Reset Token (or copy the existing token)
- Copy the token immediately
- Save it for
.envin Step 6
- Go to OAuth2 → URL Generator
- ✅
bot - ✅
applications.commands - ❌ Do not use Administrator scope
Required:
- Manage Roles, View Channels
- Send Messages, Embed Links, Read Message History, Use Slash Commands
Not needed: Administrator, Manage Server, Kick/Ban Members, Manage Channels, Voice permissions
- Copy the generated URL and open it in a browser
- Select your Discord server → Authorize
- In Discord: Server Settings → Roles
- Drag the bot role above any roles it should assign (e.g. above
Contributor)
If the bot role is too low, role changes fail silently.
- Enable Developer Mode: User Settings → Advanced → Developer Mode
- Right-click your server icon → Copy Server ID
You will paste this into discord.guild_id in config.
git clone https://github.com/AOSSIE-Org/Gitcord-GithubDiscordBot.git
cd Gitcord-GithubDiscordBotForks: clone your fork URL instead; the rest of the guide is the same.
Best if you want to skip Python setup. Requires Docker Engine and Compose v2.
cp .env.example .env
cp config/docker-example.yaml config/config.yaml
# Edit .env (tokens) and config/config.yaml (github.org, discord.guild_id)
docker compose up -d
docker compose logs -f bot- Config file:
config/config.yaml(fromconfig/docker-example.yaml) data_dirmust stay/data(Docker volume)- One-time sync:
docker compose run --rm bot --config /app/config/config.yaml run-once
See docs/DOCKER.md for pitfalls and audit workflow.
python3 -m venv .venv
source .venv/bin/activate # Windows WSL: same; native Windows: .venv\Scripts\activate
pip install -e .
cp .env.example .env
cp config/example.yaml config/config.yaml
# Edit .env and config/config.yaml (see Step 6)
ghdcbot --config config/config.yaml run-once
ghdcbot --config config/config.yaml botGitcord uses
pyproject.toml, notrequirements.txt. Install withpip install -e ..
Set a local data directory in config/config.yaml:
runtime:
data_dir: "./data"Reports appear under ./data/reports/.
- Recommended: Install WSL2 with Ubuntu, clone the repo inside WSL (
~/projects/...), and follow Option B or Option A there. - Docker Desktop: Enable WSL2 integration; run
docker composefrom the WSL shell where the repo lives. - Volume mounting: Keep the repo on the Linux filesystem (
/home/...), notC:\..., so bind mounts and file permissions work reliably. - Native Windows Python is possible but not officially tested; prefer WSL.
cp .env.example .envEdit .env:
GITHUB_TOKEN=your_github_token_here
DISCORD_TOKEN=your_discord_bot_token_hereDetails: environment_variables.md
Your active config is always config/config.yaml (gitignored — create it from a template):
| Install type | Copy from |
|---|---|
| Docker | config/docker-example.yaml |
| Local Python | config/example.yaml |
| Remote org settings (AOSSIE) | config/examples/bootstrap-remote-aossie.yaml + publish config/examples/remote-gitcord-aossie.yaml to AOSSIE-Org/.github/gitcord.yaml |
| Remote org settings (Stability Nexus) | config/examples/bootstrap-remote-stability-nexus.yaml + publish config/examples/remote-gitcord-stability-nexus.yaml to StabilityNexus/.github/gitcord.yaml |
Minimum edits (local full config):
github.org— your GitHub organization namediscord.guild_id— server ID from Step 3.6role_mappings/assignments.issue_assignees— use exact Discord role names that exist in your server- Local only:
runtime.data_dir: "./data"
Remote config: with remote_config.enabled: true, org settings (channels, repos, notifications, guild id) load from GitHub. The local file only needs runtime.data_dir, remote_config, and token placeholders. Edit channel maps on GitHub, then restart Gitcord to pick up changes. Tokens never go in the remote file.
Start with defaults in the template:
runtime.mode: "dry-run"discord.permissions.write: falsegithub.permissions.write: false
Optional blocks (notifications, snapshots, repos filter) are commented in config/example.yaml — enable only when needed.
Reference configs (not used automatically): config/examples/ (e.g. AOSSIE sample, remote bootstrap templates).
Before your first sync or bot start, run the read-only preflight check. It loads config, verifies tokens against GitHub and Discord, checks guild access, and (when enable_discord_role_updates: true) confirms configured Discord roles exist.
Docker:
docker compose run --rm bot --config /app/config/config.yaml validateLocal:
ghdcbot --config config/config.yaml validateExample success output:
✓ Config file loaded
✓ YAML valid and schema OK
✓ GITHUB_TOKEN configured
✓ DISCORD_TOKEN configured
✓ GitHub authentication successful
✓ Discord authentication successful
✓ Organization accessible
✓ Repositories visible
✓ Guild found
✓ Role "Contributor" found
Validation passed.
Exit code 0 means ready to run; 1 means fix the reported issues first. No data is written and the bot does not start.
Validates GitHub/Discord access and writes audit reports without mutating roles or issues.
Docker:
docker compose run --rm bot --config /app/config/config.yaml run-onceLocal:
ghdcbot --config config/config.yaml run-onceExpected:
- GitHub events ingested (may be zero on a quiet org)
- Discord members/roles read (needs Server Members Intent)
- Reports written to
<data_dir>/reports/audit.jsonandaudit.md
Review audit.md before enabling active mode.
Docker:
docker compose up -d
docker compose logs -f botLocal:
ghdcbot --config config/config.yaml botExpected log line:
Bot ready; slash commands synced for guild YOUR_GUILD_ID: ['link', 'verify-link', ...]
Wait ~30 seconds after startup for slash commands to appear.
Background (local Linux/macOS):
nohup ghdcbot --config config/config.yaml bot > bot.log 2>&1 &Contributors: /link, /verify-link, /profile (optional Discord member), /summary (optional Discord member for another verified contributor), /open-prs, /pr, /unlink, /connect-social, /disconnect-social
Mentors (need Mentor role or discord.command_permissions): /sync
See docs/TESTING_DISCORD.md for a full test sequence.
Only after reviewing dry-run audit.md:
- Edit
config/config.yaml:
runtime:
mode: "active"
enable_discord_role_updates: true
discord:
permissions:
write: true
github:
permissions:
write: true # if you use issue assignment or snapshots- Run
run-onceagain (Docker or local command from §7.1) - Confirm role changes in Discord and bot role hierarchy
enable_discord_role_updates: false prevents Discord role changes even if mode is mis-set — keep it false until you are ready.
- Use fine-grained GitHub tokens
- Store tokens in
.envonly - Start in dry-run; review audit reports
- Keep bot role above managed roles
- Enable minimal Discord permissions (no Administrator)
- Commit
.envorconfig/config.yamlwith secrets - Enable active mode without a dry-run review
- Share tokens in chat or screenshots
- Confirm bot is running (
docker compose logs -f botorps aux | grep ghdcbot) - Wait 30s after startup for command sync
- Verify
applications.commandsscope on invite URL - Confirm
discord.guild_idmatches your server
- Bot role above target roles in Server Settings → Roles
runtime.mode: activeandenable_discord_role_updates: truediscord.permissions.write: true- Server Members Intent enabled in Developer Portal
Missing required environment variable: GITHUB_TOKEN
Create .env in the project root with both tokens. Docker: same directory as docker-compose.yml.
Config file does not exist: ...
Run cp config/docker-example.yaml config/config.yaml (Docker) or cp config/example.yaml config/config.yaml (local).
Run ghdcbot --config config/config.yaml validate (or the Docker equivalent) after editing .env and config.
| Message | Fix |
|---|---|
GITHUB_TOKEN is missing |
Add token to .env |
GitHub authentication failed |
Regenerate PAT; confirm org access |
Discord authentication failed |
Reset bot token in Developer Portal |
Guild not found |
Re-invite bot; fix discord.guild_id |
Role "…" not found |
Create role in Discord or fix YAML spelling |
- Put verification code in GitHub bio or a public gist
- Code expires in 10 minutes — run
/linkagain if needed - See docs/IDENTITY_VERIFICATION.md
Contributors link their X or LinkedIn manually — no external setup required:
/connect-social— pick a platform and enter your X username (e.g.@name) or LinkedIn URL/disconnect-social— remove a linked profile
Linked profiles show up in /profile.
- Token not expired; org resource owner selected correctly
- Token has access to target repositories
github.permissions.read: truein config
Keep data_dir: "/data" in config; do not remove the gitcord_data volume.
| Action | Docker | Local |
|---|---|---|
| Start bot | docker compose up -d |
ghdcbot --config config/config.yaml bot |
| Logs | docker compose logs -f bot |
terminal output / bot.log |
| Dry-run sync | docker compose run --rm bot --config /app/config/config.yaml run-once |
ghdcbot --config config/config.yaml run-once |
| Validate setup | docker compose run --rm bot --config /app/config/config.yaml validate |
ghdcbot --config config/config.yaml validate |
| Identity status | docker compose run --rm bot --config /app/config/config.yaml identity status --discord-user-id ID |
ghdcbot --config config/config.yaml identity status --discord-user-id ID |
| File | Purpose |
|---|---|
config/config.yaml |
Your active config (create from template; gitignored) |
config/example.yaml |
Local template |
config/docker-example.yaml |
Docker template (data_dir: /data) |
config/examples/ |
Reference configs only |
.env |
Tokens (from .env.example) |
Contributors: /link, /verify-link, /profile (optional Discord member), /summary (optional Discord member), /open-prs, /pr, /unlink, /connect-social, /disconnect-social
Mentors: /sync
- Dry-run
run-once→ reviewaudit.md - Start bot → test
/linkand/verify-link - Match
merge_role_rules/repo_contributor_rolesto your Discord roles - Enable active mode when ready
- Schedule periodic
run-once(cron/systemd) if needed
- README.md — overview and architecture
- docs/DOCKER.md — Docker deployment
- environment_variables.md — env var reference
- TECHNICAL_DOCUMENTATION.md — architecture deep dive
- GitHub Issues
Start in dry-run mode, review reports, then go active.