Setup Github Agent Config¶
Project: arlyn-docs (ArlynLabs/arlyn-docs)
Date: April 2026
Overview¶
This page covers how Arlyn Labs configures GitHub so that AI agents (such as Claude in Cowork mode) can contribute code via Pull Requests, with all merges controlled by human approval. The approach uses a GitHub App — a first-class GitHub identity for automated systems that requires no paid user licence.
Key goals:
- Agent can open PRs, push to feature branches, and comment — but cannot merge to
main - Every merge requires at least one human approval
- No additional GitHub licence seat is consumed
- Permissions are scoped to only what the agent needs
Step 1: Create a GitHub App¶
A GitHub App gives the agent its own identity (shown as your-app[bot] in PRs and commits) without consuming a paid seat.
- Log in to GitHub as an org owner (
d-arlynlabs) - Go to GitHub.com → Settings → Developer settings → GitHub Apps → New GitHub App
- Fill in the registration form:
| Field | Value |
|---|---|
| GitHub App name | arlyn-agent (or similar) |
| Homepage URL | https://arlyn.io |
| Webhook | Disable (uncheck Active) — not needed for this use case |
| Expire user authorization tokens | Leave unchecked — only needed for OAuth user flows, not installation token auth |
- Under Repository permissions, set:
| Permission | Level |
|---|---|
| Contents | Read & write |
| Pull requests | Read & write |
| Metadata | Read-only (auto-selected) |
- Under Where can this GitHub App be installed?, select Only on this account
- Click Create GitHub App
After creation, note the App ID shown on the app's settings page. The Client ID is also shown but is not needed for the installation token flow. Neither value is a secret and can be noted freely.
Step 2: Generate a Private Key¶
The agent authenticates as the GitHub App using a private key to generate short-lived installation access tokens.
- On the app's settings page, scroll to Private keys
- Click Generate a private key — a
.pemfile downloads automatically - Store it securely at
.secrets/arlyn-agent.pemin the workspace folder — do not commit it to the repo
The private key is the only true secret in this setup. The App ID and Client ID are public identifiers and can be noted freely.
Step 3: Install the App on Your Repositories¶
- From the GitHub App's settings page, click Install App
- Select the ArlynLabs organisation
- Choose Only select repositories and add the repos the agent should work in (e.g.
arlyn-website,arlyn-docs) - Click Install
The Installation ID is visible in the URL of the installed app page and should be noted — it is required when generating installation access tokens programmatically.
Step 4: Configure Branch Protection Rules¶
Branch protection on main is what enforces human approval before any merge. Set this up for each repo the agent contributes to.
- Go to the repo → Settings → Branches → Add branch protection rule
- Set Branch name pattern to
main - Enable the following:
| Rule | Setting |
|---|---|
| Require a pull request before merging | ✅ Enabled |
| Required number of approvals | 1 (minimum) |
| Dismiss stale reviews when new commits are pushed | ✅ Enabled — forces re-review if the agent amends the PR |
| Require status checks to pass before merging | ✅ Enabled — CI must be green |
| Do not allow bypassing the above settings | ✅ Enabled — prevents direct pushes even by admins |
- Under Restrict who can push to matching branches, ensure the GitHub App is not listed as an allowed pusher to
main
Result: The agent can push to any branch and open PRs freely, but only a human with write access can approve and merge.
Step 5: Wiring Up Agent Authentication¶
When an agent needs to authenticate as the GitHub App — to push branches or open PRs via the API — it uses a two-step token exchange. The private key never leaves the local environment; it is only used to sign a short-lived JWT.
How the authentication flow works¶
Private key (.pem)
│
▼
Sign a JWT ← expires in 10 minutes, identifies the App
│
▼
POST /app/installations/{installation_id}/access_tokens
│
▼
Installation ← expires in 1 hour, scoped to selected repos
access token
│
▼
git push / API calls
Generating an installation access token (Python)¶
Install the required library:
Then generate the token:
import jwt
import time
import requests
APP_ID = "3459541"
INSTALLATION_ID = "125976267"
PRIVATE_KEY_PATH = ".secrets/arlyn-agent.pem"
# Load the private key
with open(PRIVATE_KEY_PATH, "r") as f:
private_key = f.read()
# Build and sign the JWT (valid for 10 minutes)
now = int(time.time())
payload = {
"iat": now - 60, # issued-at: 60s in the past to allow for clock skew
"exp": now + 540, # expires: 9 minutes from now (max is 10)
"iss": APP_ID,
}
jwt_token = jwt.encode(payload, private_key, algorithm="RS256")
# Exchange the JWT for an installation access token
response = requests.post(
f"https://api.github.com/app/installations/{INSTALLATION_ID}/access_tokens",
headers={
"Authorization": f"Bearer {jwt_token}",
"Accept": "application/vnd.github+json",
},
)
response.raise_for_status()
access_token = response.json()["token"]
print(access_token) # valid for 1 hour
Using the token for git operations¶
Once you have the installation access token, configure git to use it for the session:
git config --global credential.helper store
echo "https://x-token-auth:${ACCESS_TOKEN}@github.com" > ~/.git-credentials
chmod 600 ~/.git-credentials
The agent can then clone, push, and pull as arlyn-agent[bot] using standard git commands — no interactive authentication required.
Using the token for GitHub API calls¶
Pass the token as a Bearer header for any GitHub REST API call:
headers = {
"Authorization": f"Bearer {access_token}",
"Accept": "application/vnd.github+json",
}
# Example: open a pull request
requests.post(
"https://api.github.com/repos/ArlynLabs/arlyn-docs/pulls",
headers=headers,
json={
"title": "fix: correct token expiry handling",
"head": "agent/fix-token-expiry",
"base": "main",
"body": "Brief description of what changed and why.",
},
)
Token lifetime: Installation access tokens expire after 1 hour. For long-running agent sessions, regenerate the token before it expires by repeating the JWT → token exchange.
Step 6: Practical Workflow¶
With authentication wired up and branch protection in place, the standard contribution flow is:
1. Agent generates an installation access token (Step 5)
2. Agent creates a feature branch
git checkout -b agent/fix-auth-bug
3. Agent makes changes and commits
git add -p
git commit -m "fix: correct token expiry handling"
4. Agent pushes the branch
git push origin agent/fix-auth-bug
5. Agent opens a PR via the GitHub API
- Title: concise description of the change
- Body: what was changed, why, and any relevant context
- Assigns a human reviewer
6. Human reviews, requests changes if needed, then approves
7. Human (or merge queue) merges to main
→ Cloudflare Pages deployment triggers automatically
A few conventions that keep agent PRs easy to review:
- Branch naming: prefix all agent branches with
agent/so they're immediately identifiable - PR body: the agent should always include a short summary of what it changed and why — not just a list of files
- Small PRs: keep agent contributions focused; one logical change per PR makes review faster and safer
Licence & Cost Summary¶
| Identity type | GitHub licence required? |
|---|---|
| GitHub App | No — free |
| Machine user (free org) | No |
| Machine user (paid org) | Yes — consumes a seat |
Using a GitHub App is the correct approach for a paid GitHub organisation. It avoids licence costs entirely while providing a proper, auditable identity for all agent activity.
Key References¶
| Item | Value |
|---|---|
| GitHub App name | arlyn-agent |
| App ID | 3459541 |
| Installation ID | 125976267 |
| GitHub organisation | ArlynLabs |
| App permissions | Contents (R/W), Pull requests (R/W), Metadata (R) |
| Private key location | .secrets/arlyn-agent.pem (workspace folder, not committed) |
| Protected branch | main (all repos) |
| Required approvals | 1 human reviewer |
| Agent branch prefix | agent/ |
| Token lifetime | Installation access tokens expire after 1 hour |
| App settings | GitHub → Settings → Developer settings → GitHub Apps |