Diffinery
Accounts: Permissions
Docs / Accounts

Permissions

The repository roles (read, triage, write, maintain, admin), where roles come from, and how token scopes and agent policies cap them.

Every request to a repository, whether it comes from the web UI, Git, the REST API or MCP, runs with one effective role on that repository. This page explains the five roles, where a person's role comes from, and how token scopes, repository-restricted tokens and agent policies lower it.

Repository roles

Diffinery uses the same five roles as GitHub. Each role includes everything the roles before it can do.

RoleIn short
readView and clone; open issues and comment
triageManage issues, pull requests and labels without pushing code
writePush, open and merge pull requests, run workflows
maintainAlso move or delete tags and edit other people's comments
adminSettings, access, branch protection, secrets and webhooks

What each role can do

Actionreadtriagewritemaintainadmin
View code, history, issues, pull requests, workflow runs, logs and artifactsYesYesYesYesYes
Clone and fetch over Git, download Git LFS objectsYesYesYesYesYes
List collaboratorsYesYesYesYesYes
Open issues, comment, and edit or close your own issuesYesYesYesYesYes
Leave comment-only reviews and line comments on pull requestsYesYesYesYesYes
Add and remove your own reactionsYesYesYesYesYes
See published releases, download release assets and source archives (zip and tar)YesYesYesYesYes
See commit statuses, check runs, deployments and environmentsYesYesYesYesYes
Watch the repository and subscribe to threadsYesYesYesYesYes
Create, apply and delete labels; set assignees (labels and assignees sent by someone below triage, when opening or editing an issue or pull request, are dropped)NoYesYesYesYes
Edit, close or reopen anyone's issue or pull requestNoYesYesYesYes
Request reviewers on anyone's pull requestNoYesYesYesYes
Lock and unlock conversations; comment and react on locked onesNoYesYesYesYes
Push branches and new tags; upload Git LFS objectsNoNoYesYesYes
Create, update and delete branches and refs through the API; commit files in the web editor or APINoNoYesYesYes
Open pull requestsNoNoYesYesYes
Approve or request changes on a pull request (not your own)NoNoYesYesYes
Merge pull requests, add them to or remove them from a merge queue, turn auto-merge on or offNoNoYesYesYes
Resolve review threadsNoNoYesYesYes
Run, cancel and re-run workflowsNoNoYesYesYes
Report check runs and commit statuses (POST /repos/{owner}/{repo}/check-runs, POST /repos/{owner}/{repo}/statuses/{sha})NoNoYesYesYes
Create, edit and delete releases and their assets; see draft releasesNoNoYesYesYes
Create and delete deployments; report deployment statusesNoNoYesYesYes
Update a pull request's branch from its base (PUT .../pulls/{number}/update-branch)NoNoYesYesYes
Write Git objects through the API (blobs, trees, commits, tags, merges)NoNoYesYesYes
Trigger repository_dispatch (POST /repos/{owner}/{repo}/dispatches)NoNoYesYesYes
List Actions variables and environment variablesNoNoYesYesYes
Start agent sandboxesNoNoYesYesYes
Move or delete existing tagsNoNoNoYesYes
Edit or delete other people's commentsNoNoNoYesYes
Dismiss a review on someone else's pull request (people only)NoNoNoYesYes
Change settings: name, description, visibility, default branchNoNoNoNoYes
Archive, unarchive and delete the repositoryNoNoNoNoYes
Transfer the repository to your own account or an organization you own or administer (people only; a personal repository only by its owner)NoNoNoNoYes
Add, change and remove collaborators; invite by emailNoNoNoNoYes
Manage branch protection rulesNoNoNoNoYes
List, set and delete Actions secrets; set and delete variablesNoNoNoNoYes
Create, change and delete environments, their deployment branch policies and secrets (people only)NoNoNoNoYes
Set and delete environment variablesNoNoNoNoYes
Set repository topicsNoNoNoNoYes
Change the repository's workflow permissions setting: the default GITHUB_TOKEN permissions and whether workflows may create and approve pull requests (people only)NoNoNoNoYes
Delete other people's reactionsNoNoNoNoYes
Manage webhooksNoNoNoNoYes
Run self-hosted runners for the repository (diffinery runner)NoNoNoNoYes
Bypass branch protection: push past it, merge past unmet rules by asking to ("bypass_rules": true), or merge without the merge queue by asking to ("bypass_merge_queue": true), unless the rule turns on Do not allow administrators to bypass these rules (people only for merges)NoNoNoNoYes
Commit past push protection with git push -o allow-secrets=<reason>, or with allow_secrets on POST /repos/{owner}/{repo}/diffinery/commits (people only)NoNoNoNoYes

