Skip to content

fix(gateway): fix and verify launchd startup with external homes - #78150

Open
izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/launchd-external-home-78129
Open

fix(gateway): fix and verify launchd startup with external homes#78150
izumi0uu wants to merge 2 commits into
NousResearch:mainfrom
izumi0uu:fix/launchd-external-home-78129

Conversation

@izumi0uu

@izumi0uu izumi0uu commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

What does this PR do?

Fixes both launchd failure modes reported in #78129:

  1. launchd-owned stdout/stderr now live under the real macOS user's boot-volume log directory:

    ~/Library/Logs/<launchd-label>/gateway.stdout.log
    ~/Library/Logs/<launchd-label>/gateway.stderr.log
    

    This prevents launchd's pre-exec redirect open from failing with EX_CONFIG 78 when HERMES_HOME is on a non-boot volume. Hermes' application-managed logs under HERMES_HOME/logs are unchanged.

  2. hermes gateway install and hermes gateway start no longer report success merely because bootstrap or kickstart returned zero. They wait up to 60 seconds for launchd to expose a PID and for that same PID's Hermes runtime state to become running.

This builds on #78141. Its deb3c4eaa commit is retained as the first commit so RerankerGuo's authorship is preserved; the follow-up commit adds readiness verification and tightens profile/user-home handling.

Related Issue

Fixes #78129

Builds on #78141

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Tests (adding or improving test coverage)

Why this is the right fix

  • StandardOutPath and StandardErrorPath are launchd infrastructure, so they use the platform-standard user log location instead of following potentially external Hermes state.
  • The directory is derived from _launchd_user_home(), not the possibly profile-overridden HOME, and remains isolated by the existing profile-scoped launchd label.
  • Plist generation stays side-effect free. Service install/start/refresh paths create the directory immediately before launchd may need it.
  • Readiness requires agreement between launchd's current PID and Hermes' runtime record. A stale gateway_state.json from an old PID cannot produce a false success.
  • A startup_failed state exits immediately; a timeout exits non-zero and prints both launchctl print and the launchd stderr path.
  • launchd_restart() is intentionally unchanged because restart readiness is already covered by fix(gateway): wait for launchd restart readiness in-band (#56524) #56908.

Changes Made

  • hermes_cli/gateway.py
    • Generate profile-scoped launchd stdio paths under the real user's Library/Logs.
    • Create the stdio directory on launchd install/start/refresh paths.
    • Poll launchctl list <label> and require matching Hermes runtime readiness.
    • Return a non-zero exit with actionable diagnostics when startup never becomes ready.
  • tests/hermes_cli/test_gateway_service.py
    • Cover external HERMES_HOME plist generation.
    • Cover successful start readiness and matching PID checks.
    • Cover the no-PID false-success regression.
    • Cover first-install directory creation and readiness.

How to Test

  1. Configure HERMES_HOME on a non-boot volume.
  2. Run hermes gateway install or hermes gateway start.
  3. Confirm the generated plist points stdio at ~/Library/Logs/<label>/, while Hermes application logs remain under HERMES_HOME/logs.
  4. Confirm success is printed only after launchd's PID has a matching gateway_state=running runtime record.
  5. For a pre-exec failure, confirm the command exits non-zero and prints the launchctl print command plus gateway.stderr.log path.

Validation

Parent-commit reproduction tests:

  • External-home plist test failed because stdio still pointed into HERMES_HOME/logs.
  • Start did not probe the launchd PID/runtime state and printed success with no PID.
  • Start returned success when launchd never spawned a PID.
  • Install did not create the new stdio directory or wait for runtime readiness.

Post-fix checks on macOS 26.5.2:

.venv/bin/pytest -q -p no:cacheprovider tests/hermes_cli/test_gateway_service.py
74 passed

pytest tests/hermes_cli/test_gateway.py tests/hermes_cli/test_gateway_restart_loop.py tests/gateway/test_status.py -k 'launchd or launchctl'
24 passed, 124 deselected

.venv/bin/ruff check --no-cache hermes_cli/gateway.py tests/hermes_cli/test_gateway_service.py
All checks passed!

git diff upstream/main...HEAD --check
passed

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs and built on fix(gateway): keep launchd stdio logs on boot volume (#78129) #78141 rather than discarding its contribution
  • My PR contains only changes related to this fix
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes
  • I've tested on my platform: macOS 26.5.2 (targeted command-path tests)

Documentation & Housekeeping

  • Documentation update: N/A; Hermes application log locations are unchanged
  • cli-config.yaml.example update: N/A; no config keys changed
  • CONTRIBUTING.md / AGENTS.md update: N/A; no architecture or workflow changed
  • Cross-platform impact considered: changes are isolated to launchd/macOS code paths
  • Tool descriptions/schemas update: N/A

Remaining Risk

A live launchd E2E run with HERMES_HOME on a physically separate volume was not performed locally. The path failure is covered by plist regression tests and the issue's controlled reproduction; launchd/runtime convergence is covered with command-path tests.

RerankerGuo and others added 2 commits August 4, 2026 11:06
)

Write launchd stdout and stderr under the user's Library/Logs directory instead of HERMES_HOME, so non-boot homes do not fail before process launch. Add plist regression coverage.
Build on NousResearch#78141 by preserving the real macOS user-home log path across profiles, creating it only on service-management paths, and requiring launchd PID plus matching Hermes runtime readiness before reporting install/start success.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades P2 Medium — degraded but workaround exists labels Aug 4, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

macOS: launchd cannot open StandardOutPath on a non-boot HERMES_HOME — silent EX_CONFIG 78 (root cause for #5589)

3 participants