# Discord Github Correlator

> Use when correlating Discord channel discussions with GitHub repository issues. Finds which open issues relate to recent Discord conversations by matching topics, keywords, and direct links. Works with any guild/channel and any GitHub repo.

- Skill: `olaservo/discord-github-correlator` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add olaservo/discord-github-correlator`
- Raw SKILL.md: https://api.skillmd.com/api/skills/olaservo/discord-github-correlator/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: olaservo (https://skillmd.com/u/olaservo)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/olaservo/discord-github-correlator

---


# Discord ↔ GitHub Issue Correlator

## When to Use

Use this skill when:
- A user asks to "correlate", "match", or "find connections" between Discord discussions and GitHub issues
- They want to know which issues are being discussed in a Discord channel
- They need to prioritize issues based on community discussion activity
- They reference both a Discord server/channel and a GitHub repository

**Trigger even when**: The user doesn't explicitly say "correlation" — requests like "what GitHub issues relate to the auth-ig channel?" or "find issues discussed in Discord" should activate this skill.

## Instructions

### 1. Gather Parameters

Required:
- **Guild ID**: Discord server ID (numeric string)
- **Channel ID**: Discord channel ID (numeric string)
- **GitHub owner**: Repository owner (e.g., `anthropics`)
- **GitHub repo**: Repository name (e.g., `claude-code`)

Optional:
- **Keywords**: Domain-specific keywords to look for (auth, performance, etc.)
- **Message limit**: How many recent Discord messages to fetch (default: 100)
- **Top correlations**: How many correlated issues to show (default: 15)

### 2. Fetch Discord Messages

Use the `guildbridge` MCP server:

```typescript
import * as guildbridge from './servers/guildbridge';

// IMPORTANT: read_messages returns a BARE ARRAY of message objects
// ({ id, author, content, timestamp, ... }) — NOT an object with a
// `.messages` property. Newest-first; paginate older with `before`.
const messages: any[] = [];
let before: string | undefined;

while (messages.length < MESSAGE_LIMIT) {
  const batch = await guildbridge.read_messages({
    channel_id: CHANNEL_ID,
    limit: 50,
    before, // for pagination (id of the oldest message seen so far)
  });
  const arr = Array.isArray(batch) ? batch : batch?.messages ?? [];
  if (arr.length === 0) break;
  messages.push(...arr); // each item: { id, author, content, timestamp }
  before = arr[arr.length - 1].id;
}
```

Extract from each message:
- GitHub links (regex: `https?://github\.com/[^\s)]+`)
- Topics/keywords (case-insensitive matching)
- RFC references (regex: `rfc\s*\d{4}`)

### 3. Fetch GitHub Issues

Use the `github` MCP server. **Prefer search over list_issues** for large repos:

```typescript
import * as github from './servers/github';

// Approach A: Targeted search (recommended for keyword-heavy domains)
const searches = [
  `repo:${OWNER}/${REPO} is:open is:issue keyword1`,
  `repo:${OWNER}/${REPO} is:open is:issue keyword2`,
  // Add more searches for different keywords
];

for (const query of searches) {
  const response = await github.search_issues({ query, per_page: 100 });
  // Deduplicate by issue number
}

// Approach B: Full list (use only if search isn't applicable)
let cursor: string | undefined;
while (true) {
  const response = await github.list_issues({
    owner: OWNER,
    repo: REPO,
    state: 'open',
    first: 100,
    after: cursor
  });
  // ...
}
```

Extract: number, title, url, labels, createdAt, updatedAt, body (excerpt)

### 4. Score Correlations

For each issue, calculate a relevance score:

**Topic matches** (+2 per topic, weighted by Discord frequency):
- If a topic appears in the issue title/body, score += (Discord_mention_count × 2)

**Direct links** (+20 per link):
- If a Discord message links to this issue URL, strong signal

**Label matches** (+5 per relevant label):
- Check if issue labels include keywords (e.g., "auth", "mcp", "security")

**Keyword overlap** (+1 per significant keyword):
- Extract meaningful words from issue title (length > 4, not stopwords)
- If ≥2 keywords appear in a Discord message, score += matches

**Recency boost** (+5 if updated in last 30 days):
- Recent updates suggest active discussion

**Comment activity** (+0.2 per comment, max +10):
- High comment count indicates active discussion

### 5. Generate Report

Save three files to `./workspace/`:

1. **Raw Discord data**: `<channel-name>-messages.json`
2. **Raw GitHub data**: `<repo>-open-issues.json`
3. **Markdown report**: `<channel>-<repo>-correlation.md`

Report structure:

```markdown
# [Channel] ↔ [Repo] Correlation Report

Generated: [timestamp]

## Summary
- Discord messages analyzed: N
- Open issues analyzed: M
- Meaningful correlations found: K
- Top correlations shown: top 15

## Topics Extracted from Discord
| Topic | Mentions |
|-------|----------|
| topic1 | count |

## Top Correlated Issues
### 1. [#NUM] Issue Title
**Score:** X | **Comments:** Y | **Updated:** date
**URL:** link
**Labels:** label1, label2
**Matched Topics:** topic1, topic2
**Rationale:** matches topics X; directly linked in Y message(s); auth-related labels

<details>
<summary>Issue Description (excerpt)</summary>
> [First 300 chars of body]
</details>

---

## How to Read This Report
### Scoring
- Topic matches: weighted by frequency
- Direct links: +20 per link
- Auth labels: +5 per label
- Keyword overlap: multiple shared keywords

### Next Actions
1. Review top correlations
2. Cross-link Discord threads to issues
3. Triage using Discord context
4. Engage Discord participants in relevant issues
```

## Gotchas

- **read_messages return shape**: it returns a **bare array** of message objects, not `{ messages: [...] }`. Accessing `response.messages` yields `undefined` and silently looks like "0 messages" — the most common cause of an empty Discord result here. Always treat the result as the array itself (`Array.isArray(batch) ? batch : batch?.messages ?? []`).
- **Discord pagination**: `read_messages` with `before` returns older messages (pass the id of the oldest message seen). It is fast (≈1–3s for 50–80 messages).
- **GitHub auth errors**: `list_issues` may hit rate limits or auth failures mid-fetch. Wrap the loop in try-catch and save partial results.
- **Pull requests in issue lists**: Some APIs return PRs in issue endpoints. Filter with: `if (issue.url?.includes('/pull/')) continue;`
- **Score normalization**: Scores are relative, not absolute. A score of 40 vs 10 is meaningful; 40 vs 38 might not be.
- **Large repos**: anthropics/claude-code has 3500+ issues. Use `search_issues` with targeted queries instead of fetching all issues. Example: `repo:anthropics/claude-code is:open is:issue authentication`.
- **Empty Discord channels**: If a Discord channel is invite-only or you lack read permissions, the API returns 0 messages without error. Test with a known-readable channel first.

## Example Usage

```typescript
// For auth-ig Discord channel + anthropics/claude-code issues
const GUILD_ID = '1358869848138059966';  // MCP Contributors
const CHANNEL_ID = '1360835991749001368';  // auth-ig
const OWNER = 'anthropics';
const REPO = 'claude-code';

const AUTH_KEYWORDS = [
  'dpop', 'mtls', 'oauth', 'oidc', 'token refresh',
  'www-authenticate', 'authorization server', 'client registration',
  'scopes', 'bearer token', 'mcp auth'
];

// Follow steps 1-5 above
```

## Related Tools

- `guildbridge` MCP server: `read_messages`, `list_guilds`, `list_channels`
- `github` MCP server: `search_issues`, `list_issues`, `issue_read`

## Changelog

- 2026-06-21: Initial version based on auth-ig correlation task