Some actions have extra conditions on top of the role:

  • Branch protection can block pushes and merges for every role below admin, and for admins too when the rule enforces administrators. An admin's merge only skips unmet rules when they ask for it explicitly (Merge without waiting for requirements (bypass) in the web UI, "bypass_rules": true in the API, diffinery pr merge --admin). Each flag covers only what it names: bypass_rules skips unmet rules (including a merge commit on a branch that requires linear history), and bypass_merge_queue skips only the merge queue. Every bypass, including a bypassed linear-history rule or merge queue, is written to the audit log as pull_request.merge_bypassed. See Branch protection.
  • The read role's actions that change something (opening issues, commenting, reacting, comment-only reviews, watching) need a signed-in account. Anonymous visitors to a public repository can only read, and a read-scoped token can only read; see Anonymous access and Token scopes cap your role.
  • An archived repository refuses every write with 403 repository is archived (read-only), for every role and from the web UI, Git, the REST API and MCP alike: pushes, issues, comments, reviews, settings, collaborators, branch protection, secrets, variables and webhooks. Only unarchiving, deleting the repository, watching it, and linking a container image to it still work. See Archive a repository.
  • You can't approve or request changes on your own pull request, and you can't dismiss reviews on it.
  • Pull requests opened by agents always need at least one approval from a person.

Container images have their own permissions. An image linked to a repository follows that repository's roles: read pulls, write pushes, admin deletes. In an organization, every member can create images and pull the organization's images that aren't linked to a repository, but an image that isn't linked to a repository can be pushed to and managed only by the member who created it and the organization's owners and admins. See Container registry.

Where your role comes from

Diffinery works out your role on each request, so a change takes effect immediately for the browser, Git and every token you hold. Your role on a repository is the highest of:

SourceRole
You own the repository (a personal repository)admin
You are an owner or admin of the organization that owns itadmin
You are a member of the organization that owns itthe organization's base permission: none, read, write or admin (read for new organizations)
You created it in an organization as a memberadmin (you are added as an admin collaborator)
You were added as a collaborator on the repository (Settings → Collaborators, an accepted repository invite, or PUT /repos/{owner}/{repo}/collaborators/{username})the role you were given
The repository is publicread
You are a site administratoradmin on every repository

Because the highest role wins, a collaborator entry can raise an organization member's access above the base permission but can't lower it. Accounts that are pending or disabled have no role anywhere.

Collaborators

Repository admins manage collaborators under Settings → Collaborators (/acme/website/settings/access):

  • Add people: enter a Username or email (a person, an agent or an email address), pick a Role (Read, Triage, Write, Maintain or Admin; default Write) and click Add. A person's username gets an invitation, and they get the role once they accept it under Settings → Invitations ("Invited diffy with write access. They get access once they accept."). Agents, people who already are direct collaborators, members of the organization that owns the repository and you yourself get the role immediately ("diffy now has write access. We let them know."). An email address gets an invitation link; see Invitations.
  • Change a collaborator's role with the Role menu and Save, or click Remove and confirm.

The person gets an email when their access is granted, changed or removed, and an in-app notification when someone adds or invites them with Add people. With the API:

# Invite diffy with the triage role, or change their role if they already are a collaborator
# (GitHub's "pull" and "push" also work: they mean read and write)
curl -X PUT https://diffinery.com/api/v3/repos/acme/website/collaborators/diffy \
  -H "Authorization: Bearer dfy_..." \
  -H "Content-Type: application/json" \
  -d '{"permission": "triage"}'

# Remove diffy
curl -X DELETE https://diffinery.com/api/v3/repos/acme/website/collaborators/diffy \
  -H "Authorization: Bearer dfy_..."

Without a body, PUT gives write. PUT answers 201 Created with the invitation when it invited the person, and 204 No Content when the role applied at once (the same cases as Add people). Both need admin on the repository and a token with the admin scope. Any other permission than pull, read, triage, push, write, maintain or admin answers 422 permission must be pull, triage, push, maintain or admin, and an organization's login answers 422 too: add its members instead, or transfer the repository to it.

Organization roles

Organizations have their own three roles, which map onto repository roles for every repository the organization owns. Members get the organization's base permission, which owners choose:

Organization roleRole on organization repositoriesCan also
memberThe base permission: none, read, write or adminCreate repositories (and get admin on the ones they create) and container images in the organization
adminadminManage members (except owners), invites, agents and organization secrets
owneradminEverything an admin can, plus manage owners and the organization's Settings tab (name, display name, base permission, picture)

New organizations start with a base permission of read; organizations that existed before the setting was added use write. Owners change it on the organization's Settings tab (Base permission) or with PATCH /api/v3/orgs/{org} and {"default_repository_permission": "write"}. With none, members don't see the organization's private repositories unless they are collaborators on them or created them. See Base permission for details.

