Among Hermes Agent’s ~78 bundled skills are several for GitHub — PR workflows, code review, issue triage, repo management — all gated behind one thing first: the agent actually being able to authenticate to GitHub. That’s handled by a dedicated github-auth skill.
How Detection Works
The skill checks four places, in this exact order, and stops at the first one that works:
ghCLI — ifgh auth statussucceeds, Hermes uses it for everything. This is the path of least setup: no token to generate or store at all.GITHUB_TOKENenvironment variable — used directly for API calls viacurlif set.~/.hermes/.env— aGITHUB_TOKEN=line in Hermes’s own config directory.- Git credential store —
~/.git-credentials, extracted as a last resort if nothing else is configured.
If none of these resolve, GitHub-dependent skills simply aren’t available — nothing crashes, they just can’t do anything that needs GitHub access.
Option A: Use the gh CLI (Simplest)
If you already have the GitHub CLI installed and logged in (gh auth login) on the box running Hermes, there’s nothing further to configure — the skill picks it up automatically as the first-choice method.
Option B: Set a Token Directly
If gh isn’t installed or authenticated, generate a personal access token. The skill’s own documentation recommends, for a classic PAT:
repo— full repository access: read, write, push, PRsworkflow— trigger and manage GitHub Actionsread:org— only if you’re working with organization repos- Expiration: 90 days as a reasonable default, rather than a token that never expires
If you’d rather scope it tighter, GitHub’s newer fine-grained tokens work just as well — limit repository access to only what Hermes needs, with Contents (read/write), Pull requests (read/write), and Issues (read/write) as the equivalent permissions.
Store it without it ever touching your shell history:
read -s -p "GitHub token: " GITHUB_TOKEN
echo
hermes config set GITHUB_TOKEN "$GITHUB_TOKEN"
unset GITHUB_TOKENThis writes it to ~/.hermes/.env. Restart the gateway for it to take effect:
hermes gateway restartVerifying It Worked, Without Printing the Token
Confirm the line exists without echoing the value:
grep -q '^GITHUB_TOKEN=.' ~/.hermes/.env \
&& echo "GitHub token configured" \
|| echo "GitHub token missing"Then confirm it actually authenticates:
set -a
source ~/.hermes/.env
set +a
curl -fsS \
-H "Authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github+json" \
https://api.github.com/user |
python3 -c 'import json,sys; print("Authenticated as:", json.load(sys.stdin)["login"])'
unset GITHUB_TOKENIn practice, once this is wired up you don’t need to run these checks manually every time — you can just ask the agent directly (through whichever messaging channel you’ve connected) to run a read-only auth check. It’ll verify a token is present, call GitHub’s GET /user endpoint, and report back only the username and whether authentication succeeded — never the token itself.
Three Known Gotchas
hermes doctor Warns About a Missing Token Even With gh CLI Logged In
This is a documented false positive (issue #16115): the doctor check only looks for the GITHUB_TOKEN/GH_TOKEN environment variable, but the actual runtime correctly falls back to gh auth token when neither is set — the check just hasn’t caught up to that fallback logic. If you’re authenticated via gh and GitHub skills work fine in practice, the warning is cosmetic and safe to ignore. Setting GITHUB_TOKEN anyway will make the warning go away, at the cost of maintaining a token you didn’t strictly need.
The Sandboxed Terminal Can’t See GITHUB_TOKEN — By Design
A token can be sitting in ~/.hermes/.env, confirmed present, and still be invisible to a printenv run from inside the agent’s own terminal. This isn’t a bug: Hermes deliberately strips sensitive environment variables from the sandboxed processes behind its terminal and execute_code tools, specifically to prevent LLM-generated code from exfiltrating credentials. Setting a variable in .env only makes it available to Hermes itself — not automatically to commands Hermes runs on your behalf.
A variable passes through in one of two ways:
- Automatically, if a currently-loaded skill declares it in its
required_environment_variablesfrontmatter and it’s already set in Hermes’s own process environment. Loading (or reloading) the relevant skill can be enough to trigger this. - Explicitly, by adding it to
terminal.env_passthroughin~/.hermes/config.yaml:
terminal:
env_passthrough:
- GITHUB_TOKENThis is also the underlying cause of issue #1436, reported specifically against the Docker terminal backend — but the stripping behavior applies regardless of which terminal backend you’re using, not just Docker.
Never add Hermes’s own infrastructure secrets (Nous Portal’s provider tokens, gateway credentials) to env_passthrough — it’s meant for tool-specific tokens like this one, and Hermes’s Skills Guard scans skill content for suspicious environment-variable access before installation precisely because this mechanism is a real trust boundary.
git push Still Asks for a Password Even With the Token Passed Through
Getting the token into the terminal’s environment isn’t the whole story — git doesn’t automatically use a GITHUB_TOKEN environment variable for HTTPS authentication. It needs a credential helper configured. On Ubuntu, gh is a plain apt install, no separate repository needed:
sudo apt update
sudo apt install -y ghFrom there you have two ways to authenticate it, depending on whether you’re doing this by hand over SSH or scripting it for Hermes itself.
Interactive, from an SSH session — just run gh auth login and follow the prompts (GitHub.com, HTTPS, “Authenticate Git with your GitHub credentials? Yes”, “Login with a web browser”). On a headless VPS it can’t actually open a browser for you:
! Failed opening a web browser at https://github.com/login/device
exec: "xdg-open,x-www-browser,www-browser,wslview": executable file not found in $PATH
Please try entering the URL in your browser manuallyThat’s fine — it still printed a one-time code first. Open https://github.com/login/device on your laptop or phone, enter the code, and the CLI on the VPS completes authentication as soon as you do. It’ll confirm with ✓ Authentication complete. and ✓ Logged in as <username>, and print a reminder that credentials are saved to disk in plain text — the same tradeoff noted below.
Non-interactive, piping a token in (what the github-auth skill itself documents, and the right choice if Hermes needs to do this on its own rather than you doing it by hand):
echo "$GITHUB_TOKEN" | gh auth login --hostname github.com --git-protocol https --with-tokenEither way, finish by wiring gh in as git’s credential helper:
gh auth setup-gitFrom then on, a plain git push over HTTPS picks up credentials automatically. Confirm all of it worked:
gh auth status
git ls-remote origin HEADgh auth status also reports the token’s actual scopes — if you went through the interactive browser login, expect gist, read:org, repo, workflow (gh’s own OAuth app’s default set), which is close to but not identical to the classic-PAT scopes recommended earlier.
If git push still prompts for a username/password after all this, check git config --global credential.helper — it needs to actually point at gh (or store/cache) rather than being unset.
Security Notes
- Prefer exporting the token as an environment variable or letting
ghmanage it over embedding it directly in commands — keeps it out of shell history and process listings. - If you use
git config credential.helper store, be aware it saves credentials to~/.git-credentialsin plaintext — a deliberate simplicity/security tradeoff the skill’s own docs acknowledge. - Set an expiration on any token you create; don’t generate one that never expires.
- GitHub no longer accepts password authentication for git operations — a personal access token is the password now, wherever a git prompt asks for one.