Role-scoped GitHub App installation tokens for automated agents. Part of the clagentic suite.
Gatekeeper stands at the GitHub gate. When an automated agent needs to act on a repository, Gatekeeper mints a short-lived, role-scoped GitHub App installation token narrowed to exactly what that role is allowed to do — and nothing more.
It ships four generic roles out of the box:
| Role | Can do | Cannot do |
|---|---|---|
builder |
Push feature branches, open/update PRs | Merge, push to the default branch |
reviewer |
Submit PR reviews (approve / request changes), comment | Push code, merge |
merger |
Merge PRs, push to the default branch | Open PRs, author feature work |
security |
Post security review comments, request changes | Push code, merge |
The roles are generic. Gatekeeper does not know or care what agents you run. You map your own agents to roles in your own configuration. Gatekeeper's only job is: given a role, return a token scoped to that role's permissions.
You can also define custom roles in config.yaml without forking code — for example a releaser scoped only to tagging, or a deployer with deployment write access. See docs/ROLES.md under "Adding a custom role" for the config schema.
GitHub forbids an actor from approving its own pull request. A workflow where one identity builds, reviews, and merges therefore cannot produce a credible, auditable "built → reviewed → merged by separate actors" trail. Gatekeeper solves this by minting distinct, role-narrowed tokens from distinct GitHub Apps, so every PR visibly flows through separate build, review, and merge actors. An optional security role can add an independent security review gate on top of that core trail.
The App private keys never touch the agent. Gatekeeper reads them from a pluggable secret broker (OpenBao by default), signs the App JWT server-side, and hands the agent only a ≤1-hour installation token narrowed to its role.
- It is not a dispatcher, a queue, or an agent framework. It mints tokens. That is the whole surface.
- It is not coupled to any specific set of agents. Agent→role mapping lives in the consumer, not here.
- It does not store long-lived secrets. The broker does.
# Mint a token for the builder role, scoped to one repo.
gatekeeper mint --role builder --repo owner/name
# Returns a short-lived installation token on stdout.A consumer (e.g. an agent dispatcher) calls gatekeeper mint --role <role> with the role mapped to its agent, then uses the returned token for the git/API operations that role permits.
Copy config.example.yaml to config.yaml and fill in your values. All deployment-specific values — org name, broker endpoint, broker secret paths, role→app bindings — live there. No hardcoded org names, hostnames, paths, or identities exist in the code.
github:
owner: your-org-name
api_base: https://api.github.com
broker:
type: openbao # openbao | vault | env | file
endpoint: https://broker.example.com
auth: approle # approle | token
roles:
builder:
app_id_path: secret/gatekeeper/builder/app-id
installation_id_path: secret/gatekeeper/builder/installation-id
private_key_path: secret/gatekeeper/builder/private-key
# ... reviewer, mergerSee config.example.yaml for the full reference.
Registering a GitHub App requires a one-time manual step — Gatekeeper cannot script first-time App creation.
- Register four GitHub Apps on your org: one each for
builder,reviewer,merger, andsecurity, with the per-role permissions indocs/ROLES.md. - Install each App on the target repos.
- Store each App's
app-id,installation-id, andprivate-keyin your broker at the paths yourconfig.yamlpoints to. - Apply a branch ruleset (see
docs/GOVERNANCE.md) that requires PR + review and restricts who may push the default branch.
After that, everything is code.
Gatekeeper's broker is pluggable:
| Type | Use case | Credentials from |
|---|---|---|
openbao |
Production | BROKER_ROLE_ID + BROKER_SECRET_ID (AppRole) or BROKER_TOKEN |
vault |
Production (Vault) | Same env vars |
env |
Local dev / CI | Env var name is the secret path |
file |
Local dev / CI | File path is the secret path |
The private key is read server-side only, used to sign the App JWT, and never returned, logged, or persisted.
docs/ROLES.md— per-role GitHub App permission tablesdocs/GOVERNANCE.md— branch ruleset and CODEOWNERS referencedocs/DESIGN.md— module architecture and security invariants
go build ./cmd/gatekeeperRequires Go 1.22+. No external dependencies beyond the standard library.
If clagentic:gatekeeper is useful to you: ko-fi.com/clagentic
Not affiliated with Anthropic or OpenAI. Claude is a trademark of Anthropic. Codex is a trademark of OpenAI. Provided "as is" without warranty. Users are responsible for complying with their AI provider's terms of service.
FSL-1.1-MIT — Functional Source License 1.1, with MIT as the Change License.
Free for personal, internal-business, evaluation, research, and non-commercial use. Not free for offering this tool (or a substantial fork) as a competing commercial product. Each release auto-converts to MIT on its second anniversary.
