Murmur authenticates with GitHub using the gh CLI by default. You can provide a GitHub Personal Access Token (PAT) instead — either by pasting it during interactive setup or by setting the MURMUR_GH_PAT environment variable for non-interactive (CI) runs.
When you need a PAT
Most developers do not need to create a PAT. During murmur setup, the default option is “Use gh CLI token,” which reuses your existing gh auth login session.
Choose a PAT when:
- You are running
murmur setup --non-interactive in CI or a headless environment (set MURMUR_GH_PAT). This is the only path that does not require the gh CLI to be installed.
- You want fine-grained control over token permissions and expiration
Required permissions
Murmur uses the GitHub token to list repositories, read and write issues and pull requests, push code, and verify org membership. The required scopes depend on whether you create a classic or fine-grained token.
Scopes for Classic PAT
| Scope | Purpose |
|---|
repo | Read/write access to repositories, issues, and pull requests |
read:org | Read-only access to org membership and roles |
For classic PATs, repo covers issues and pull requests — there are no separate classic scopes for those.
If you want agents to sign commits with a verified signature, also add the admin:ssh_signing_key scope. This is optional — agents work without it, but their commits will be unverified.
Scopes for fine-grained PAT
| Permission | Access | Purpose |
|---|
| Contents | Read and write | Clone repos, push branches |
| Issues | Read and write | Read and create issue comments |
| Pull requests | Read and write | Open PRs, read and post review comments |
| Organization members | Read | Verify org membership |
Fine-grained PATs also require:
- Resource owner set to your organization (not your personal account)
- Repository access set to “All repositories” or the specific repositories your agents will work on
For commit signing with a fine-grained PAT, add the SSH signing keys permission at Read and write.
Creating a classic PAT
- Go to Settings → Developer settings → Personal access tokens → Tokens (classic) on GitHub, or open github.com/settings/tokens directly.
- Click Generate new token → Generate new token (classic).
- Give the token a descriptive name (e.g. “Murmur PAT”).
- Set an expiration. Murmur does not enforce a minimum, but shorter is better.
- Select the scopes:
- repo (full control of private repositories)
- read:org (under admin:org)
- Optionally admin:ssh_signing_key for commit signing
- Click Generate token and copy the value immediately — GitHub will not show it again.
SSO-enforced organizations: If your org requires SAML single sign-on, GitHub will not let the token access org resources until you explicitly authorize it. After creating the token, return to the Personal access tokens list, click Configure SSO next to the token, and click Authorize for each org you need. Without this step, Murmur API calls to those orgs return 403 Resource protected by organization SAML enforcement.
Creating a fine-grained PAT
- Go to Settings → Developer settings → Personal access tokens → Fine-grained tokens on GitHub, or open github.com/settings/tokens?type=beta directly.
- Click Generate new token.
- Give the token a descriptive name and set an expiration.
- Under Resource owner, select the organization whose repos your agents will access.
If the org requires admin approval for fine-grained PATs, GitHub sends an approval request to org admins after you click Generate token. The token is created immediately but remains in a pending state — it cannot access org resources until an admin approves it at Organization settings → Personal access tokens. You will receive an email when approved. If the token stays pending, ask your org admin to approve it, or switch to a classic PAT.
- Under Repository access, choose “All repositories” or select the specific repos your agents will work on. Selecting too few repos is a common source of 403 errors — see Troubleshooting.
- Under Permissions → Repository permissions, set:
- Contents → Read and write
- Issues → Read and write
- Pull requests → Read and write
- Under Permissions → Organization permissions, set:
- Optionally, set SSH signing keys → Read and write for commit signing.
- Click Generate token and copy the value.
Using the token
Interactive setup
Run murmur setup and select “Paste a Personal Access Token (PAT)” when prompted. Murmur validates the token against the GitHub API, confirms your username and permissions, and stores it in your encrypted developer profile.
▸ How would you like to authenticate with GitHub?
> Use gh CLI token (recommended)
Paste a Personal Access Token (PAT)
Interactive setup requires the gh CLI to be installed even when you choose the PAT option — gh is used for other operations during setup (e.g. commit signing). The token is set as GH_TOKEN for the duration of the setup process only. This is process-local: it does not run gh auth login or otherwise overwrite your existing gh CLI session.
Commit signing failures don’t abort setup. If you enable commit signing with a PAT that lacks the signing-key permission (admin:ssh_signing_key for classic, SSH signing keys: Read and write for fine-grained), Murmur cannot upload the signing key. Rather than failing, setup prints a warning with the public key and a link to github.com/settings/ssh/new so you can add it manually as a Signing Key. The rest of setup completes normally; until the key is uploaded, agent commits are unverified.
Non-interactive setup
Set the MURMUR_GH_PAT environment variable:
MURMUR_GH_PAT=ghp_xxxxxxxxxxxx murmur setup --non-interactive --upload
The token is validated at startup. If it is missing required scopes, setup fails with a clear error message listing the missing permissions.
GitHub Actions: Store the PAT as an encrypted Actions secret in your repository or organization, then map it to MURMUR_GH_PAT in your workflow:
- name: Set up Murmur
env:
MURMUR_GH_PAT: ${{ secrets.MURMUR_GH_PAT }}
run: murmur setup --non-interactive --upload
The secret name in GitHub Actions is arbitrary — only the env var name MURMUR_GH_PAT matters. Avoid naming the secret GITHUB_TOKEN; GitHub reserves that name for its own short-lived App installation token (ghs_…). If that value is passed as MURMUR_GH_PAT, Murmur rejects it: GitHub returned empty login — token may be a GitHub App token, not a PAT.
Where the token is stored
The GitHub token is KMS-encrypted during setup and stored as the GH_TOKEN entry in the encrypted_secrets map in .murmur/murmur.local.yaml — a gitignored file that cannot be read without the Cloud KMS key. See Encryption for the full encryption lifecycle.
When an agent is spawned, each secret (including the GitHub token) is re-sealed to the agent VM’s ephemeral key and decrypted only in process memory. The token is never written to disk on the VM.
Token validation
Murmur validates your token when you provide it during setup. Validation calls the GitHub API with a 15-second timeout. If the GitHub API is slow or unreachable, validation fails and setup stops with a clear error — re-run setup once connectivity is restored.
- Classic PATs — the
X-OAuth-Scopes response header from GET /user is compared against the required scopes (repo and read:org). Scope hierarchy is respected — admin:X satisfies write:X and read:X, and write:X satisfies read:X — so admin:org or write:org both satisfy read:org. Token type is determined automatically by the presence of this header.
A classic PAT with no scopes granted produces no X-OAuth-Scopes header and is indistinguishable from a fine-grained PAT. In that case Murmur treats it as fine-grained and may not catch missing scopes at setup time — the token will fail at runtime. If setup reports a fine-grained token but you created a classic PAT, verify that repo and read:org are selected on the token’s settings page.
- Fine-grained PATs — fine-grained tokens do not expose scope headers. Murmur picks a single repository to probe — the most recently updated repo the token can access — and checks its
/issues and /pulls endpoints, where a 403 response indicates a missing permission.
This probe verifies permissions on one repository only. It does not prove that every repository you selected has the right permissions. If your token grants different permissions across repos, the probe can pass while other repos still fail at runtime. Grant the same Issues and Pull requests permissions across all repos your agents will work on.
Verification is skipped (not failed) in several cases — the token is still accepted and stored, with the warning “Fine-grained PAT — some permissions could not be verified”:
- No repositories are accessible to the token.
- The probe repository has Issues or Pull requests disabled.
- GitHub returns any other status that is neither
200 (permission confirmed) nor 403 (permission missing). When verification is skipped, operations requiring Issues or Pull requests access will fail at runtime if those permissions are absent. Ensure at least one target repository — ideally one with Issues and PRs enabled — is in scope before running setup.
Expiration and rotation
GitHub PATs expire on the date you set when creating them. When a token expires, CLI calls and agent operations start failing with authentication errors.
To rotate a token:
- Create a new PAT with the same permissions as above.
- For SSO-enforced orgs, authorize the new token immediately (see SAML/SSO).
- Run
murmur setup again. When prompted, paste the new token. Murmur re-encrypts it into your developer profile.
Set a calendar reminder a few days before your token expires so you can rotate it without downtime. GitHub sends an email when a PAT is about to expire, but that email can be easy to miss in a busy inbox.
For non-interactive environments, update the MURMUR_GH_PAT secret in your secrets store or CI provider and re-run the setup job before the old token expires.
Troubleshooting
403 on org-scoped operations
Classic PAT — missing read:org scope. Confirm the token has read:org (or a superset like admin:org) at github.com/settings/tokens.
Classic PAT — SAML not authorized. In SSO-enforced orgs, look for a Configure SSO button next to the token on the tokens list page. If the button shows “Authorize” for your org, click it. A token that is not SSO-authorized returns 403 Resource protected by organization SAML enforcement regardless of its scopes.
Fine-grained PAT — pending org approval. If the token was created with an org as the resource owner and the org enforces a PAT approval policy, the token cannot access org resources until an admin approves it. Check the status at GitHub → Your profile → Settings → Developer settings → Fine-grained tokens. The token status shows “Pending approval” until an org admin acts.
403 on repository operations
Fine-grained PAT — repository not in scope. Fine-grained PATs only access the repositories you selected at creation time. If an agent is asked to work on a repo that wasn’t included, every API call to that repo returns 403. Either re-create the token with the repo included, or change the repository access to “All repositories.”
Fine-grained PAT — wrong resource owner. If the token’s resource owner is your personal account but the repo belongs to an org, the token cannot access org repos. Re-create the token with the org as the resource owner.
”GitHub returned empty login — token may be a GitHub App token, not a PAT”
Murmur returns this error when the token does not belong to a GitHub user account. Common causes:
- You set
MURMUR_GH_PAT to the value of GitHub Actions’ auto-provisioned GITHUB_TOKEN (a ghs_…-prefixed App installation token that expires when the job ends).
- You used an OAuth App credential or a GitHub App server-to-server token instead of a PAT.
Create a classic or fine-grained PAT as described above and use that value instead.
Token works in the browser but not in Murmur
If you can access GitHub in a browser but Murmur rejects the token, the most common causes are:
- The token was created but not yet SAML-authorized for the org.
- The token is a fine-grained PAT that is still pending org approval.
- You copied the token with leading or trailing whitespace — paste it again directly from the clipboard.