> ## Documentation Index
> Fetch the complete documentation index at: https://graph.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# A custom bot identity

> Give a commenting plan its own name and avatar via a GitHub App

By default, the comments a plan posts in CI — like the [`graph_review_9000` reviewer](/cookbook/ci-checks)'s summary and inline findings — appear as **github-actions\[bot]**. That identity comes from the workflow's `github.token`, not from graph. The [github pack](/tools/builtins) tools shell out to `gh`, which acts as whatever `GH_TOKEN` is set in the environment — and exec tools pass the process env through untouched. So giving the reviewer its own name and avatar is just a token swap: mint a GitHub App installation token and hand it to the review step.

## Create the app

GitHub Settings → Developer settings → GitHub Apps → New GitHub App. The app's name becomes the comment author (as `<name>[bot]`) and its avatar shows on every comment. Disable webhooks. One permission: **Pull requests: Read and write**. Install it on the repository, then collect two values: the **App ID** (on the app's About page) and a **private key** (generate one; it downloads a `.pem`). Store them as repository secrets — say `REVIEW_APP_ID` and `REVIEW_APP_KEY`.

## Mint the token in the job

The official [`actions/create-github-app-token`](https://github.com/actions/create-github-app-token) action exchanges the app credentials for a short-lived installation token scoped to the repo:

```yaml theme={null}
  pr-review:
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/create-github-app-token@v2
        id: bot
        with:
          app-id: ${{ secrets.REVIEW_APP_ID }}
          private-key: ${{ secrets.REVIEW_APP_KEY }}

      - name: Review and comment
        run: graph plan run graph_review_9000 --input pr="$PR"
        env:
          GH_TOKEN: ${{ steps.bot.outputs.token }}
```

The step-level `env` overrides the workflow-level `GH_TOKEN` for the plan run only — checkout and everything else keep the default token, and jobs that never post (like the [docs-drift gate](/cookbook/ci-checks#docs_drift--an-inferred-gate-as-a-merge-check)) need no changes.

## What to expect on the switch

Comment identity is per-token, so the upsert mechanics keep working but don't cross identities: `gh_pr_comment --edit-last` edits the *app's* most recent comment, and on PRs the old identity already reviewed, its stale summary comment sits until deleted by hand. The thread-lifecycle tools key on the hidden marker rather than the author, so `gh_pr_review_threads` reads the old identity's findings back too — but its resolved-vs-declined heuristic compares the resolver's login to the *poster's*, so threads the old identity posted and the new one resolves read back as `declined` (a different login closed them), which conveniently also stops them from being re-raised. One caveat on the state heuristic generally: it can't tell two automation identities apart from a human, so keep one posting identity per marker. All of these are one-time transition effects on already-open PRs.


## Related topics

- [CI checks](/cookbook/ci-checks.md)
- [Changelog](/changelog.md)
- [Built-ins](/tools/builtins.md)
- [Introduction](/getting-started/introduction.md)
- [Plan workbench](/workbench/plan-workbench.md)
