GitHub Source connector (Nango-brokered) โ design
Date: 2026-08-03
Status: approved (design), pending implementation
Branch: feat/github-source-connector (off origin/dev)
Goalโ
Make GitHub a client-connectable Source: an org admin authorizes GitHub via
OAuth on the Sources page (/client/settings/sources), the token lives in
Nango, and the already-shipped runtime tools consume the org's connection
instead of relying on script-imported connections or the anonymous public-repo
fallback.
What already exists (not in scope)โ
The entire runtime consumption path shipped earlier and needs no changes:
github_read(kind: 'nango', handlergithub) inapi/src/agent-api/tool-registry.tsโlistIssues/listPullRequests/listCommits. The executor (runtime-tool-executor.service.ts) proxies throughNangoService.proxy({ provider: 'github', connectionId: <stored> })when an org credential exists, and falls back to anonymous public-repo reads (executePublicGitHubRead) when it doesn't.github_write(kind: 'bespoke', handlergithub_first_party) โGitHubFirstPartyToolServerServiceresolves the sameintegrationType: 'github'credential row and proxies writes through the same Nango connection. One connection feeds both tools.owner/repoare per-call tool params โ no per-connection configuration is needed, so the Sources tile is plain connect/disconnect (no drawer, unlike Slack Archive).testNangoConnectionis provider-generic (GET /connection/:id) โ no new branch.
What's missing โ the connector plumbingโ
'github' is absent from every provider registry, so it cannot be connected
through the Nango session/confirm flow and never appears on the Sources page.
This design adds it, mirroring the google_workspace addition
(docs/superpowers/plans/2026-07-28-google-workspace-read-tools.md) โ same
touchpoints, no new architecture.
Decisionsโ
| Decision | Choice | Why |
|---|---|---|
| OAuth model | GitHub OAuth App, repo scope (Nango provider github) | Matches the plain Connect-session flow every other provider uses and the existing seeds/fixtures (nango_scopes: ['repo']). A GitHub App (fine-grained, installation-based) would deviate from the shared session/confirm flow โ rejected by user 2026-08-03. |
| Scope delivery | Configured on the Nango integration (dashboard), not NANGO_USER_SCOPES | The user/bot scope split is Slack-specific; GitHub scopes ride the provider-level scope= param. |
| Tile gating | SOURCE_TOOLS_BY_PROVIDER.github: ['github_read', 'github_write'] โ any-enabled shows the tile | Both tools consume this one connection; same any-enabled rule as google_workspace's three tools. |
| Display name | GitHub | โ |
| DB migration | None | integration_type is varchar; precedent: slack_archive, google_workspace. |
Changesโ
Backend (api/src/integrations/credentials/)โ
credentials.dto.ts'github'added to theChannelTypeunion (after'google_workspace').'github'added toNANGO_CONNECT_PROVIDERS(single source of truth for both DTO@IsInallow-lists and the Sources/connect-token surfaces).
credentials.service.tsCHANNEL_REQUIRED_KEYS.github: [](creds live in Nango; onlynango_connection_idis stored locally).'github'added toNANGO_BACKED_TYPES(gives create/confirm, delete with Nango-side revoke, and the generic connection test for free).validateNangoProvider: widen the error string and theExtract<...>return type.- No
NANGO_USER_SCOPESentry (see Decisions).
sources.service.tsSOURCE_TOOLS_BY_PROVIDER.github: ['github_read', 'github_write'].SOURCE_DISPLAY_NAME.github: 'GitHub'.
Everything downstream keys off these sets and picks GitHub up automatically:
the Connect session/confirm endpoints (NangoCredentialsController), delete
with provider-side revoke, testIntegration, the Sources read model, the
connect_integration agent tool (integrationTypes: [...NANGO_CONNECT_PROVIDERS]),
the public connect-token flow, and ToolPermissionsGuard's provider gating.
Frontend (frontend/src/)โ
lib/api.tsโ'google_workspace'and'github'are present in theSourceInfo.providerunion andNANGO_SOURCE_PROVIDERSclassifier (comment there says: mirrorsNANGO_CONNECT_PROVIDERS, update together). This closes the pre-existing Google Workspace mirror drift while adding GitHub, so one-argument source-provider calls use the authenticated/v1source routes.app/client/settings/sources/page.tsxโ GitHub entry in the provider icon/meta map usingsiGithubfromsimple-icons(the idiom the other tiles use). No other page changes: tiles render from the API response.
Testsโ
credentials.nango-provider-lockstep.specandsources.service.spec(map-completeness guard) are loop-driven over the provider sets โ they extend togithubautomatically and fail if any set is missed.tool-permissions.guard.specpins the Connect-session/confirm permission gate for GitHub's two-tool any-enabled mapping, rejecting when neithergithub_readnorgithub_writeis enabled and allowing when either one is.credentials.delete.specpins the GitHub disconnect lifecycle: the service revokes the stored Nango-generated connection id as providergithubbefore removing the local row, and fail-closes without local removal if revoke fails.- Add a
githubcase to the Nango session-mint spec asserting the session carries nointegrations_config_defaults/user_scopes(the inverse of theslack_search/slack_archiveassertions), pinning the scopes-live-on-the-integration decision. - Frontend:
api.test.tspins the Nango helper overload routing for source-provider calls (google_workspace/github) and the existing org-scoped GitHub card call shape;page.github.test.tsxrenders the Sources-page GitHub tile and pins the org-scoped Connect flow.
Error handlingโ
No new error paths. Connect failures surface through the existing
session/confirm flow (generic {success:false} on the public path, HTTP errors
on the authenticated path); a missing connection keeps github_read on the
public fallback and github_write on its existing 404
("GitHub is not configured for this organization").
Out-of-repo handoff (user)โ
- Create a GitHub OAuth App (org-owned), callback URL = Nango's callback.
- In the Nango dashboard: create integration with provider
github, unique keygithub, the OAuth App client id/secret, scoperepo. - SuperAdmin enables
github_read(and optionallygithub_write) tool permissions for the pilot org โ deny-by-default hides the tile until then.
Verificationโ
- Targeted jest: the two lockstep/completeness specs + the new session-mint case + existing credentials/sources specs touched by the sets.
frontend: build + rendered Sources page against the Railway-hosted Nango (rendered-UI rule) once the dashboard integration exists.- Smoke: connect a real org โ credential row stores the Nango-generated
connection id โ
github_readon a private repo succeeds โ disconnect revokes at Nango and removes the row.