Skip to content

Bot Identities ​

Fullsend agents authenticate as GitHub Apps; the table below also includes non-agent bots that appear in trusted-actor lists. Multiple agent roles may share a single app identity. The GitHub App login is determined by the role field in each harness file (in the fullsend-ai/agents repo); slug is an install-time hint the mint never reads.

AgentGitHub App loginNotes
codefullsend-ai-coder[bot]role: coder. Opens PRs from issues
fixfullsend-ai-coder[bot]role: coder. Shares the coder app; pushes to existing PR branches
reviewfullsend-ai-review[bot]Posts review comments
triagefullsend-ai-triage[bot]Posts triage summaries on issues
retrofullsend-ai-retro[bot]Files retro issues, posts PR comments
prioritizefullsend-ai-prioritize[bot]Prioritizes issues
renovaterenovate-fullsend[bot]Dependency updates (not a fullsend agent)
syncfullsend-ai-sync[bot]Converges scaffold files and per-repo variables across .fullsend's repos.yaml targets; commits directly to main

When referencing bot identities in code (e.g., trusted actor lists, dispatch filters), always verify the login name against this table. Do not assume each agent role has a unique app identity — the fix agent reuses fullsend-ai-coder[bot], not a separate fullsend-ai-fix[bot].

Scaffold-sync write path ​

The fullsend-ai-sync[bot] App has a broader write path than the agent Apps listed above. Three properties are load-bearing and must be considered when building trusted-actor lists, dispatch filters, or security assessments:

Ruleset bypass ​

The sync App holds bypass_mode: always on the fullsend-ai/fullsend main ruleset. Its commits are direct pushes to main — no PR, no review, no status checks. This is intentional: scaffold convergence is a cross-repo reconciliation that runs unattended after every push to main.

Workflow-write scope ​

The sync App has workflow-write permission. Combined with the ruleset bypass, .github/workflows/ on main is writable by the sync path with no human in the loop. This is distinct from the coder token path: the coder token has no workflows permission (internal/mintcore/github.go), so code agents cannot push workflow files (see #6512). The sync App can. Both facts are correct — read in isolation, the #6512 statement about the coder token is easy to take as covering every bot, but it applies only to the coder token, not the sync path.

App-token push recursion ​

GitHub's "events triggered by GITHUB_TOKEN will not create a new workflow run" suppression is scoped to GITHUB_TOKEN and does not apply to GitHub App installation tokens. A sync commit to main therefore re-triggers notify-scaffold-sync, which dispatches again. Observed 2026-08-24: merge cfdbf2ff at 14:29 → dispatch → sync commit 14:51 → dispatch → sync commit 14:52 → dispatch → stop. Each scaffold-touching merge costs ≥2 dispatch rounds. This is by design — the second round converges any files that depend on the first sync — but it interacts with the convergence non-idempotence tracked in #6553. See also CI Workflows § Scaffold-sync dispatch recursion.

General identity notes ​

Shared vendor identity ​

The default deployment model uses a shared, vendor-owned App (per ADR 0029/0059/0068). For adopting orgs other than fullsend-ai, the review bot's login is fullsend-ai-review[bot], not ${ORG_NAME}-review[bot]. Any code that gates on the review bot's identity must match both the org-specific form (${ORG_NAME}-review[bot]) and the shared vendor form (fullsend-ai-review[bot]). See #5550 for the bug this caused.

REST vs. GraphQL login format ​

The [bot] suffix above is the REST/App-slug form. GitHub's GraphQL API omits it — a bot author's login field comes back as fullsend-ai-coder, not fullsend-ai-coder[bot], with __typename: "Bot". Comparing a GraphQL-sourced login against a literal "...[bot]" string never matches (see #5575) — match on __typename == "Bot" plus the un-suffixed login instead.

gh pr view --json format ​

The gh pr view --json author CLI command uses a different schema than raw GraphQL — it exposes .author.is_bot (boolean) and .author.login (with an app/ prefix, e.g. app/fullsend-ai-coder), but does not expose __typename. When using gh pr view --json, check .author.is_bot == true plus .author.login against the app/-prefixed name (see #5536).

Configured app-set identities ​

When FULLSEND_APP_SET is configured, dispatch and prior-review lookup also accept ${FULLSEND_APP_SET}-review[bot]. Automatic fix eligibility accepts the matching coder identity, ${FULLSEND_APP_SET}-coder[bot], without requiring the fullsend-fix label. In gh pr view --json output, that coder login is app/${FULLSEND_APP_SET}-coder; always require .author.is_bot == true and use the app/-prefixed form when comparing CLI output. Human authors and unrelated bots remain subject to the normal fullsend-fix label and permission checks.

GitLab responsibility identities ​

GitLab does not use GitHub Apps. Runtime authentication uses registered role credentials, not a single shared project access token. The registered- role contract — built-in Poller, Analyst, and Coder plus optional administrator-registered custom roles — is defined in gitlab-role-credentials.md. repos install provisions those credentials on fresh and existing shared-token installs. It does not retire a leftover FULLSEND_FORGE_TOKEN — there is no automated path for that; an administrator must revoke it manually. GitLab CI poll/agent jobs and fullsend poll / fullsend run always select the registered role credential and fail closed if that secret is missing (see gitlab-role-credentials.md). The shared fullsend-bot identity never authenticates at runtime — runtime credential selection unconditionally requires the registered role credential and fails closed otherwise. A leftover FULLSEND_FORGE_TOKEN is untouched by both repos install and repos uninstall; cleaning it up (and revoking its matching fullsend-bot project access token) is a manual administrator step. Role registration is install-state only; repository and merge-request content cannot create or elevate a GitLab role. Role credentials are provisioned, but the legacy shared credential is left in place — retiring it is always a manual administrator step.