GitHub connector
The GitHub connector lets an AI agent do real work in your repositories — open PRs, leave review comments, post check runs — without ever holding your GitHub token, and with the riskiest actions paused for a human. The agent proposes a change; Axtary decides whether it's allowed, binds the approval to the exact payload, and only then makes the GitHub call from a credential the agent never sees.
What it's for
Picture a coding agent that fixes a failing test and opens a PR. You want it to:
move fast on ordinary edits, but stop and ask before it touches sensitive
paths like auth/, billing/, or infra/prod/; and you never want it to be
able to swap the PR's contents after you approved them. That's exactly what
this connector enforces.
The agent talks to Axtary, not to GitHub. Axtary checks each action against your policy, and for high-blast-radius actions it requires a human to approve the specific diff/comment. The approval is bound to the SHA-256 hash of that exact payload, so a confused or prompt-injected agent can't approve a harmless change and then push a different one.
What an agent can do
Each row is a distinct, payload-bound action. "Payload-bound" means the exact body, path, line, PR number, commit SHA, check name, and output are part of what gets authorized — change any of them and it's a different (re-checked) action.
| Action | What it does | Default treatment |
|---|---|---|
github.contents.read | Read one file in the repo | denied until you scope it |
github.branches.create | Create a branch | allowed within your branch rules |
github.contents.write | Write one file | pauses for approval on protected paths |
github.pull_requests.create | Open a pull request | pauses for approval on protected paths/impact |
github.pull_request_review_comments.create | Add an inline review comment | pauses for approval on protected paths |
github.check_runs.create | Post a check run on a commit | allowed after structural checks |
github.issue_comments.create | Comment on an issue or PR | allowed after structural checks |
Anything unsupported or malformed fails closed — it's refused before a GitHub request is made.
What happens when the agent opens a PR
- The agent proposes the action — say an inline review comment on
auth/session.tsline 18 — and sends it to Axtary, not GitHub. - Policy decides. Ordinary paths are allowed; a protected path like
auth/returnsstep_upand waits for a human. - A human approves the exact payload (in the dashboard or CLI). The approval is bound to that comment's hash.
- Axtary executes using a short-lived token it mints in memory — the agent never holds it — and records a decision plus an outcome in the ledger.
- If the agent later changes the comment, the hash no longer matches and the action is blocked before the GitHub call.
A normal edit looks like this through the proxy:
decision: allow
reasons: [github_write_inside_policy]
A protected-path action escalates instead of running:
$ # agent tries to edit auth/session.ts
decision: step_up
reasons: [github_write_inside_policy, step_up_protected_path]
Connect it: credentials and permissions
Prefer GitHub App mode (github.mode: app): Axtary mints a short-lived
installation token in memory from an App private key you hold locally, so there's
no long-lived token sitting in an env var. A fine-grained personal access token
(github.mode: rest) is the manual alternative.
Scope the App installation (or PAT) to the exact repository and grant:
- Metadata: read
- Contents: read and write
- Pull requests: read and write
- Checks: read and write
- Issues: read and write
Check runs are App-only. GitHub only lets a GitHub App create check runs — a fine-grained PAT cannot, no matter its permissions. So the check-run action requires
github.mode: app. The other actions work with either an App token or a PAT.
Axtary reads X-Accepted-GitHub-Permissions from GitHub's responses and records
that (non-secret) permission requirement alongside the outcome. It never records
the token itself.
Rate limits
GitHub can return primary or secondary rate limits as 403 or 429. Axtary
honors Retry-After, waits until X-RateLimit-Reset when capacity is zero, and
records the non-secret limit/remaining/reset fields from successful writes. If
retries are exhausted, the action is recorded as a failed outcome — never as a
successful one it didn't actually complete.
What an action looks like
The agent sends a normalized action like this; the payload fields are exactly
what gets hashed and authorized:
{
"tool": "github.pull_request_review_comments.create",
"resource": "repo:company/web-app",
"payload": {
"pullNumber": 42,
"body": "Please add an authorization regression test.",
"commitId": "abc123",
"path": "auth/session.ts",
"line": 18,
"side": "RIGHT"
}
}
See the write depth end to end
This one command exercises the three "depth" writes against a real repo so you can watch the whole loop:
axtary run workflow github-depth --real --repo <owner>/<repo>
It opens a draft pull request in a sandbox repository, then writes an inline
review comment on the changed file, a check run on the PR's head commit, and a
conversation comment — each decided by policy, bound to an ActionPass, and
recorded as a decision plus an outcome. It's GitHub-only and runs in
github.mode: app (because of the check-run rule above).
Status: live. Repository content, branches, and pull requests were verified against GitHub end to end earlier; inline review comments, check runs, and issue comments were verified on 2026-06-24 by a
github-depthrun that opened a PR and wrote all three against it — each governed and recorded, with an independently verified signed ledger export.
FAQ
Does the agent ever see my GitHub token? No. In App mode the token is minted in memory and used only by the local adapter; the agent only ever talks to Axtary.
Can the agent change a PR after I approve it? No. The approval is bound to the exact payload's hash. Any later change is a different action and is blocked before the GitHub call.
Why did my check run fail with a permissions error?
Check runs require a GitHub App — a PAT can't create them. Switch that workflow
to github.mode: app.
Can I make more paths require approval?
Yes. Protected-path step-up is policy-driven; add the prefixes you care about to
your axtary.yml policy and those writes will pause for a human.