Appearance
date: 2026-06-05 tags: [github, auth, agent, git, pat] status: active graduated_to:
Acting as a separate agent GitHub account is TWO independent layers
To make an agent's GitHub work attributable to a distinct account (not the human), both layers must flip — set one only and PRs look like the bot while commits still look like you:
- API identity (PRs, comments, issues, Projects) — the
ghtoken. SetGH_TOKENin the env → it overrides the keyring login for that process, leaving the user's personalghuntouched. - Commit identity (author/committer) —
git config. SetGIT_AUTHOR_NAME/EMAIL+GIT_COMMITTER_NAME/EMAILin the env → overridesgit configwithout touching it. Use the account's<id>+<login>@users.noreply.github.comemail.
Both ride Claude Code's settings.json env block: the non-secret git identity can be committed (.claude/settings.json, so it travels to the cloud container too); the secret GH_TOKEN goes in user-scope ~/.claude/settings.json or a container secret — never committed. (settings.local.json is tracked in this repo, so it is not safe for secrets.)
Fine-grained PAT requirements that bit:
- resource owner = the org (not the agent's personal account — otherwise it sees zero org repos:
user/reposlength 0); - org approval of the PAT (pending → 403 on org resources);
- Contents: Read+Write for
git push/fetch— the repo API'sadmin:truereflects the user's role, not the token's grants, so git over HTTPS 403s ("Write access not granted") without it; - an org-scoped PAT cannot see the user's personal repos (404).
Verify after wiring: gh api user --jq .login (the bot) · git var GIT_AUTHOR_IDENT (the bot + noreply) · gh api user/repos --jq length (> 0).
Guard — this entry; the identity env lives in settings.json. See [[2026-06-05-github-native-typed-backlog-api]] for what these scopes unlock.
Inverse trap — when the env identity ≠ the identity you need (2026-06-11)
A web session sets GIT_COMMITTER_EMAIL/GIT_AUTHOR_EMAIL to a session bot (agent-89165@…), which overrides git config — so git config user.email noreply@anthropic.com does not win, and commits land Unverified. To commit as a different identity than the env dictates, unset the env per command:
env -u GIT_COMMITTER_EMAIL -u GIT_COMMITTER_NAME -u GIT_AUTHOR_EMAIL -u GIT_AUTHOR_NAME git commit …- The same wrapper is needed on a fixup:
git rebase --exec "git commit --amend --no-edit --reset-author"re-applies the env identity unless the rebase itself runs underenv -u …(--reset-authorresets to the env, not togit config). Missing this cost a redo.