Skip to content
By Wayne Sun, Hector Martinez
Picture of Wayne Sun
Wayne Sun
Picture of Hector Martinez
Hector Martinez

Custom Agent Identity ​

When an agent acts on GitHub — commits, comments, reviews, status checks — it does so as a GitHub App. Which App, and what that App is allowed to do, is decided by one field in your harness: role.

yaml
role: triage        # ← decides identity AND permissions at the mint
slug: my-org-triage # ← install-time hint only; the mint never reads it

The mint service maps role to a GitHub App (its ID + private key) and to a permission ceiling, then issues a token scoped to your repo. slug only helps fullsend github setup find or name the App at install time — it is not what authenticates your agent, and changing it does not change identity or permissions. If you set a role the mint doesn't serve, you get a 403, not a new identity.

Within that ceiling, privilege_levels selects which named level (read or write, plus any extra levels on a custom role) each run-stage receives. Omit the field and every stage gets write. Set runtime: read so the LLM sandbox gets a read-only token while pre/post scripts keep write. See privilege_levels in the harness reference.

So the real question is: whose mint issues your token?

Two paths, one decision ​

Default (hosted) mintYour own mint (standalone)
URLhttps://mint.fullsend.sh (default)your FULLSEND_MINT_URL
Roles you can usea fixed built-in set — triage, coder, review, retro, prioritize, fullsendthose built-ins plus any custom role you define
Identitythe shared fullsend App for that role (e.g. fullsend-ai-triage[bot])your GitHub App — your name, your avatar
Custom permissionsno — each role's ceiling is fixedyes — security_events:write, deployments:write, anything the GitHub API allows
Who sets it upnobody — it just worksyou (create App → install → register the role)

The default mint cannot mint a new identity for you. It serves a fixed set of Apps that fullsend operates (see why). Picking a role: it doesn't serve — or a custom slug: — will not create one; it produces the 403 above.

Built-in roles ​

Each built-in role is a GitHub App identity with a fixed permission ceiling. An agent's name is separate from its role: the code and fix agents both run as the coder role. For each role's permissions, see fullsend agent — Roles.

RoleGitHub AppPurpose
fullsend{org}-fullsend[bot]Dispatch/control
triage{org}-triage[bot]Issue triage
coder{org}-coder[bot]Code generation
review{org}-review[bot]PR review
fix(reuses coder app)Fix failures
retro{org}-retro[bot]Retrospectives
prioritize{org}-prioritize[bot]Backlog priority

Apps are named {org}-{role} and act as {org}-{role}[bot]. Each role's private key is stored as fullsend-{role}-app-pem, in GCP Secret Manager or on the filesystem (standalone mint). The fix role reuses the coder App and PEM, so no separate GitHub App or secret is created for it. Which of these roles a repository provisions is set by the roles field in config.yaml.

Note: The default deployment uses a shared vendor App (fullsend-ai-review[bot]). Code that gates on a review bot's identity must match the org-specific and shared vendor forms, plus ${FULLSEND_APP_SET}-review[bot] when a custom app set is configured — see Bot Identities for details.

Most customization needs no custom identity ​

Before reaching for your own mint, check whether you actually need a new identity. You usually don't:

  • Changing behavior — model, timeout, skills, prompt, env — keeps a built-in role:. Use base: composition; the agent still runs as that role's App.
  • A brand-new agent (its own trigger, scripts, schema) can still run on the hosted mint — set its role: to the built-in role whose permissions match what it does. A code-writing agent uses role: coder; a triage-like agent uses role: triage. The agent's own name lives in name: in its .md, not in role:. role: also sets who may trigger the agent: triage or review needs triage access, any other role needs write.
  • Acting on the result after the run — to re-run CI jobs, dispatch a workflow, deploy, and so on, chain your own workflow on the run's artifact; see Chaining Follow-up Workflows.

Rule of thumb. Pick the built-in role whose permission ceiling is the closest fit for what your agent needs to do. You only need your own mint when no built-in role fits — because you need a distinct identity, or permissions no built-in role has.

When you do need your own mint ​

Choose a standalone mint when one of these is true:

  • Custom permissions — your agent needs GitHub App permissions beyond any built-in role (for example, write access to packages, deployments, or security events).
  • Custom identity / branding — you want actions to appear under your own GitHub App name and avatar, not the shared fullsend App.
  • Compliance — your organization requires GitHub App credentials to stay inside your own infrastructure.

Set it up, then point your repo at it:

  1. Define the role and App on your mint — follow the Standalone mint guide: create the GitHub App, install it, store its PEM, and register the role's permissions (CUSTOM_ROLE_PERMISSIONS, or fullsend mint add-role).

  2. Reference the role in your harness:

    yaml
    role: my-role          # a role YOUR mint serves
    slug: my-org-my-role   # install-time App discovery; still not read by the mint
  3. Point your repo at your mint — set FULLSEND_MINT_URL to your mint's URL. Without this, tokens are requested from the hosted mint, which does not serve my-role.

Tip: adopt gradually. With FALLBACK_MINT_URL, your standalone mint serves your custom roles locally and proxies the built-in ones to the hosted mint — so you can start with a single custom role without disrupting existing agents. See Standalone mint — Fallback proxy behavior.

See also ​