hermes - ✅(Solved) Fix macOS: per-profile HOME isolation in _make_run_env hides ~/Library/Keychains from worker subprocesses, breaks claude CLI auth [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
NousResearch/hermes-agent#29015Fetched 2026-05-20 04:00:37
View on GitHub
Comments
0
Participants
1
Timeline
7
Reactions
0
Participants
Timeline (top)
labeled ×4cross-referenced ×3

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.

Error Message

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.

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.

Fix Action

Fix / Workaround

  • 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.

Workaround for users hitting this today

PR fix notes

PR #29050: fix(local): expose macOS keychains in profile home

Description (problem / solution / changelog)

Summary

  • Preserve access to the user's macOS login keychains when subprocess HOME is redirected to an isolated Hermes profile home.
  • Symlink only Library/Keychains into $HERMES_HOME/home, leaving the rest of the profile home isolated.
  • Do not overwrite an existing profile Library/Keychains directory or symlink.

Fixes #29015.

Why

_make_run_env() and _sanitize_subprocess_env() intentionally rewrite HOME to $HERMES_HOME/home for profile isolation. On macOS, CLIs such as Claude Code resolve login credentials through $HOME/Library/Keychains; once HOME points at the isolated profile home, those tools report unauthenticated even though the user is logged in from their normal shell.

Validation

  • python3 -m pytest -o addopts='' tests/test_subprocess_home_isolation.py -q → 19 passed
  • python3 -m pytest -o addopts='' tests/tools/test_env_passthrough.py -q → 17 passed
  • python3 -m py_compile tools/environments/local.py tests/test_subprocess_home_isolation.py
  • git diff --check

Notes

I used -o addopts='' for the focused pytest runs because this local checkout does not have the pytest-timeout plugin installed, while the repository config includes timeout addopts.

Changed files

  • tests/test_subprocess_home_isolation.py (modified, +62/-0)
  • tools/environments/local.py (modified, +45/-0)

Code Example

claude auth status --text
   # → Login method: Claude Max account

---

Not logged in. Run claude auth login to authenticate.
   "loggedIn": false, "authMethod": "none", "apiProvider": "firstParty"

---

from hermes_constants import get_subprocess_home
_profile_home = get_subprocess_home()
if _profile_home:
    run_env["HOME"] = _profile_home

---

mkdir -p ~/.hermes/profiles/<profile>/home/Library
ln -sfn ~/Library/Keychains ~/.hermes/profiles/<profile>/home/Library/Keychains

---

HOME=~/.hermes/profiles/<profile>/home claude auth status --text
# → Login method: Claude Max account

---

ln -sfn ~/.claude.json ~/.hermes/profiles/<profile>/home/.claude.json
ln -sfn ~/.claude      ~/.hermes/profiles/<profile>/home/.claude
RAW_BUFFERClick to expand / collapse

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

  1. 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).
  2. Authenticate Claude Code via claude /login in your normal Terminal so the macOS Keychain entry is populated.
  3. Verify auth works from the user's shell:
    claude auth status --text
    # → Login method: Claude Max account
  4. 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').
  5. 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:

  1. 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).

  2. 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.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - ✅(Solved) Fix macOS: per-profile HOME isolation in _make_run_env hides ~/Library/Keychains from worker subprocesses, breaks claude CLI auth [1 pull requests, 1 participants]