docs(docker): overriding entrypoint: drops the zombie reaper — document init: true; trim the PID-1 warning

Follow-up to the cherry-picked #111584 (@chelsealong):

- website/docs/user-guide/docker.md: new warning block next to the existing
  "do not override the entrypoint" note explaining WHY (with `/init` gone the
  hermes process is PID 1 and nothing reaps orphaned browser/MCP/shell
  children), the Compose `init: true` / `docker run --init` remedy, and that
  supervision is still lost on that path; plus a Troubleshooting entry for
  `<defunct>` processes under PID 1.
- hermes_cli/main.py: `_warn_if_unsupervised_pid1` keeps the `os.getpid() == 1`
  check and drops the `platform.system()` gate and the blanket
  `try/except Exception: pass` — a user process is never PID 1 on any host OS
  (PID 1 is init/launchd; Windows PIDs are multiples of 4), and nothing in the
  check can raise.
- tests trimmed to two invariants (warns at pid 1 / silent otherwise).

Not done, on purpose: a `prctl(PR_SET_CHILD_SUBREAPER)` + SIGCHLD reaper in
main-wrapper/hermes. As PID 1 hermes already receives the orphans; what is
missing is a `waitpid(-1)` loop, and a process-wide one races
`subprocess.Popen` for exit statuses. The maintainer decides whether that
runtime change is wanted; docs + the startup warning cover the reported
deployment.
This commit is contained in:
teknium1
2026-09-15 12:08:18 -07:00
committed by Teknium
parent 8d5cce4d94
commit a2837ec088
3 changed files with 47 additions and 53 deletions
@@ -1,33 +1,16 @@
"""Tests for the PID-1-with-no-init warning (NousResearch/hermes-agent#111577).
When a deployment overrides the image's ``entrypoint:`` to invoke hermes
directly, ``docker/entrypoint-dispatch.sh`` never runs and hermes itself
becomes PID 1 with no supervisor above it to reap orphaned children —
they accumulate as zombies without bound. ``_warn_if_unsupervised_pid1``
surfaces that trap at startup, mirroring the warning
``entrypoint-dispatch.sh`` already prints on its own non-PID-1 fallback path.
"""
"""The PID-1-with-no-init startup warning (#111577): a Compose ``entrypoint:`` override
makes hermes PID 1 with no reaper above it, so orphaned children pile up as zombies."""
from hermes_cli.main import _warn_if_unsupervised_pid1
class TestWarnIfUnsupervisedPid1:
def test_warns_when_pid_is_1_on_linux(self, monkeypatch, capsys):
monkeypatch.setattr("platform.system", lambda: "Linux")
_warn_if_unsupervised_pid1(pid=1)
captured = capsys.readouterr()
assert "PID 1" in captured.err
assert "zombies" in captured.err
def test_warns_when_process_is_pid_1(capsys):
_warn_if_unsupervised_pid1(pid=1)
err = capsys.readouterr().err
assert "PID 1" in err and "init: true" in err
def test_silent_when_not_pid_1(self, monkeypatch, capsys):
monkeypatch.setattr("platform.system", lambda: "Linux")
_warn_if_unsupervised_pid1(pid=4242)
captured = capsys.readouterr()
assert captured.err == ""
assert captured.out == ""
def test_silent_on_non_linux_even_as_pid_1(self, monkeypatch, capsys):
monkeypatch.setattr("platform.system", lambda: "Darwin")
_warn_if_unsupervised_pid1(pid=1)
captured = capsys.readouterr()
assert captured.err == ""
def test_silent_when_not_pid_1(capsys):
_warn_if_unsupervised_pid1(pid=4242)
captured = capsys.readouterr()
assert captured.err == "" and captured.out == ""