* feat(channels): dispatch GitHub notifications by reason Route each GitHub notification by notification.reason into one of five lanes, instead of dispatching every new comment regardless of trigger: - mention: only dispatch comments that actually @ the bot (noise reduction) - review_requested (PR): fetch PR meta via pulls.get and dispatch a review-specific prompt, even with no new comments - assign: fetch issue meta and dispatch a triage-specific prompt - author/comment: aggregate the window's new comments into one check-and- respond prompt - other reasons: generic fallback (current behavior) Add cursor dedup via dispatchedComments (by comment node_id) and dispatchedNotifications (by notification id), surviving a markNotificationsAsRead failure that leaves the cursor un-advanced. Closes #7807 * fix(channels): mark review_requested/assign envelopes as mentioned GroupGate defaults to requireMention: true, which silently drops isMentioned:false envelopes as 'mention_required'. The review_requested and assign lanes are explicit directed triggers — the bot was asked to review or assigned — equivalent to a mention, so set isMentioned: true so they pass the gate instead of being inert on the documented default config. Addresses review Critical on #7826. * fix(channels): resolve github routing review comments * fix(channels): dedupe github meta lane comments * fix(channels): conditional assign framing for PR threads The assign route already detected PR threads to use pulls.get, but the trigger framing text always read 'assigned to this issue' even for PRs. Make it conditional so PR assignments read 'assigned to this pull request'. * fix(channels): dedup meta lane dispatch inputs * fix(channels): simplify GitHub reason dispatch * fix(channels): respect mention gate for github aggregate lane * fix(channels): truncate aggregate comment bodies by code points Match the code-point-aware truncation already used for meta-lane bodies so a supplementary-plane emoji at the MAX_COMMENT_CHARS boundary is not split into a lone surrogate. * fix(channels): harden GitHub dispatch failures, event window, and framing (#7826) - Classify deleted/transferred subjects (404/410) as terminal so a single dead notification is logged and skipped instead of wedging the batch's mark-read and cursor advance every poll. - Widen the review_requested/assign event search to the newest ~100 events by merging the preceding page when the last page is partial, instead of inspecting only the last page (which can hold a single event). - Move the aggregate lane's untrusted-data warning to the head of the prompt text so it precedes the comment text it describes (metadata is appended after text by ChannelBase). - Add regression tests: permanent-failure two-poll advance, terminal 404 no-retry, multi-page event search, prompt caps, and the no-actor guard. * fix(channels): drop lastReadAt filter in findMetaTrigger, add review coverage (#7826) * fix(github): keep aggregate and meta windows bounded * fix(channels): apply windowSince lower bound in findMetaTrigger (#7826) * fix(channels): bound retry wedge, compute aggregate isMentioned, fix pairing pre-filter (#7826) * fix(github): record dispatch before handler * fix(github): persist skipped notifications * fix(github): close dispatch retry loss cases * test(github): cover cursor trim and meta floor validation * fix(github): simplify notification reason dispatch * fix(github): preserve batched dispatch comments * fix(github): restore direct event dedup * fix(github): preserve directed mention context * fix(github): keep review fixes scoped * fix(github): preserve delayed direct triggers --------- Co-authored-by: Shaojin Wen <shaojin.wensj@alibaba-inc.com> Co-authored-by: Qwen Code Autofix <qwen-code-autofix@users.noreply.github.com> Co-authored-by: Qwen Code <qwen-code@users.noreply.github.com> Co-authored-by: qwen-code-ci-bot <qwen-code-ci-bot@users.noreply.github.com> Co-authored-by: Qwen Code Bot <qwen-code-bot@users.noreply.github.com>
5.4 KiB
GitHub
This guide covers setting up a Qwen Code channel that monitors GitHub notifications and responds to mentions, review requests, assignments, and followed-thread activity.
Prerequisites
- A GitHub account (or a dedicated bot account)
- A GitHub Personal Access Token (PAT) with
notificationsandpublic_repo(orrepo) scopes
Creating a Token
- Go to Settings → Developer settings → Personal access tokens → Tokens (classic)
- Generate a token with these scopes:
- notifications — read notification threads
- public_repo (or repo for private repos) — post comments
- Save the token securely as an environment variable
Configuration
Add the channel to ~/.qwen/settings.json:
{
"channels": {
"my-github": {
"type": "github",
"token": "$GITHUB_TOKEN",
"pollInterval": 60000,
"senderPolicy": "allowlist",
"allowedUsers": ["your-github-username"],
"sessionScope": "chat_thread",
"cwd": "/path/to/your/project",
"groupPolicy": "open",
"groups": {
"*": { "requireMention": true }
}
}
}
}
Set the token as an environment variable:
export GITHUB_TOKEN="ghp_your_token_here"
GitHub Enterprise
For GitHub Enterprise Server, set baseUrl:
{
"baseUrl": "https://github.example.com/api/v3"
}
Configuration Options
| Option | Default | Description |
|---|---|---|
token |
(required) | Classic PAT with notifications scope |
pollInterval |
60000 |
Poll interval in ms |
baseUrl |
https://api.github.com |
API base URL (for GHE) |
groupPolicy |
"disabled" |
Must be "open" for notifications to flow |
senderPolicy |
"allowlist" |
Who can trigger the bot |
groups.*.requireMention |
true |
Require @mentions for ordinary comments; directed notification reasons still run |
⚠️ Security
On a public repository, setting senderPolicy: "open" allows any GitHub user who triggers a supported notification reason to submit prompts that drive the agent in your cwd. This includes reading code, spending tokens, posting comments, and (subject to permission policy) running tools.
Always use senderPolicy: "allowlist" with explicit allowedUsers on public repos.
Allowlist and pairing entries follow the username, not the immutable account ID. If an allowlisted user renames their GitHub account, remove the stale entry — GitHub releases the old username for anyone else to claim, and the new holder would inherit the allowlist/pairing authorization.
Mention Detection
The adapter detects mentions by scanning comment text and first-contact issue or PR bodies for @bot-username using a case-insensitive regex. It does not trust reason: "mention" alone because that value is sticky at the thread level. Other reasons select review, triage, followed-thread, or fallback prompts.
How It Works
The adapter uses GitHub's Notifications API as a wake-up signal:
- Poll
GET /notificationsfor unread threads - Mark read via
markNotificationsAsRead(best-effort cleanup, before processing) - Enumerate comments via
listCommentswithin a cursor-based time window - Dispatch by notification reason: strict mention matching, pull request review, issue triage, followed-thread comment aggregation, or per-comment fallback
- First-contact fallback: a brand-new unread issue/PR body can be processed when no comment was dispatched; mention notifications still require an actual body mention
The comment window is (previousCursor, currentMaxUpdatedAt] — comments already eligible in a previous poll cycle are excluded by the cursor, preventing duplicate replies even when the async mark-read has not taken effect. If the process crashes mid-processing, the user can re-mention the bot to retry.
Non-comment activity (push, label changes) bumps the notification's updated_at but produces zero new comments in the window, so re-fetched threads are skipped without triggering the agent.
Known Limitations
- First start skips existing unread notifications. The cursor initializes to "now" on first launch. Notifications created before the bot starts are not processed unless the thread receives new activity afterwards.
- If a user marks a notification as read on github.com before the bot's poll cycle, the bot will not process it.
- The bot does not read comments before the current polling window;
authorandcommentnotifications may aggregate up to 20 comments from that window. - Inline PR review comments and review summary bodies are not enumerated; only issue/PR comments are processed.
- Requires a classic PAT with
notificationsscope. Fine-grained PATs do not support the notifications API.
Starting the Channel
qwen channel start my-github