GitHub
The GitHub connector pins your gateway to https://api.github.com and exposes a small, deliberate slice of the REST API: repository metadata, issues, pull requests, commits, and repository search. It suits an agent that triages issues, summarises what changed this week, or drafts a pull request description — without handing it a token it could use anywhere else on GitHub.
What you need
A fine-grained personal access token. Create one at Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token.
- Resource owner — yourself, or the organisation that owns the repositories.
- Repository access — Only select repositories, and pick just the ones the agent should reach. This is your real blast radius; the gateway can stop the agent calling anything else, but it cannot narrow a token that was issued for every repository.
- Repository permissions — select the least that covers what you plan to enable:
| Permission | Level | Needed for |
|---|---|---|
| Metadata | Read-only | mandatory; also backs repos.read and repository search |
| Contents | Read-only | commits.list |
| Issues | Read and write | issues.list, issues.create |
| Pull requests | Read and write | pull_requests.list, pull_requests.create, pull_requests.merge |
| Administration | Read and write | repos.delete only — leave this at No access unless you genuinely want an agent able to delete a repository |
If you only ever want reads, set Issues and Pull requests to Read-only and skip Administration entirely. Give the token a short expiry; you can rotate the connection's credential later without rebuilding it.
Copy the token when GitHub shows it. You cannot read it back afterwards, and neither can Permaura once it is sealed.
Add the connection
Open Access → Connections → Add connection, choose GitHub from the catalog, and paste the token into the credential field. It is sealed on your gateway at that moment and never displayed again — from then on the gateway injects it server-side on each approved call.
Nothing is usable yet. A connection makes actions possible, not permitted: an agent still needs a grant before it can call anything here.
What the agent can do
| Action | What it does | On by default |
|---|---|---|
repos.read | Read repository metadata | Yes |
issues.list | List issues, filtered by state and labels | Yes |
pull_requests.list | List pull requests, filtered by state | Yes |
commits.list | List commits on a repository | Yes |
search.repos | Search repositories by query | Yes |
issues.create | Open an issue | No |
pull_requests.create | Open a pull request | No |
pull_requests.merge | Merge a pull request | No — approval required |
repos.delete | Delete a repository | No — approval required |
The four writes land switched off when you connect. Switch on only the ones you want, one at a time. pull_requests.merge and repos.delete are classified critical and carry a standing approval requirement on top: even once enabled, each call stops and waits for a human on a paired device before GitHub sees it. issues.create and pull_requests.create have no such stop, so enabling one of those is itself the decision point.
Good to know
- Rate limits. A personal access token gets 5,000 requests per hour. Search endpoints are tighter, and GitHub applies undisclosed secondary limits on bursts and concurrency — an agent looping over
commits.listcan trip those long before the hourly budget runs out. Both surface as 403 or 429. - The API version is pinned. The connector always sends
X-GitHub-Api-Version: 2022-11-28alongsideAccept: application/vnd.github+json, so responses keep the same shape whatever GitHub makes default. That is still GitHub's default version and is supported until 10 March 2028. GitHub also publishes a newer2026-03-10; the connector stays on the older pin deliberately, because the response shapes documented here are the ones it was authored against. - OAuth works too, but only against a GitHub App. Gateway 1.1.0 and later runs the whole authorisation code flow itself, sealing the tokens on your gateway and refreshing them there; you start it through the gateway's REST API (
POST /v1/connections/:id/oauth/start), because the console has no "Sign in with GitHub" button yet. Which kind of app you register decides whether it completes: a classic OAuth app issues a user token that never expires and returns no refresh token with it, and the gateway refuses to seal a credential it cannot refresh — so the authorisation link works, you approve in the browser, and the callback stops with that error. A GitHub App with expiring user access tokens left enabled does return a refresh token, alongside an eight-hour user token, and it draws its access from the permissions configured on the app rather than the scopes the connector requests. The fine-grained token stays the recommendation here: it pins to named repositories with nothing to register. - Responses are not redacted. This connector declares no redaction fields, so issue and pull request bodies come back to the agent verbatim. If your private repositories carry secrets in issue text, that is worth knowing before you grant
issues.list. - Repository search sees what the token sees.
search.reposreturns public repositories plus any private ones the token was granted, so results differ between a personal token and an organisation-owned one.