GitHub authentication for agents
How private repos, workspace repos, runtime tokens, and the GitHub integration relate — and how to verify gh on a runtime.
Agents run on your machine via the daemon. Cloning and fetching private GitHub repositories happens there, using git and optional gh. The Agenthost server does not perform git operations for agent tasks.
Three ways the daemon gets a GitHub token (priority order)
When the daemon starts an agent task, it sets GH_TOKEN / GITHUB_TOKEN on the agent process from one resolved value. The daemon picks the first non-empty source in this order (see resolveGitHubToken in the server/daemon code):
(1) GitHub token saved on the runtime (highest priority)
- Where to set: Agenthost UI → your workspace → Runtimes → select the runtime (device + provider) → GitHub token field. On Save, the server calls GitHub’s
GET /userAPI with your PAT; if GitHub returns 401/403, the save is rejected and nothing is written. On success, the UI shows which GitHub user the PAT belongs to and (when GitHub sends it) token scopes from theX-OAuth-Scopesheader — this is independent of whether theghCLI is installed on the daemon machine. - How it is stored: In PostgreSQL on the
agent_runtimerow, columnsettings(JSONB). The key isgithub_token(plaintext in the DB). API GET responses never return the raw token — onlygithub_token_setand a shortgithub_token_preview(masked). Updating settings usesUPDATE ... SET settings = settings || patch::jsonbso other keys are preserved. When the daemon registers runtimes for a workspace, the server attaches plaintext tokens to the registration HTTP response (github_tokenskeyed by runtime id) over TLS; the daemon keeps that in memory as the highest-priority source forresolveGitHubToken(). Tokens are not embedded in themetadataJSON blob (that blob only carries things like CLI version andghprobe status). - After you change the token: Restart the daemon on that machine so it re-registers and picks up the new value; heartbeats today do not re-stream
github_tokens. - When to use: Team-friendly default — each machine that runs agents can have its own PAT without putting secrets in shell profiles.
- Scopes: For private repo clone/fetch over HTTPS, a classic PAT needs
repo(or a fine-grained token with Contents: Read on the repos you use). For pushes, include write access as needed.
(2) Environment variables on the daemon process
- Where to set: Whatever launches the daemon (shell profile, systemd unit, Docker env, CI, etc.) — set
GH_TOKENorGITHUB_TOKENfor the process that runsagenthost daemon start(or the desktop app’s embedded daemon). - When to use: Headless servers, containers, or when you intentionally want the same token for all workspaces on that host.
(3) GitHub CLI on the host (gh auth login)
- Where to set: On the same user account (or environment) that runs the daemon, run
gh auth loginand complete the flow sogh auth tokenreturns a token. - When to use: Local development when you already use
ghand prefer not to paste a PAT into Agenthost.
If all three are empty, HTTPS clones of private GitHub repos will fail; public repos may still work. SSH remotes ([email protected]:...) can still work if SSH keys and the agent are available to git (not covered by the token list above).
How to see if gh is installed and logged in on a runtime
Open Runtimes in the workspace, choose the runtime row for the machine and provider you care about. The GitHub section shows:
- gh CLI authenticated as <user> —
ghis onPATHandgh auth tokenworks. - gh CLI available (not authenticated) — binary found but not logged in.
- gh CLI not detected on this runtime —
ghwas not found when the daemon registered.
That status reflects the daemon host at registration time; restart the daemon after installing or logging in to gh so metadata refreshes.
metadata.gh_available is not “do I have a runtime PAT?” It only records whether the GitHub CLI (gh) was found on the daemon’s PATH and (when found) whether gh auth status succeeded. You can have gh_available: false in the raw metadata JSON while a runtime GitHub token is saved and used for HTTPS git — those are independent. In the UI, the masked token row under GitHub is the indicator that (1) is configured; the CLI line is optional (3).
Workspace GitHub integration (OAuth) vs git auth
Connecting GitHub under Settings → Integrations stores an OAuth token on the server for Agenthost features (e.g. listing repos, importing issues, webhooks). It does not replace (1)–(3) for local git clone/fetch inside agent tasks.
You can still use the integration to pick repositories when editing Settings → Repositories (“Add from GitHub”), which copies HTTPS URLs into the workspace list. Clone auth for those URLs still uses (1)–(3) on the daemon host.
Workspace repository list
Workspace repositories (Settings → Repositories) are an allowlist of URLs passed to the agent as metadata. They are not credentials. For GitHub HTTPS, use https://github.com/org/repo.git form.
Per-agent PAT / separate GitHub users for commits
Today, one resolved token (per the priority above) is injected into the agent process as GH_TOKEN / GITHUB_TOKEN for that run. Per-agent PATs are not a first-class field yet.
Practical options:
- Different GitHub accounts: Run agents on different machines (or different OS users) with different runtime tokens or
ghlogins — each runtime row maps to one daemon registration context. - Commit author metadata only: You can set
GIT_AUTHOR_NAMEandGIT_AUTHOR_EMAILin the agent’s Environment tab so commits show a chosen name/email; push still uses the runtime/daemon/ghidentity unless you use SSH keys for that identity.
Do not put GH_TOKEN / GITHUB_TOKEN in the agent Environment tab — those keys are blocked; the daemon manages them to avoid accidental overrides and confusion with (1)–(3).
Next
- Daemon and runtimes — heartbeats, offline behavior, parallelism
- Tasks — retries, rerun, failures