Quick answer: Pick one tool as the source of truth (your bug tracker). Mint a canonical ID for every bug. Every PR, commit, Slack thread, and design doc references the ID, never duplicates the bug details. Install a Slack unfurl bot and PR webhooks so the references resolve automatically to current status.
A senior engineer reads a Slack thread about “that physics crash from last week.” She checks GitHub and finds three PRs that mention “physics crash.” None of them link to the tracker. The tracker has four open crashes, two of which could match. Thirty minutes later she still doesn’t know whether the bug she’s about to start working on is already fixed. The fix is not another tool. It’s a discipline: one ID everywhere, one source of truth.
Pick the Canonical ID Format
Your bug tracker mints the IDs. Use a short prefix that’s easy to type and hard to confuse with other IDs. BUG-412, FOX-2103 (initials of the game), QA-88. Whatever you pick, stick to it — changing the prefix a year in leaves a long tail of references that no longer match.
Avoid collisions with your engine’s own numbering (Unity UUM- or Unreal UE-) and with anything that already means something in your engineering lingo. Your bots will run regexes on these, and a false positive (BUG- inside a URL or a file name) is annoying.
Set the One Rule
The rule is: if it relates to a bug, it references the bug’s canonical ID.
- PR title:
[BUG-412] Fix boss despawn on phase transition. - Commit message:
Fix null check for despawned boss (BUG-412). - Slack thread first message:
Following up on BUG-412 — repro is easier on medium difficulty. - Design doc: a link to
tracker/BUG-412, not a copy of the bug title.
Anything that breaks the rule either goes through review and gets fixed or gets flagged by a bot. Over time the team internalizes the habit.
Bot Integrations That Earn Their Keep
Slack unfurl bot. When someone mentions BUG-412 in a channel, the bot replies with a small preview: title, current status, assignee, and a link. Readers don’t have to context-switch. Writing your own is a half-day of work against the Slack API — listen for message events, regex for BUG-\d+, call the tracker API, post a reply.
# Minimal Slack bot in Python (Bolt)
import re, requests
from slack_bolt import App
BUG_RE = re.compile(r"\bBUG-(\d+)\b")
app = App(token=SLACK_BOT_TOKEN)
@app.message(BUG_RE)
def unfurl(message, say):
for m in BUG_RE.finditer(message["text"]):
bug = requests.get(f"https://bugnet.io/api/bugs/BUG-{m.group(1)}").json()["data"]
say(
thread_ts=message["ts"],
text=f"*{bug['id']}*: {bug['title']}\nStatus: {bug['status']} Assignee: {bug['assignee']}"
)
GitHub PR webhook. When a PR is opened or merged, parse the title for BUG-\d+ and tell the tracker. The tracker links the PR, which then appears as “Fix in progress” on the bug page. On merge, it auto-transitions to “awaiting QA.” The discipline is enforced by making the convenient path also the correct one.
Commit hook. Optional, but cheap. A pre-push hook warns when commits don’t reference a bug ID and the branch name doesn’t suggest a chore. It’s a nudge, not a block — hotfix branches bypass it.
One Source of Truth, Always
Every tool has a temptation to become the source of truth. Slack threads grow into rich histories that feel authoritative. PRs accumulate detailed debugging conversations. Google Docs fill with screenshots. Resist all of that.
The bug tracker carries the bug’s state over its whole life. Slack threads lock after 90 days. PRs close. Docs get forgotten. If the bug tracker doesn’t have the information, the information is gone. So: attach screenshots to the tracker, copy the key findings from the Slack thread back, and link out from the tracker to the PR — not the reverse.
What to Put Where
A quick reference to settle arguments:
- Bug tracker: title, repro, severity, assignee, fix status, attachments, all test notes.
- PR: code change, review conversation, test plan. Link to the bug.
- Slack: ephemeral coordination, quick questions. Link to the bug. Move anything you want to keep back into the tracker.
- Design doc: context that spans many bugs (a systemic design issue). Link to individual bugs, don’t copy them.
Cleaning Up Drift
Even with rules, drift happens. A quarterly cleanup script helps:
- Find PRs merged in the last quarter with no linked bug. Ask the author whether one exists.
- Find bugs marked “fix in progress” for more than 30 days with no recent PR activity. Nudge the assignee.
- Find bugs closed as “duplicate” with different canonical IDs than their twin. Merge.
The script doesn’t need to fix anything automatically. A Slack DM to the owner is usually enough. The value is visibility — the drift is the defect; the fix is the owner’s to make.
“The measure of a good tracker isn’t how many bugs are in it. It’s how often the question ‘what’s the status?’ can be answered in one link.”
Related Issues
For decision records that pair with links, see how to write a bug triage decision log. For picking the right tool to be that source of truth, see bug tracker comparison for indie developers.
One ID. One tool of record. Everything else links, nothing else owns.