Organization profiles
An organization profile defines sets of repository access and permissions available to agents associated with the Buildkite organization, optionally restricted to specific pipelines via match rules.
The location of the profile configuration file is specified via the GITHUB_ORG_PROFILE environment variable.
Profile-related tokens are requested via separate URL paths. Tokens will not be vended on these paths unless configuration is present.
Profiles are useful for a variety of use cases where low-risk access is required by a wide set of repositories. For example:
- Accessing private packages or releases
- Loading Buildkite plugins from private repositories
- Cloning or reading multiple private repositories within a pipeline
Organization profile structure
Section titled “Organization profile structure”The profile configuration file is provided as YAML with both organization and pipeline profile sections:
organization: profiles: - name: "<profile-name>" app: "<app-name>" # Optional: the GitHub App tokens are created through match: # Optional: restricts which pipelines can use this profile - claim: "<claim-name>" value: "<exact-value>" # OR valuePattern: "<regex>" # One of value/valuePattern required repositories: - "<repository-name>" permissions: ["<permission>"]
pipeline: defaults: permissions: ["<permission>"] profiles: - name: "<profile-name>" # ... see pipeline profile referenceFields
Section titled “Fields”organization
Section titled “organization”The root element that contains all organization-related configurations.
profiles
Section titled “profiles”A list of profiles within the organization. Each profile must contain:
The name of the profile. This should be a unique identifier for the profile.
Optional. The name of a GitHub App registered with
GITHUB_APPS. Omitted, or set to
default, creates the profile’s tokens through the default app.
An empty value, or a name that is not a configured, enabled app, makes the
profile invalid: requests for it return 404.
See using multiple GitHub Apps.
Optional claim matching rules that restrict which pipelines can use this profile. Omit this field entirely to make the profile available to all pipelines.
See the profile matching reference for complete details on:
- Match rule syntax (exact vs regex matching)
- Available claims
- Pattern examples
- Troubleshooting
repositories
Section titled “repositories”The repositories the profile grants access to. One of:
- A list of repository names (owner/organization omitted), e.g.
["release-tools", "shared-infra"] {{all-repositories}}, granting access to every repository the GitHub App installation can reach.{{caller-scoped-repository}}, narrowing the token to a single repository named by the caller at request time (see caller-scoped repositories below)
A literal ({{all-repositories}}, {{caller-scoped-repository}}, or *)
must be the only entry in the list; it cannot be combined with named
repositories.
permissions
Section titled “permissions”A list of permissions granted to the profile. The metadata:read permission is automatically included in all tokens. See the GitHub documentation for tokens for available permission values.
Example
Section titled “Example”organization: profiles: # allow read access to a set of buildkite-plugins - name: "buildkite-plugin" # array of repos accessible to the profile repositories: - somewhat-private-buildkite-plugin - very-private-buildkite-plugin permissions: ["contents:read"]
# allow package access to any repository - name: "package-registry" repositories: ["{{all-repositories}}"] permissions: ["packages:read"]
# publish packages through a dedicated GitHub App - name: "package-publisher" app: packages repositories: ["{{all-repositories}}"] permissions: ["packages:write"]
# let a shared CI pipeline open PRs against any repository it names - name: "agent-pr" repositories: ["{{caller-scoped-repository}}"] permissions: ["contents:write", "pull_requests:write"]
# allow write access only for release pipelines on main branch - name: "release-publisher" match: - claim: pipeline_slug valuePattern: ".*-release" - claim: build_branch value: "main" repositories: ["release-tools", "shared-infra"] permissions: ["contents:write", "packages:write"]
pipeline: defaults: permissions: ["contents:read"]Accessing organization profiles
Section titled “Accessing organization profiles”Organization profiles are requested via:
/organization/token/{profile}for JSON token responses/organization/git-credentials/{profile}for Git credential helper format
From Buildkite plugins
Section titled “From Buildkite plugins”The Chinmina Token plugin and Chinmina Git Credentials plugin use the org: prefix to identify organization profiles:
environment: - PACKAGES_TOKEN=org:package-registry - PLUGINS_TOKEN=org:buildkite-pluginThe plugins translate these to appropriate API paths (/organization/token/package-registry, etc.).
Caller-scoped repositories
Section titled “Caller-scoped repositories”A profile with repositories: ["{{caller-scoped-repository}}"] does not
store a fixed repository list. Instead, the caller names a single target
repository per request, and the vended token is narrowed to it — useful for
workflows (e.g. AI coding agents) that operate against a different
repository each run without needing one profile per repository.
/organization/token/{profile} takes the target repository via the
repository-scope query parameter:
POST /organization/token/agent-pr?repository-scope=widgetThis endpoint returns 400 Bad Request when repository-scope is:
- Missing on a caller-scoped profile
- Supplied to a profile that is not caller-scoped
- Empty or malformed
/organization/git-credentials/{profile} derives the target repository
from the path property in the request body. It ignores the repository-scope
query parameter. For a supported destination, a caller-scoped profile returns
400 Bad Request when path does not resolve to a repository.
Empty targets and unsupported destinations return 200 without credentials before profile resolution. See Git credential request handling for the target validation and repository derivation rules.
On both endpoints, repository names containing /, whitespace, or control
characters return 400 Bad Request. Valid names are used verbatim as the
repository name and cache key.
If GitHub rejects the token request, the response is a generic 403 Forbidden.
This includes repositories that do not exist or are outside the installation.
The response does not reveal whether a repository exists.
See also
Section titled “See also”For permissions scoped to the pipeline’s own repository, see pipeline profiles.
