Skip to content

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.

  1. Log in to GitHub as an org owner (d-arlynlabs)
  2. Go to GitHub.com → Settings → Developer settings → GitHub Apps → New GitHub App
  3. 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
  1. Under Repository permissions, set:
Permission Level
Contents Read & write
Pull requests Read & write
Metadata Read-only (auto-selected)
  1. Under Where can this GitHub App be installed?, select Only on this account
  2. 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.

  1. On the app's settings page, scroll to Private keys
  2. Click Generate a private key — a .pem file downloads automatically
  3. Store it securely at .secrets/arlyn-agent.pem in 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

  1. From the GitHub App's settings page, click Install App
  2. Select the ArlynLabs organisation
  3. Choose Only select repositories and add the repos the agent should work in (e.g. arlyn-website, arlyn-docs)
  4. 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.

  1. Go to the repo → Settings → Branches → Add branch protection rule
  2. Set Branch name pattern to main
  3. 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
  1. 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:

pip install PyJWT cryptography requests

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