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.

ActionWhat it doesDefault treatment
github.contents.readRead one file in the repodenied until you scope it
github.branches.createCreate a branchallowed within your branch rules
github.contents.writeWrite one filepauses for approval on protected paths
github.pull_requests.createOpen a pull requestpauses for approval on protected paths/impact
github.pull_request_review_comments.createAdd an inline review commentpauses for approval on protected paths
github.check_runs.createPost a check run on a commitallowed after structural checks
github.issue_comments.createComment on an issue or PRallowed 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

  1. The agent proposes the action — say an inline review comment on auth/session.ts line 18 — and sends it to Axtary, not GitHub.
  2. Policy decides. Ordinary paths are allowed; a protected path like auth/ returns step_up and waits for a human.
  3. A human approves the exact payload (in the dashboard or CLI). The approval is bound to that comment's hash.
  4. 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.
  5. 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-depth run 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.