Skip to content

fix(install): preserve pip entry point when re-running on symlinked install#21513

Closed
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/21454-install-symlink-stomp
Closed

fix(install): preserve pip entry point when re-running on symlinked install#21513
Tranquil-Flow wants to merge 1 commit into
NousResearch:mainfrom
Tranquil-Flow:fix/21454-install-symlink-stomp

Conversation

@Tranquil-Flow

Copy link
Copy Markdown
Contributor

What does this PR do?

Re-running install.sh on a system installed with an older version of the script destroys the pip-generated venv/bin/hermes entry point and replaces it with a self-recursing bash shim, so hermes hangs on every invocation.

The cause is that setup_path() writes the shim with a cat > heredoc:

cat > "$command_link_dir/hermes" <<EOF
#!/usr/bin/env bash
unset PYTHONPATH
unset PYTHONHOME
exec "$HERMES_BIN" "\$@"
EOF

On a prior install, ~/.local/bin/hermes is a symlink to ~/.hermes/hermes-agent/venv/bin/hermes. The redirect follows the symlink and overwrites the pip entry point with the shim body. $HERMES_BIN then resolves to the same path — exec calls itself.

This PR adds a 1-line rm -f before the heredoc so the shim is created as a regular file in $command_link_dir, leaving the venv entry point intact. The fix is the smallest change that captures the diagnosis — no restructuring of setup_path().

Related Issue

Fixes #21454

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ✨ New feature (non-breaking change that adds functionality)
  • 🔒 Security fix
  • 📝 Documentation update
  • ✅ Tests (adding or improving test coverage)
  • ♻️ Refactor (no behavior change)
  • 🎯 New skill (bundled or hub)

Changes Made

  • scripts/install.sh — added rm -f "$command_link_dir/hermes" before the cat > heredoc in setup_path() so the shim is a regular file, not written through a legacy symlink.
  • tests/test_install_sh_symlink_stomp.py — new file. Two tests: a static guard that the rm precedes the heredoc, and a behavioural reproducer that pre-creates the symlinked prior-install layout, drives the real shim-write block extracted from install.sh, and asserts venv/bin/hermes survives.

How to Test

  1. python -m pytest tests/test_install_sh_symlink_stomp.py tests/test_install_sh_pythonpath_sanitization.py -v → 4 passed.
  2. To confirm the test catches the regression: git stash the scripts/install.sh change, re-run pytest. The behavioural test fails with the pip script body replaced by the self-execing shim. git stash pop restores it.
  3. bash -n scripts/install.sh → clean (no syntax regressions).

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(scope):, feat(scope):, etc.)
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature (no unrelated commits)
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes (required for bug fixes, strongly encouraged for features)
  • I've tested on my platform: macOS 15 (Darwin 24.6.0)

Documentation & Housekeeping

  • I've updated relevant documentation (README, docs/, docstrings) — or N/A
  • I've updated cli-config.yaml.example if I added/changed config keys — or N/A
  • I've updated CONTRIBUTING.md or AGENTS.md if I changed architecture or workflows — or N/A
  • I've considered cross-platform impact (Windows, macOS) per the compatibility guide — or N/A
  • I've updated tool descriptions/schemas if I changed tool behavior — or N/A

Screenshots / Logs

$ python -m pytest tests/test_install_sh_symlink_stomp.py tests/test_install_sh_pythonpath_sanitization.py -q
....
4 passed in 0.78s

Test reproducing the bug on origin/main (without the fix):

FAILED tests/test_install_sh_symlink_stomp.py::test_re_running_setup_path_block_preserves_pip_entry_point
AssertionError: pip entry point body was overwritten by the shim
  expected: from hermes_cli.main import main
  got:      exec "<…>/venv/bin/hermes" "$@"

Notes

  • Only cat > site in install.sh whose target could realistically pre-exist as a symlink to a user-writable path. The other heredoc (cat > "$HERMES_HOME/SOUL.md") is gated by a non-existence check and isn't affected.
  • Adopts the reporter-provided fix verbatim.

…nstall

setup_path() writes the user-facing hermes shim with `cat >`, which
follows existing symlinks. Older installs created
`$command_link_dir/hermes` as a symlink to `$HERMES_BIN`
(`venv/bin/hermes`), so re-running install.sh stomped the pip entry
point with a bash shim that exec'd itself in an infinite loop.

`rm -f` the link target before writing so the shim lands at
`$command_link_dir/hermes` and the venv entry point is left intact.

Adds a regression test that reproduces the symlink-stomp end-to-end
(creates the symlink, drives the real shim-write block from setup_path,
asserts the venv pip script body survives and the shim is now a regular
file). Both new assertions fail on origin/main and pass with the fix.

Closes NousResearch#21454.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cli CLI entry point, hermes_cli/, setup wizard P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Re-running install.sh on prior install creates infinite-loop shim (CLI hangs)

2 participants