Netclode uses a GitHub App to generate per-repo scoped tokens on demand. Each token only has access to the repos you select.
When you create a session with repos:
- You select repos and access level (read or write)
- Control-plane generates a token scoped to only those repos
- Sandbox clones the repos on startup
- Agent can push commits (if write access granted)
- Access level can be changed mid-session
| Repo Selected | Access Level | Capabilities |
|---|---|---|
| No | N/A | No git operations |
| Yes | Read (default) | Clone only |
| Yes | Write | Clone and push |
Write access is always scoped to the selected repos only - you can't accidentally push to other repos.
- Go to https://github.com/settings/apps/new
- Fill in:
- Name:
Netclode - Homepage URL:
https://github.com/angristan/netclode - Webhook: Check "Active" if using the GitHub Bot, otherwise uncheck
- Name:
- Set permissions:
- Contents: Read and write
- Metadata: Read-only
- Pull requests: Read and write (optional)
- Issues: Read and write (required for GitHub Bot)
- Install scope: Only on this account (or Any account for multiple orgs)
- Click Create GitHub App
- After creating the app, scroll down to Private keys
- Click Generate a private key
- A
.pemfile will be downloaded - Base64 encode the key for your
.env:cat your-app-name.2024-01-26.private-key.pem | base64 | tr -d '\n'
- Go to your app's settings → Install App
- Choose account/org
- Select All repositories (or specific ones)
- Note the Installation ID from the URL:
https://github.com/settings/installations/12345678→ ID is12345678
Add the following to your .env file:
# GitHub App for repository access
GITHUB_APP_ID=123456 # App ID from app settings page
GITHUB_APP_PRIVATE_KEY_B64= # Base64-encoded private key
GITHUB_INSTALLATION_ID=12345 # From installation URLcd infra/ansible
DEPLOY_HOST=your-server ansible-playbook playbooks/secrets.yaml
make rollout-control-planeWhen creating a session via Connect protocol, include the repos and repo_access fields:
{
"type": "session.create",
"name": "my-feature",
"repos": ["owner/repo", "owner/other"],
"repoAccess": "write"
}| Field | Values | Default |
|---|---|---|
repos |
Repositories in owner/repo format or full URL |
- |
repoAccess |
read, write |
read |
The following formats are supported for each entry in repos:
owner/repo- Short format (recommended)https://github.com/owner/repo- Full HTTPS URLhttps://github.com/owner/repo.git- With .git suffix
iOS App: Session menu → tap access level → select new level
When access changes, control-plane generates a new token and the agent reconfigures git credentials immediately. Useful when you start read-only and later need to push.
When a session starts with repositories, the agent broadcasts progress events:
{
"type": "agent.event",
"sessionId": "abc123",
"event": {
"kind": "repo_clone",
"timestamp": "2026-01-18T22:50:00Z",
"repo": "https://github.com/owner/repo.git",
"stage": "starting",
"message": "Cloning repository..."
}
}Possible stages:
starting- Clone is beginningdone- Clone completed successfullyerror- Clone failed (agent continues without repos)
┌─────────────────┐ ┌──────────────────┐
│ Client │────▶│ Control Plane │
│ │ │ │
│ session.create │ │ 1. Generate repo-│
│ {repos, access} │ │ scoped token │
└─────────────────┘ │ via GitHub App│
└────────┬─────────┘
│
▼
┌──────────────────┐
│ Sandbox Pod │
│ │
│ GITHUB_TOKEN env │
│ GIT_REPOS env │
│ │
│ entrypoint.sh: │
│ - Configure creds│
│ - git clone │
└──────────────────┘
┌─────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Client │────▶│ Control Plane │────▶│ Agent │
│ │ │ │ │ │
│ repo.access. │ │ 1. Validate req │ │ 1. Receive msg │
│ update │ │ 2. Generate new │ │ 2. Reconfigure │
│ {write} │ │ token via App │ │ git creds │
│ │◀────│ 3. Send response │ │ 3. Ready for │
│ │ │ │ │ push │
└─────────────────┘ └──────────────────┘ └──────────────────┘
GitHub App tokens expire after 1 hour, scoped to only the requested repos and permissions. If a token expires during a long session, control-plane handles refresh automatically.
"Repository not found" - verify the repo exists and GitHub App is installed on the owner account/org.
"Permission denied" during push - session has read-only access. Change to write in session menu.
"GitHub App not configured" - check env vars:
kubectl --context netclode -n netclode exec deploy/control-plane -- printenv | grep GITHUB_APP"Resource not accessible by integration" - app doesn't have access to this repo. Go to https://github.com/settings/installations and add the repo.
- Per-repo scoping - tokens only access the specific repos requested
- Minimal permissions - read or write, nothing more
- Short-lived - tokens expire after 1 hour
- No storage - tokens generated on-demand, not stored in DB
- Private key protection - stored in k8s secrets, never exposed to clients