Skip to content

fix: Docker backend fails when docker is not in PATH (macOS gateway) - #889

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-b0162f8d
Mar 11, 2026
Merged

fix: Docker backend fails when docker is not in PATH (macOS gateway)#889
teknium1 merged 1 commit into
mainfrom
hermes/hermes-b0162f8d

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

On macOS, Docker Desktop installs the CLI to /usr/local/bin/docker, but when Hermes runs as a gateway service (launchd) or in other non-login contexts, /usr/local/bin is often not in PATH. This causes the Docker backend requirements check to fail with:

ERROR tools.terminal_tool: Terminal requirements check failed: [Errno 2] No such file or directory: 'docker'

...even though docker works fine from the user's terminal.

Changes

  • tools/environments/docker.py: Add find_docker() helper that uses shutil.which() first, then probes common Docker Desktop install paths (/usr/local/bin, /opt/homebrew/bin, Docker.app bundle). Resolved path is cached and passed to mini-swe-agent via its executable parameter. Also used in _storage_opt_supported().
  • tools/terminal_tool.py: Use find_docker() in the Docker requirements check instead of bare subprocess.run(["docker", ...]).
  • tests/tools/test_docker_find.py: 4 tests (PATH lookup, fallback paths, not found, caching).

Reported by

lord asado on Discord — Docker backend with persistent mode on macOS, docker works in terminal but not from Hermes gateway.

Test Plan

2877 tests pass (4 new).

On macOS, Docker Desktop installs the CLI to /usr/local/bin/docker, but
when Hermes runs as a gateway service (launchd) or in other non-login
contexts, /usr/local/bin is often not in PATH. This causes the Docker
requirements check to fail with 'No such file or directory: docker' even
though docker works fine from the user's terminal.

Add find_docker() helper that uses shutil.which() first, then probes
common Docker Desktop install paths on macOS (/usr/local/bin,
/opt/homebrew/bin, Docker.app bundle). The resolved path is cached and
passed to mini-swe-agent via its 'executable' parameter.

- tools/environments/docker.py: add find_docker(), use it in
  _storage_opt_supported() and pass to _Docker(executable=...)
- tools/terminal_tool.py: use find_docker() in requirements check
- tests/tools/test_docker_find.py: 4 tests (PATH, fallback, not found, cache)

2877 tests pass.
@teknium1
teknium1 merged commit b76cae9 into main Mar 11, 2026
1 check passed
angelburgosrosado pushed a commit to angelburgosrosado/hermes-agent that referenced this pull request Apr 27, 2026
…0162f8d

fix: Docker backend fails when docker is not in PATH (macOS gateway)
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
…0162f8d

fix: Docker backend fails when docker is not in PATH (macOS gateway)
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
…0162f8d

fix: Docker backend fails when docker is not in PATH (macOS gateway)
SSC-ENG added a commit to SSC-Engineering/hermes-agent that referenced this pull request Aug 7, 2026
…only (t_edd7abd5) (#29)

check_respawn_guard() step 4 previously froze a task's respawn for
_RESPAWN_GUARD_PR_WINDOW seconds on the mere PRESENCE of any GitHub PR
URL in a recent comment, regardless of whether that PR was still open.
Observed live: t_771d2af9 (/overwatch dashboard work) was guarded
'active_pr' on three consecutive dispatch ticks even though every
overwatch PR (NousResearch#888/NousResearch#889/NousResearch#890/NousResearch#895/NousResearch#898) was already MERGED — the URLs
were merely cited as context in orchestrator comments. This converted
"someone mentioned a PR link" into an involuntary dispatch freeze that
got worse the more productive a lane was.

Fix: resolve each cited PR's live state via `gh api
repos/<owner>/<repo>/pulls/<n> --jq .state` (reusing existing gh
auth), cached in-process for 5 minutes. state=open holds the guard;
state=closed (covers both closed and merged) clears it immediately.
Unresolvable state (gh missing/unauthenticated/network error/malformed
response) fails CLOSED exactly as the old text-only guard did -- this
makes the guard smarter about clearing, never more permissive about
holding when nothing can be verified. Citation identity (worker vs.
orchestrator vs. reviewer) is irrelevant; only live PR state decides.

Layers on top of the fork's existing 1h window + code-task scoping
(HAA 2026-07-29 option B) without reverting either.

Tests: merged/closed PR URL does not guard; open PR URL does guard;
PR URL cited by a non-worker author does not guard once merged;
unresolvable state fails closed; gh api output parsing
(open/closed/unparseable); in-process cache TTL behavior; full
existing respawn-guard suite (comment-ordering, requeue-bypass,
code-task scoping) re-verified green with the new state check patched
to a fixed value. 262 tests passed via scripts/run_tests.sh
(per-file isolated runner matching CI). ruff clean.

Same defect class as the dependency-block cooldown defect (t_360d58da):
a respawn guard recomputing a hold from stale/derived signals instead
of the live, authoritative state of the thing it's guarding against.

Co-authored-by: SSC-ENG <225143396+SSC-ENG@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant