[N11b] githubChannel(): the agent answers issue and pull-request comments - #306
Merged
Merged
Conversation
…ents Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
1 task
This was referenced Oct 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
N11b:
githubChannel()githubChannel({ webhookSecret, botName, token? | app?, botLogin?, name?, apiUrl?, fetch?, triggers?, approvers?, onError? }):@<botName>in an issue, pull-request or review comment starts a turn and the agent answers in the same thread. Built ondefineChannel()like the Slack, Discord and Telegram channels (src/channels/githubChannel.ts; App authentication insrc/channels/githubAppAuth.ts, not exported from the root). Nonode:*import in either file.X-Hub-Signature-256is verified over the raw body withcrypto.subtle.verify(constant time) before the body is parsed; missing or wrong is 401.ping, edits, deletions, other events, bots,<botName>[bot],botLoginand any comment the channel posted (a hidden marker) are ignored, so there is no loop even when a personal access token posts as a normal user./approve <id>//deny <id>on the first line (note below it). Default approvers:author_associationOWNER,MEMBERorCOLLABORATOR, read from the command comment itself;approvers(logins or function) overrides it. A decision is accepted once per id; an id from another thread is ignored; a refusal is only posted for an approval this process knows, so a made-up id gets no reply.triggers(not in the ticket, asked for in the task): who may start a turn or answer a question; default everyone who can comment (the ticket's behavior), documented as untrusted input with a recommendation to restrict it on public repositories.ask_question: answered by the next comment in the thread; survives a restart given durable stores (M10a pattern,ctx.pendingQuestion).Docs for the docs site
docs/channels.md: new## GitHubsection appended after## Telegram(no###headings; the Arabicchannelspage needs it), and one new row in the existing## Built-in channelstable.docs/agent-directories.md(channel list),docs/errors.md(LOUSHO_CHANNEL_INVALIDfix line,LOUSHO_CHANNEL_REQUEST_FAILEDmeans/example),CHANGELOG.md,llms.txt/llms-full.txt.## GitHub.Acceptance criteria
githubChannel.tsandgithubAppAuth.tsexist,githubChannelexported from the package root (checked indist), nonode:*import.githubChannel.test.ts(49 tests,mountChannels()with a fake GitHub REST API): signatures, ping, issue and pull-request comments, review threads as two sessions, follow-ups, ignored events, 130,000 characters as 3 comments, approval prompt,/approveby MEMBER, refusal for NONE,approverslist and function,/denywith a note, restart on a second instance over the same stores, replay of an old/approve,ask_question(also across a restart), failed post toonErrorwithout the token.githubAppAuth.test.ts(9 tests): key pair generated in the test (PKCS#1 and PKCS#8 PEM) signs a JWT the test verifies; installation token fetched once and reused until 5 minutes before expiry.npm run docs:llms, snippet check.## GitHubsection in the Arabicchannelspage.Not verified
src/channels/githubChannel.live.test.tsis written and skips without a cassette (and is excluded from the default run, like the Telegram one). The OpenRouter account is out of credit (total_credits10,total_usage10.199...), so no cassette was recorded; a checklist line is on [LIVE] Run the deferred live-model tests once OpenRouter credit is added #260. Live test spend: none (balance checked once, no model call made).installation.idin the payload) is verified against GitHub's documentation only.Verification (on the branch after merging
origin/mainat 401900c)npx tsc --noEmit: ok.npm run lint: 0 warnings.npm run build,npm run build --workspace=packages/create-lousho-agent: ok.npm run test:types: 65 passed, no type errors.npm run docs:verify-snippets -- --skip-build: 213 snippets type-check, 8 run.npm run docs:llms:check: ok.src/tools/built-in/http.test.tsunder machine load; it passes alone and in the second full run.)npm run fallow: 0 above threshold (maintainability 89.7). Its first run flaggedreadEvent(cyclomatic 26); split into small helpers.npm run pack-smoke: all checks passed (esm and cjs 16/16 entries).Other
docs/channels.mdline 203 contains a strayr(from the Telegram change, [N11a] telegramChannel(): Telegram bot webhooks, inline-keyboard approvals #302), and the Telegram CHANGELOG entry appears in three### Addedblocks with&where/was meant. Left alone.aetherxeg-source(association NONE) asked for the approver rule's time-of-check to be explicit. It is inside the written scope (the default-approver rule), and I checked it against the code: the association is read from the command comment's webhook, so a removed collaborator is refused (test added). The docs say it is a snapshot at the command, and point to a functionapproversfor a live permission check.Closes #252
🤖 Generated with Claude Code