Summary
tools/environments/local.py:_make_run_env rewrites HOME to $HERMES_HOME/home/ for every shell subprocess when the per-profile home/ dir exists. This silently breaks any external CLI that resolves its credentials via $HOME/Library/Keychains/login.keychain-db — most notably claude CLI on macOS, which is the exact tool a Hermes kanban worker would shell out to under the recommended "Hermes coordinates, Claude Code implements" delegation pattern.
The symptom is loud and unambiguous from the user's side (claude auth status returns "Not logged in" inside the worker even though the user is authenticated in their interactive shell) but the root cause is buried three layers deep, and there are several plausible-but-wrong leads (audit sessions, start_new_session=True, launchd domain pollution) that consume real debugging time before you find it.
Environment
- Hermes Agent
v0.14.0 (2026.5.16)
- Claude Code
2.1.145 on macOS Darwin 25.2.0
- Python 3.11.15
- Profile setup: orchestrator (gpt-5.5 / openai-codex) dispatches kanban workers as the
builder profile, which then invokes claude -p per the claude-cli-kanban-worker skill pattern.
Repro
- Create or have a Hermes profile whose
$HERMES_HOME/home/ dir exists (hermes profile create <name> populates it; or it auto-creates the first time the bash tool runs).
- Authenticate Claude Code via
claude /login in your normal Terminal so the macOS Keychain entry is populated.
- Verify auth works from the user's shell:
claude auth status --text
# → Login method: Claude Max account
- Spawn a Hermes worker that invokes
claude auth status via the agent's bash tool (any kanban task pointing at a skill that runs claude auth status reproduces; or use hermes -p <profile> chat -q 'run: claude auth status --text').
- Worker reports:
Not logged in. Run claude auth login to authenticate.
"loggedIn": false, "authMethod": "none", "apiProvider": "firstParty"
Root cause
tools/environments/local.py lines 311–317:
from hermes_constants import get_subprocess_home
_profile_home = get_subprocess_home()
if _profile_home:
run_env["HOME"] = _profile_home
get_subprocess_home() returns $HERMES_HOME/home/ whenever that dir exists. This isolates git/ssh/gh/npm configs per profile — good and intentional. But macOS Claude Code resolves the user's login keychain via $HOME/Library/Keychains/login.keychain-db, and the rewritten HOME has no Library/Keychains/ symlink or directory under it, so the keychain lookup fails and claude falls back to apiProvider: "firstParty" with no credentials.
Bisection that landed on this:
- ✗ Audit session — Terminal-launched gateway has the right audit session (verified via
audit_session_self()), but workers still fail.
- ✗
start_new_session=True / os.setsid — reproduces fine in isolation with the same flags from a Terminal-spawned Python; not the gate.
- ✗ Launchd
gui/<uid> domain env pollution — launchctl kickstart -k produced a clean daemon env, no change.
- ✓ HOME override —
HOME=/tmp/nope claude auth status --text deterministically reproduces "Not logged in"; restoring HOME or symlinking ~/Library/Keychains into $HERMES_HOME/home/Library/ fixes it.
Suggested fix
Two reasonable options, increasing order of effort:
-
Whitelist Library/Keychains in the HOME isolation. Auto-symlink $REAL_HOME/Library/Keychains into $HERMES_HOME/home/Library/Keychains whenever get_subprocess_home() is active. This preserves all current isolation guarantees and is the minimum needed for any macOS CLI that depends on the login keychain (claude, gh, anything using security framework).
-
Document the requirement in the profile-init docs and add a hermes doctor check that flags missing home/Library/Keychains symlinks when a profile is set up to use claude CLI (e.g., detects the claude-cli-kanban-worker skill).
Option 1 is what I'd recommend — the breakage isn't user error, it's a Hermes-imposed environmental constraint that quietly defeats the most-recommended delegation pattern.
Workaround for users hitting this today
mkdir -p ~/.hermes/profiles/<profile>/home/Library
ln -sfn ~/Library/Keychains ~/.hermes/profiles/<profile>/home/Library/Keychains
Verify:
HOME=~/.hermes/profiles/<profile>/home claude auth status --text
# → Login method: Claude Max account
Optional (for projects/sessions/trust-list sharing with the user's interactive claude):
ln -sfn ~/.claude.json ~/.hermes/profiles/<profile>/home/.claude.json
ln -sfn ~/.claude ~/.hermes/profiles/<profile>/home/.claude
Do not delete the profile's home/ dir to "fix" this — it disables HOME isolation entirely and leaks git/npm/ssh state into your real ~/.
Why this matters beyond claude
Anything on macOS that resolves credentials via $HOME/Library/Keychains/ will silently fail from inside a Hermes worker the same way: gh auth status, aws sso login (writes there), op (1Password CLI), security find-generic-password, etc. Claude is the most user-visible case because the recommended "Claude Code as implementer" delegation pattern routes through it, but it's a general issue.
Summary
tools/environments/local.py:_make_run_envrewritesHOMEto$HERMES_HOME/home/for every shell subprocess when the per-profilehome/dir exists. This silently breaks any external CLI that resolves its credentials via$HOME/Library/Keychains/login.keychain-db— most notablyclaudeCLI on macOS, which is the exact tool a Hermes kanban worker would shell out to under the recommended "Hermes coordinates, Claude Code implements" delegation pattern.The symptom is loud and unambiguous from the user's side (
claude auth statusreturns "Not logged in" inside the worker even though the user is authenticated in their interactive shell) but the root cause is buried three layers deep, and there are several plausible-but-wrong leads (audit sessions,start_new_session=True, launchd domain pollution) that consume real debugging time before you find it.Environment
v0.14.0(2026.5.16)2.1.145on macOS Darwin 25.2.0builderprofile, which then invokesclaude -pper theclaude-cli-kanban-workerskill pattern.Repro
$HERMES_HOME/home/dir exists (hermes profile create <name>populates it; or it auto-creates the first time the bash tool runs).claude /loginin your normal Terminal so the macOS Keychain entry is populated.claude auth status --text # → Login method: Claude Max accountclaude auth statusvia the agent's bash tool (any kanban task pointing at a skill that runsclaude auth statusreproduces; or usehermes -p <profile> chat -q 'run: claude auth status --text').Root cause
tools/environments/local.pylines 311–317:get_subprocess_home()returns$HERMES_HOME/home/whenever that dir exists. This isolates git/ssh/gh/npm configs per profile — good and intentional. But macOS Claude Code resolves the user's login keychain via$HOME/Library/Keychains/login.keychain-db, and the rewritten HOME has noLibrary/Keychains/symlink or directory under it, so the keychain lookup fails and claude falls back toapiProvider: "firstParty"with no credentials.Bisection that landed on this:
audit_session_self()), but workers still fail.start_new_session=True/os.setsid— reproduces fine in isolation with the same flags from a Terminal-spawned Python; not the gate.gui/<uid>domain env pollution —launchctl kickstart -kproduced a clean daemon env, no change.HOME=/tmp/nope claude auth status --textdeterministically reproduces "Not logged in"; restoring HOME or symlinking~/Library/Keychainsinto$HERMES_HOME/home/Library/fixes it.Suggested fix
Two reasonable options, increasing order of effort:
Whitelist
Library/Keychainsin the HOME isolation. Auto-symlink$REAL_HOME/Library/Keychainsinto$HERMES_HOME/home/Library/Keychainswheneverget_subprocess_home()is active. This preserves all current isolation guarantees and is the minimum needed for any macOS CLI that depends on the login keychain (claude, gh, anything usingsecurityframework).Document the requirement in the profile-init docs and add a
hermes doctorcheck that flags missinghome/Library/Keychainssymlinks when a profile is set up to useclaudeCLI (e.g., detects theclaude-cli-kanban-workerskill).Option 1 is what I'd recommend — the breakage isn't user error, it's a Hermes-imposed environmental constraint that quietly defeats the most-recommended delegation pattern.
Workaround for users hitting this today
Verify:
Optional (for projects/sessions/trust-list sharing with the user's interactive claude):
Do not delete the profile's
home/dir to "fix" this — it disables HOME isolation entirely and leaks git/npm/ssh state into your real~/.Why this matters beyond claude
Anything on macOS that resolves credentials via
$HOME/Library/Keychains/will silently fail from inside a Hermes worker the same way:gh auth status,aws sso login(writes there),op(1Password CLI),security find-generic-password, etc. Claude is the most user-visible case because the recommended "Claude Code as implementer" delegation pattern routes through it, but it's a general issue.