Site administrators

Site administrators run the instance. They have admin on every repository, can act as an owner of every organization, and see a Site administration group in Settings with People and invitations, Email and Audit log. Accounts become site administrators when their email address or username is listed in the instance's BOOTSTRAP_ADMINS setting when the account is created. See Site administration.

A site administrator's tokens are still capped by their scopes, like everyone's.

Anonymous access

Without signing in or sending a token, you have read on public repositories, but only to look: you can browse them, clone and fetch over Git, download LFS objects and call the API's read endpoints (GET and HEAD) for those repositories. Anonymous callers can't change anything, as on GitHub: opening an issue, commenting, reacting, watching or any other request that isn't a read gets 401 authentication required, even on a public repository. Everything else, including MCP, needs an account.

SituationResponse
No credentials, private repository, or one that doesn't existGit, Git LFS and the web UI: 401 authentication required (Git then asks for a username and password). REST API: 404, as on GitHub. A signed-out caller can't tell the two apart.
No credentials, any change to a public repository (for example POST /repos/{owner}/{repo}/issues)401 authentication required
Signed in or token, but no access to a private repository404 repository not found (Diffinery doesn't reveal that it exists)
Access, but the role is too low403 <role> access required, for example 403 write access required

Token scopes cap your role

A personal access token never does more than its scope allows, whatever your role is. The cap is:

Token scopeHighest effective role
readread
writemaintain
adminadmin

Your effective role through a token is the lower of your own role and the cap. If a token has several scopes, the highest one sets the cap. For example, an organization owner using a write token can push and merge in the organization's repositories but can't change their settings, secrets or branch protection; for that they need an admin token or the web UI.

A read token goes further than the cap: it can't make any change at all. Any repository request other than GET or HEAD gets 403 this token needs the write scope, including the changes the read role allows (opening issues, commenting, reacting, comment-only reviews). git fetch and Git LFS downloads keep working, because they only read even though they use POST.

Browser sessions (signing in with a passkey) aren't capped: in the web UI you always act with your full role.

Account-level actions check the scope directly, and most also refuse tokens restricted to repositories (403 this token is limited to repositories and can't change account settings):

ActionNeeds
Create a repository (POST /api/v3/user/repos, POST /api/v3/orgs/{org}/repos)a write or admin token that isn't restricted to repositories, or a browser session
Mark notifications read, change notification settings, send a test emaila write or admin token that isn't restricted to repositories, or a browser session
Watch or unwatch a repositorya write or admin token, or a browser session
Upload or remove your profile picture or an organization's (PUT/DELETE /api/v3/user/avatar, /api/v3/orgs/{org}/avatar; organization owners only)a write or admin token that isn't restricted to repositories, or a browser session
Create a token (POST /api/v3/diffinery/tokens, diffinery token create)an admin token or a browser session
Revoke a token, create an organization, invite people, manage organization secrets, create agents and agent tokens, disable agentsan admin token that isn't restricted to repositories, or a browser session
Send every email template (site administrators)an admin token that isn't restricted to repositories, or a browser session
Change an organization's display name or base permission (PATCH /api/v3/orgs/{org}, owners only)an admin token that isn't restricted to repositories, or a browser session
Change your username, display name or appearancea browser session; there is no API
Add or remove passkeys, sign out other browsersa browser session; tokens can't do this

A token whose scope is too low gets 403 this token needs the write scope or 403 this token needs the admin scope.

See Personal access tokens for how to create tokens.

Repository-restricted tokens

A token can be restricted to a list of repositories when you create it. With such a token, every other repository behaves as if you had no access: you get 404 repository not found, even for repositories you could otherwise read. Inside the listed repositories, the usual role and scope cap apply. Restricting a token doesn't limit account-level reads such as GET /api/v3/user, but a restricted token can't make account-level changes: creating repositories or organizations, inviting, managing agents, organization secrets, notification settings or profile pictures, or revoking tokens. Those answer 403 this token is limited to repositories and can't change account settings (profile pictures have their own message).

Agents

Agents are accounts that act for a person or an organization. Their role on a repository is the lowest of:

  1. The owner's role. A personal agent can never do more than the person who owns it. An organization agent has a role only on that organization's repositories (as an organization admin would) and none anywhere else.
  2. The agent's cap. By default an agent's maximum role is write. The owner can choose another Maximum role when creating the agent. If the agent was added as a collaborator on a repository, that collaborator role replaces the maximum role for that repository.
  3. The token's scope, as for any token.

On top of the role, these guardrails apply to agents everywhere (Git, the REST API, MCP and the web UI):

  • Agents can't push to the default branch or any protected branch, unless a protection rule turns on Allow agents to push directly (agentsMayPush). They get "agents may not push to protected or default branches; open a pull request".
  • Agents can't merge into the default branch or a protected branch, unless the rule turns on Allow agents to merge pull requests (agentsMayMerge).
  • A pull request opened by an agent needs at least one approving review from a person. Only people's approvals count toward required approvals: approvals from agents and from workflow tokens never do.
  • Agents can never bypass push protection, and the merge-protection bypass for admins ("bypass_rules": true) applies only to people.
  • Check runs and commit statuses reported by agents never satisfy a required status check.
  • Agents can't dismiss reviews.
  • Through the API, agents can't change branch protection, delete repositories, or manage environments. Whatever their role, they can't create, update or delete Actions secrets (repository, environment or organization), and can't create, change or delete Actions variables (repository or environment); they get 403 agents cannot manage secrets or 403 agents cannot manage variables. An agent with write or higher can still list variables.
  • A workflow run started by an agent only gets an environment's secrets when the environment is limited to protected branches. Tags created or moved by an agent never match an environment's tag patterns. See Environments.
  • Commits an agent makes carry a diffinery-agent header naming the agent and the person it acts for.

See Agents for creating and managing agents.

Job tokens and sandbox tokens

Workflows and sandboxes get short-lived tokens of their own:

TokenPrefixWhere it comes fromWhat it can do on the repository
Job tokendjt_Each workflow job gets one as GITHUB_TOKEN (also DIFFINERY_TOKEN)Act as diffinery-actions[bot] with what the workflow's permissions: grant (see below). Container images follow the job's permissions: packages: it pulls its own repository's images, its owner's images not linked to a repository and public images, and pushes only to images linked to its own repository (creating them, linked, on first push)
Sandbox tokendst_Each agent sandbox gets oneAct as the person or agent that started the sandbox, capped at write, on that repository
Runner tokendrn_A self-hosted runner gets one when it registers with a repository admin's registration tokenClaim that repository's queued jobs, with the labels it registered. Nothing else: no reads, pushes or other API calls. It lasts until the runner is removed, or until its one job for an --ephemeral runner. See Manage runners

Job and sandbox tokens can also read other public repositories (as anyone can), but no other private repository. They stop working when the job completes or the sandbox closes. See Secrets and variables and Sandboxes.

What a job token may do

A job token follows GitHub's permissions: model. Its permissions come from the job's permissions:, else the workflow's, else the repository's default:

Repository defaultPermissions without permissions:
Read (the default for new repositories)contents and packages read, nothing else
Read and write (repositories created before the setting existed)Write on every permission except id-token, which stays off

An admin changes the default, and whether workflows may create and approve pull requests (off by default), on the repository's Settings → Actions tab or with PUT /api/v3/repos/{owner}/{repo}/actions/permissions/workflow. See Workflow permissions for the details.

On top of its permissions:

  • Each endpoint needs its permission (issues, pull-requests, contents, statuses, checks, deployments, actions and so on). A request without it gets 403 Resource not accessible by integration (the workflow's GITHUB_TOKEN needs permissions: <scope>: <read or write>). Reads of a public repository are always allowed.
  • The token's role is at most write, so branch protection always applies to it. Repository settings, collaborators, secrets, variables, webhooks, runners and branch protection are out of its reach (403 this endpoint is not available to a workflow's GITHUB_TOKEN).
  • It never creates, changes or deletes files under .github/workflows/ or .diffinery/workflows/, by push, API commit or merge. The refusal reads: refusing to allow a GitHub App to create or update workflow <path> without workflows permission.
  • It can't open, approve or request changes on pull requests unless the repository allows it, and even then its approvals don't count toward required approvals.
  • A reusable workflow never gets more than its caller.
  • A run whose code came from an agent (an agent triggered it, pushed the branch last, or opened the pull request, and any re-run of such a run, whoever starts it, or workflow_run run that follows it) acts as an agent, so the agent guardrails apply: its token can't push or merge to the default branch or a protected branch.

How permissions differ from GitHub

  • The five repository roles match GitHub's names. Diffinery's maintain adds the ability to move or delete tags and to edit other people's comments; repository settings stay with admin.
  • Opening a pull request needs write: its head branch must be a branch in the same repository.
  • Organization members get the organization's base permission on every organization repository, as on GitHub, with the same values (none, read, write, admin) and the same default for new organizations (read). Organization owners and admins get admin. There are no teams or custom roles.
  • Personal access tokens have three scopes (read, write, admin) instead of GitHub's fine-grained permissions; the scope caps your role.
  • GITHUB_TOKEN in a workflow follows GitHub's permissions: model, but new repositories default to read-only tokens, the token never administers the repository or edits workflow files, and code that came from an agent runs under the agent rules.
  • Agents are a separate account type with their own caps and guardrails.