Skip to content

Running the agent under a dedicated GitHub account

Synced from actions/docs/bot-account.md. The repository is the source of truth.

By default the action acts as github-actions[bot] via the workflow token. To give your agent its own identity — so it can be assigned issues, requested as a reviewer, @-mentioned, and produce PRs that trigger CI — run it under a dedicated machine account.

  • Identity & audit — every comment, commit, and PR is attributed to the bot. Reviews read as “outfitter-bot approved”, and the audit log separates agent actions from human ones.
  • Blast radius — the account is only ever granted the repos and roles the agent needs. Revoking or suspending it disables the agent everywhere at once without touching any human’s access.
  • Triggerability — PRs and pushes made with a machine-account PAT trigger workflows normally (unlike GITHUB_TOKEN), so the agent’s PRs get CI.
  • Assignability — “when a PR is assigned to X, run the agent” needs an X that is a real account.
  • Reachability — the bot has a name and a real email address, so it can plug into the channels your team already watches. Point its email alias at a Slack-connected address or shared inbox and the bot’s notifications (review requests, mentions, failed runs) land where humans see them; give the account a matching handle in Slack or your chat tool and teammates can @-mention “the bot” as naturally as a colleague. None of this changes what the agent can do — it makes the agent’s activity visible and addressable in your team’s normal communication.

GitHub’s terms allow one machine account per user for this purpose; on GitHub Enterprise Cloud, use a dedicated managed user instead.

  1. Create the account — e.g. myorg-outfitter-bot, with an email your team controls (a shared alias like outfitter-bot@myorg.com). Enable 2FA and store the credentials in your team’s secret manager; no human should use this account interactively.
  2. Invite it to the organization with the least role that works. Give it repository access via a team so membership is reviewable — Write on the repos it must push to, Triage/Read where it only comments (note: PR comments and reviews via API need at least read access plus the PAT’s Pull requests: write permission).
  3. Issue a fine-grained PAT from the bot account, scoped to only the repositories the agent works in, with the minimum permissions — see token-permissions.md. If your org requires approval for fine-grained PATs, an org admin approves it once.
  4. Store the PAT as an Actions secret (e.g. OUTFITTER_BOT_TOKEN) at the repo level, or org level restricted to selected repositories.
  5. Wire it into the workflow:
jobs:
agent:
# Only run when the bot account itself was assigned
if: github.event.assignee.login == 'myorg-outfitter-bot'
runs-on: ubuntu-latest
permissions: {} # the PAT carries the access; the workflow token gets none
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.OUTFITTER_BOT_TOKEN }} # pushes happen as the bot
fetch-depth: 0
- uses: ai-outfitter/actions@v1
with:
github-token: ${{ secrets.OUTFITTER_BOT_TOKEN }}
git-user-name: myorg-outfitter-bot
git-user-email: outfitter-bot@myorg.com
profile: task-agent
profile-source: my-org/outfitter-catalog
profile-source-ref: v1.2.0
prompt: >-
You are assigned issue #${{ github.event.issue.number }} in
${{ github.repository }}. Read it with `gh issue view`, implement
the change on a branch named agent/issue-${{ github.event.issue.number }},
push it, and open a draft PR that references the issue.
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}

Because actions/checkout is given the bot’s token and the git identity is set to the bot, commits and pushes are attributed to the machine account, and the resulting PR triggers CI like any human-opened PR.

  • Branch protection still applies. Don’t exempt the bot from required reviews on protected branches; let it open PRs that humans merge. The agent proposing changes and a human approving them is the point of the workflow.
  • CODEOWNERS — leave the bot out of CODEOWNERS so its approval never satisfies a required-review rule by itself.
  • Recursion guard — when the bot’s PRs trigger workflows that could re-invoke the agent, gate agent jobs with if: github.actor != 'myorg-outfitter-bot' (or an equivalent label check) so the agent doesn’t respond to itself.
  • Rotate the PAT on a schedule (fine-grained PATs have expiry; use it) and immediately if a workflow log ever suggests the token was echoed.
  • Review its footprint periodically — the org’s people/teams pages and the PAT list under the org’s settings show exactly what the bot can reach; prune repos it no longer works in.

Self-hosted forges: Gitea, Forgejo, and friends

Section titled “Self-hosted forges: Gitea, Forgejo, and friends”

On a self-hosted forge, machine accounts stop being scarce. There is no seat cost and no one-machine-account-per-user terms clause — an admin can create as many bot accounts as the automation warrants, each with its own avatar, display name, and scoped access tokens. That makes one account per persona practical: a review-bot whose comments read as the reviewer, an implement-bot that picks up assigned issues, a release-bot that only touches tags and changelogs. Each persona gets exactly the repository access its job needs, its own email that can route to a team channel (see “Reachability” above), and suspending one persona never touches the others.

Gitea Actions and Forgejo Actions run GitHub-Actions-compatible workflows, so the patterns in this repository’s examples carry over: create the account, issue a scoped access token from it, store the token as an Actions secret, and pass it through the same github-token input. The guardrails above apply unchanged — branch protection, recursion guards keyed on each bot’s login, and periodic footprint review.