token— the default for local and individual use. Fabro capturesgh auth tokenduringfabro install, stores it asGITHUB_TOKEN, and uses that token directly for repo access, pull requests, and sandboxGITHUB_TOKENinjection.app— the team-oriented option. Fabro registers a GitHub App, uses installation tokens for repo access, enables browser OAuth, and supports webhook delivery when you configure a webhook strategy.
token changes GitHub integration auth only. It does not provide browser sign-in, so the embedded web UI is disabled when strategy = "token".
Strategy matrix
| Capability | token | app |
|---|---|---|
| CLI pull requests | Yes | Yes |
| Private repo cloning | Yes | Yes |
Sandbox GITHUB_TOKEN | Direct token | Scoped installation token |
| Browser sign-in | No | Yes |
| Web UI routes | Disabled | Enabled |
| Webhooks | No | Strategy-dependent |
GitHub App mode
The rest of this page describes theapp strategy, which is required for browser auth and for any webhook delivery strategy.
| Feature | How it’s used |
|---|---|
| OAuth login | Users sign in to the web UI with their GitHub account |
| Private repo cloning | Daytona and Docker sandboxes clone private repositories using short-lived Installation Access Tokens |
| Checkpoint pushing | After each workflow stage, Fabro pushes the run branch and metadata branch back to origin from inside the sandbox |
| Auto-PR | When [run.pull_request] enabled = true in the run config, Fabro opens a PR from the agent’s working branch after a successful run |
| Auto-merge | When [run.pull_request] auto_merge = true, Fabro enables GitHub’s auto-merge on created PRs so they merge automatically once required checks pass |
| Sandbox GITHUB_TOKEN | When [server.integrations.github.permissions] are declared in the server config, Fabro mints a scoped Installation Access Token and injects it as GITHUB_TOKEN in the sandbox |
Setup
Prerequisites
- A GitHub account (personal or organization)
- Shell access to the host that runs the Fabro server
- The Fabro web app running (
cd apps/fabro-web && bun run dev) if you want browser sign-in after setup
Register the GitHub App with fabro install
Run the installer on the same machine that will run the Fabro server:
| Permission | Level | Purpose |
|---|---|---|
| Contents | Write | Clone repos, push run branches and checkpoints |
| Metadata | Read | Look up repository installation status |
| Pull requests | Write | Create and update PRs from workflows |
| Checks | Write | Report workflow status on commits |
| Issues | Write | Create issues from workflows |
| Emails | Read | Read verified email for OAuth login |
- Lets you choose where to register the app. If you have the
ghCLI installed, Fabro detects your GitHub username and any organizations you administer and lets you pick. Ifghis not available, the installer prompts for a GitHub token and uses it to look up your identity and organizations. - Opens GitHub in your browser so you can review the manifest and click Create GitHub App.
- Receives GitHub’s temporary callback on localhost, exchanges it for permanent app credentials, and writes:
app_id,client_id, andslugto~/.fabro/settings.tomlGITHUB_APP_CLIENT_SECRET,GITHUB_APP_WEBHOOK_SECRET, andGITHUB_APP_PRIVATE_KEYto<data_dir>/server.env
- Prints the resulting app slug so you can install the app on the repositories Fabro should access.
Install the app on GitHub
Go tohttps://github.com/settings/apps/<your-app-slug>/installations and install it on the repositories Fabro should access.
Verify the configuration
Run the doctor command to check that all GitHub App credentials are in place:| Field | Source |
|---|---|
server.integrations.github.app_id | ~/.fabro/settings.toml |
server.integrations.github.client_id | ~/.fabro/settings.toml |
GITHUB_APP_CLIENT_SECRET | <data_dir>/server.env |
GITHUB_APP_WEBHOOK_SECRET | <data_dir>/server.env |
GITHUB_APP_PRIVATE_KEY | <data_dir>/server.env |
Configuration
The GitHub App configuration lives in two places:~/.fabro/settings.toml
settings.toml
| Field | Description |
|---|---|
app_id | Numeric GitHub App ID |
client_id | OAuth Client ID for the app |
slug | App slug, used for linking to the GitHub App settings page |
server.env
Fabro stores the GitHub App secrets in <data_dir>/server.env under these keys:
GITHUB_APP_CLIENT_SECRETGITHUB_APP_WEBHOOK_SECRETGITHUB_APP_PRIVATE_KEY
-----BEGIN).
Webhook delivery strategies
Fabro receives GitHub webhooks onPOST /api/v1/webhooks/github whenever GITHUB_APP_WEBHOOK_SECRET is configured. The webhook strategy controls how that route becomes reachable from GitHub:
settings.toml
server_url: recommended for production. Fabro assumesserver.api.urlis already publicly reachable and best-effort updates the GitHub App webhook URL to<server.api.url>/api/v1/webhooks/githubeach timefabro server startruns.tailscale_funnel: opt-in for machines reachable through Tailscale but not through a stable public URL. Fabro runstailscale funnelagainst the main server port and best-effort updates the GitHub App webhook URL to the resulting Funnel origin.- Unset
strategy: Fabro still serves the webhook route if the secret is present, but it does not expose the route for you and does not mutate the GitHub App webhook URL.
tailscale_funnel has host-wide side effects: it changes Tailscale Funnel state on the server and rewrites the GitHub App webhook URL on startup. Use server_url when you already have HTTPS and a stable hostname.
Reconfigure GitHub after install
To switch GitHub strategies or re-register the app without re-running the full install wizard, usefabro install github:
token mode
Choose GitHub CLI in fabro install to use the default local-user flow. The installer:
- Runs
gh auth token - Stores the token as
GITHUB_TOKEN - Writes
strategy = "token"under[server.integrations.github]
GITHUB_TOKEN from the vault or environment (with GH_TOKEN as a fallback). Token updates after install are the user’s responsibility.
In this mode, Fabro disables the embedded web UI and browser auth routes. Machine API routes and /health continue to work.
How it works
OAuth login
The web app uses the GitHub App’s OAuth credentials to authenticate users:- User clicks Sign in with GitHub on the login page
- Fabro redirects to GitHub’s OAuth authorization endpoint with scopes
read:useranduser:email - User authorizes the app on GitHub
- GitHub redirects back with an authorization code
- Fabro exchanges the code for an access token and fetches the user’s profile and verified email
- Fabro checks the username against the
allowed_usernameslist insettings.toml
settings.toml:
settings.toml
allowed_usernames list rejects all users.
Repository cloning in sandboxes
When a workflow runs in a remote sandbox (Daytona or Docker), Fabro clones the current repository into the sandbox using the GitHub App:- Fabro detects the local repository’s
originremote URL and current branch - SSH URLs (e.g.
git@github.com:owner/repo.git) are converted to HTTPS - Fabro signs a short-lived JWT using the App ID and private key (RS256, 10-minute validity)
- Using the JWT, Fabro looks up the GitHub App installation for the repository (
GET /repos/\{owner\}/\{repo\}/installation) - Fabro requests a scoped Installation Access Token with
contents: writepermission on the specific repository - The sandbox clones via HTTPS using
x-access-tokenas the username and the token as the password
GITHUB_TOKEN injection
When a run config declares[github] permissions, Fabro mints a scoped Installation Access Token at startup and injects it into the sandbox as the GITHUB_TOKEN environment variable. Agents running inside the sandbox can use this token for GitHub API calls, cloning additional private repos, or pushing to branches.
run.toml
.fabro/project.toml as a project-level default, so all workflows in the project automatically get a GITHUB_TOKEN without repeating the config in each run TOML.
Checkpoint pushing
After each workflow stage, Fabro checkpoints by pushing the run branch and metadata branch to origin. Inside remote sandboxes, the git remote URL is configured with the Installation Access Token for authenticated pushing. For long-running workflows, Fabro refreshes the token before each push since Installation Access Tokens are short-lived (typically 1 hour).Troubleshooting
”GitHub App is not installed for {owner}”
The GitHub App exists but hasn’t been installed on the organization or user account that owns the repository. Install it at:“GitHub App is private but this repo belongs to a different owner”
GitHub Apps are private by default, meaning they can only be installed on repositories owned by the same account or organization that owns the app. If you need to install the app on a repository owned by a different user or organization, you must make the app public:- Go to GitHub → Settings → Developer settings → GitHub Apps → {your app}
- Scroll to the bottom under Danger zone
- Click Make public
”GitHub App installation is suspended”
The installation was disabled in GitHub’s settings. Re-enable it in the organization’s GitHub App settings.”GitHub App does not have access to repository {repo}”
The app is installed but doesn’t have access to this specific repository. Update the installation’s repository permissions to include it (the app may be configured for “Only select repositories”).”GitHub App authentication failed”
Theapp_id in settings.toml or the GITHUB_APP_PRIVATE_KEY environment variable is incorrect. Re-run fabro install on the server host or verify the values match your GitHub App.
Clone fails for private repositories
If you seeGit clone failed ... If this is a private repository, configure a GitHub App, the GitHub App credentials are not configured. Run fabro install on the server host or verify with fabro doctor.