ContextMatrix authenticates to GitHub via a single identity held by CM only. That identity covers CM's own git operations (boards repo, task-skills repo) and REST calls (issue import, branch listing), and it is the source of the short-lived, per-run tokens CM mints for worker containers so they can clone and push project repos. Workers never hold a long-lived credential; the backends never configure their own.
This guide covers end-to-end setup for both supported methods.
| Method | When to use |
|---|---|
| GitHub App (recommended) | Production deployments. Tokens are short-lived (1h), revocable per installation, and can be scoped finer than a PAT. |
| Fine-grained PAT | GitHub Enterprise tenants where App creation is restricted; small-scale or single-developer deployments. |
The credential lives on CM regardless of method. See github-auth-recommended-topologies.md for how this maps onto all-in-one, CM-plus-worker-VM, and Kubernetes layouts.
| Use case | Used by | App permission | Equivalent PAT scope |
|---|---|---|---|
| Boards repo clone/pull/push | CM | Contents: read & write | Contents: read and write |
| Task-skills repo clone/pull | CM (backends clone via a CM-minted token) | Contents: read & write | Contents: read and write |
| Issue importing (project repos) | CM | Issues: read | Issues: read |
| Branch listing (project repos) | CM | Contents: read | Contents: read |
| Project repo clone + push (worker container) | worker (via a per-run token CM mints) | Contents: read & write | Contents: read and write |
| Pull request creation (project repos) | worker via gh/model inside the container |
Pull requests: read & write | Pull requests: read and write |
CM does not call GitHub's PR-creation endpoint itself - the worker container runs
gh pr create (or equivalent) using the token CM minted for that run. CM's own
direct GitHub traffic is boards sync, task-skills pull, issue import, and branch
listing.
App-installation tokens automatically include Metadata: read - that's not a
separate setting. Fine-grained PAT users have to remember to include it
explicitly.
- Navigate to Settings → Developer settings → GitHub Apps → New GitHub App (in your user account or organization, depending on where you want the App to live).
- Fill in:
- GitHub App name:
contextmatrix-yourorg(must be globally unique). - Homepage URL: any URL - required, but unused by ContextMatrix.
- Webhook: uncheck "Active". ContextMatrix doesn't receive webhooks from GitHub directly.
- GitHub App name:
- Under Permissions → Repository permissions, set:
- Contents: read & write
- Issues: read (only if you'll use issue importing)
- Pull requests: read & write (worker containers create PRs)
- Under Where can this GitHub App be installed?, choose Only on this account (recommended) or Any account if you want to install it on multiple orgs.
- Click Create GitHub App.
- On the App's settings page, scroll to Private keys.
- Click Generate a private key. A
.pemfile downloads. - Move the file to a secure location (e.g.,
/etc/contextmatrix/github-app/private-key.pemon a single host, or a k8s Secret in production). It lives on CM only. - Note the App ID at the top of the App's settings page.
- On the App's settings page, click Install App in the left sidebar.
- Choose the account or org and select the repositories the App should access:
- The boards repo (e.g.,
contextmatrix-boards). - The task-skills repo (e.g.,
contextmatrix-task-skills). - Every project repo whose cards ContextMatrix tracks - needed both for CM's issue import / branch listing and for the per-run tokens CM mints so workers can clone and push.
- The boards repo (e.g.,
- After installation, the URL shows the installation ID as a path segment
(e.g.,
https://github.com/settings/installations/12345678).
github:
auth_mode: "app"
app:
app_id: 123456 # from the App's settings page
installation_id: 12345678 # from the installation URL
private_key_path: /etc/contextmatrix/github-app/private-key.pemOr via env vars (recommended for production secrets):
CONTEXTMATRIX_GITHUB_AUTH_MODE=app
CONTEXTMATRIX_GITHUB_APP_ID=123456
CONTEXTMATRIX_GITHUB_INSTALLATION_ID=12345678
CONTEXTMATRIX_GITHUB_PRIVATE_KEY_PATH=/etc/contextmatrix/github-app/private-key.pemThis is the only place the GitHub credential is configured. The agent and chat
backends receive minted tokens from CM at run time (agent workers via
GET /api/agent/git-credentials, chat workers via
GET /api/worker/git-credentials); they have no github: block of their own.
Start the server. The startup log should show:
INFO github token provider initialized auth_mode=app
The server does not validate the private-key file at config-load - it only
checks that private_key_path is non-empty. A missing or unreadable PEM file
fails on the first GitHub call (e.g., git clone of the boards repo) rather
than at startup.
If you see github api: status 401 or status 404 from a git clone or REST
call, the App is not installed on the relevant repo (or the installation was not
granted the Contents: read & write permission).
- Navigate to Settings → Developer settings → Personal access tokens → Fine-grained tokens → Generate new token.
- Set:
- Token name:
contextmatrix. - Expiration: as long as your security policy allows (90 days is typical; CM has no in-process refresh, so you'll rotate manually).
- Repository access: Only select repositories, then add:
- The boards repo
- The task-skills repo
- Every project repo CM tracks
- Token name:
- Under Repository permissions, grant:
- Contents: Read and write
- Issues: Read (for issue importing)
- Metadata: Read (auto-included; double-check it's there)
- Pull requests: Read and write (worker containers create PRs)
- Click Generate token, copy it (it's shown only once), and store it in your secrets manager.
github:
auth_mode: "pat"
pat:
token: "" # leave empty in YAML; supply via env var belowEnv var:
CONTEXTMATRIX_GITHUB_PAT_TOKEN=github_pat_xxxxxxxxxxxxxxxxxxxxxxINFO github token provider initialized auth_mode=pat
Set github.host to your enterprise hostname (no scheme):
github:
auth_mode: "app" # or "pat"
host: "acme.ghe.com"
# api_base_url is derived from host as https://api.acme.ghe.com when left blank.
app:
# ...If your enterprise's API URL doesn't match the standard api.<host> pattern,
set github.api_base_url explicitly.
When github.host is set, both github.com and the enterprise hostname are
accepted simultaneously for project repo URLs (boards, task-skills, and any
project's repo field in .board.yaml). This lets a single CM instance
coordinate work across both surfaces with one identity, provided the App or PAT
has access on both. See internal/config/config.go (AllowedHosts).
- PAT created as classic instead of fine-grained. Classic PATs work but give too-broad access and can't be repo-scoped.
- App not installed on every relevant repo. Issue import on a repo the App isn't installed on returns 404; clone/push on the boards repo without installation returns 403; a worker's per-run token for a project repo fails the same way. Re-install and pick all the repos.
- Token committed to YAML in a public repo. Always use env vars for secrets in production.
- Forgetting to renew a PAT. PATs expire and ContextMatrix has no in-process refresh; the day the PAT expires, all GitHub operations fail - including the worker tokens CM mints from it. Apps don't have this problem: the App credentials (App ID + private key) don't expire, only the installation tokens minted from them. CM wraps its provider in a caching layer that reuses installation tokens until they near expiry, and mints the fresh, short-lived per-run/per-repo tokens it hands to workers from that same identity.
See config.yaml.example for the annotated YAML schema. Every option above maps
to a field in that file.