Skip to content

fix(hooks): real python-resolution for .sh hooks, with MEMPAL_PYTHON override#833

Open
igorls wants to merge 1 commit intodevelopfrom
fix/hooks-python-resolution
Open

fix(hooks): real python-resolution for .sh hooks, with MEMPAL_PYTHON override#833
igorls wants to merge 1 commit intodevelopfrom
fix/hooks-python-resolution

Conversation

@igorls
Copy link
Copy Markdown
Collaborator

@igorls igorls commented Apr 13, 2026

Summary

The legacy shell hooks (mempal_save_hook.sh, mempal_precompact_hook.sh) call python3 -m mempalace mine … directly. On macOS GUI launches of Claude Code, PATH comes from launchd (/usr/bin:/bin:/usr/sbin:/sbin), which usually does not contain the Python where the user installed mempalace. The hook then fails silently deep in the background log.

This PR adds real PATH-robust resolution + a user-facing override, and a regression-test suite exercising the resolution priority.

Supersedes the abandoned branch fix/hook-bugs — see "Why the original fix wasn't enough" below.

Changes

  1. MEMPAL_PYTHON override. Users whose GUI-launch PATH lacks the right interpreter can export MEMPAL_PYTHON=/path/to/venv/python and hooks pick it up first. Resolution order:

    • $MEMPAL_PYTHON if set and executable
    • $(command -v python3) on PATH
    • bare python3 as a last resort
  2. Import sanity check before auto-ingest. Before running -m mempalace mine, the hook runs -c 'import mempalace'. On failure it logs a clear warning with the fix instructions to ~/.mempalace/hook_state/hook.log and skips the ingest — preserving the Claude Code contract of returning 0.

  3. Applied consistently. The JSON parse and transcript-count calls use the same resolution, so MEMPAL_PYTHON consistently controls the whole script.

  4. README Known Limitations — documents the macOS GUI PATH behavior and the MEMPAL_PYTHON workaround.

  5. 5 regression tests in tests/test_hooks_shell.py:

    • MEMPAL_PYTHON override wins over PATH (proven via marker-emitting shim).
    • Non-executable MEMPAL_PYTHON falls back to PATH rather than crashing.
    • Unset MEMPAL_PYTHON resolves via PATH.
    • Both hooks exit 0 and log the warning when the resolved interpreter can't import mempalace.
    • Tests skip on Windows (POSIX-only bash scripts). Full suite 810/810 locally; new tests ~0.2s total.

Why the original fix wasn't enough

The abandoned fix/hook-bugs branch replaced python3 with \$(command -v python3) and claimed it fixed a "nohup strips PATH" production bug. Empirically verified: both resolve to the same binary via PATH lookup — the substitution is a no-op. And the hooks don't use nohup. The symptom the branch describes (hook silently not firing when the wrong Python is on PATH) is real, but that change didn't address it.

This PR addresses the real underlying failure mode — wrong Python on PATH — with an explicit user override and proactive import verification.

Compatibility

  • hooks_cli.py (the Python implementation invoked via mempalace hook run …) already uses sys.executable and is trivially correct. No changes there.
  • Users who are already happy with bare python3 (most Linux and CLI-launched setups) need to do nothing — the fallback chain is unchanged for them.
  • Users hitting the macOS GUI issue now have a documented, testable escape hatch.

Co-Authored-By: MSL 232237854+milla-jovovich@users.noreply.github.com

The legacy ``.sh`` hook scripts (``mempal_save_hook.sh``,
``mempal_precompact_hook.sh``) call ``python3 -m mempalace mine …``
directly. On macOS GUI launches of Claude Code — ``open -a``,
Spotlight, the dock — the harness inherits ``PATH`` from launchd
(``/usr/bin:/bin:/usr/sbin:/sbin``), which typically does not contain
the Python where ``mempalace`` was installed. The hook then silently
fails deep in the background log where users never look.

The original drive-by fix (branch ``fix/hook-bugs``) replaced
``python3`` with ``$(command -v python3)``. Verified empirically that
those two resolve to the same binary — the "fix" was a no-op, and the
"nohup strips PATH" rationale in the commit message doesn't apply
(the hooks don't use nohup).

This PR delivers the fix the original branch intended:

1. **MEMPAL_PYTHON override** — users whose GUI-launch PATH lacks the
   right interpreter can export ``MEMPAL_PYTHON=/path/to/venv/python``
   and the hooks pick it up first. Resolution order:
     $MEMPAL_PYTHON (if set and executable)
     → $(command -v python3)
     → bare ``python3``

2. **Import sanity check before auto-ingest** — before running
   ``-m mempalace mine``, the hook runs ``-c 'import mempalace'``. On
   failure it logs a clear warning (with the fix instructions) to
   ``~/.mempalace/hook_state/hook.log`` and skips the ingest,
   preserving the Claude Code contract of returning 0 rather than
   crashing the Stop flow.

3. **Applied to all hook python calls** — not just the ingest line.
   The JSON parse and transcript-count calls use the same resolution
   so that ``MEMPAL_PYTHON`` consistently controls interpretation for
   the whole script.

4. **README** — adds a "Known Limitations" entry documenting the
   macOS GUI PATH behaviour and the ``MEMPAL_PYTHON`` workaround.
   (The "session restart after install" note was already on develop.)

5. **Regression tests** in ``tests/test_hooks_shell.py``:
   * ``MEMPAL_PYTHON`` override wins over PATH (proved via a
     marker-emitting shim that proxies to the real interpreter).
   * Non-executable ``MEMPAL_PYTHON`` falls back to PATH rather than
     crashing on permission denied.
   * Unset ``MEMPAL_PYTHON`` resolves via PATH.
   * Both hooks exit 0 and log the warning when the resolved
     interpreter can't import mempalace — Claude Code never sees a
     non-zero exit from the auto-ingest branch.

   Tests are skipped on Windows (POSIX-only bash scripts). 810/810 on
   Linux; the 5 new tests take ~0.2s total.

``hooks_cli.py`` (the Python implementation invoked via
``mempalace hook run …``) already uses ``sys.executable`` and is
therefore trivially correct — no changes needed there.

Supersedes abandoned branch ``fix/hook-bugs``.

Co-Authored-By: MSL <232237854+milla-jovovich@users.noreply.github.com>
@igorls igorls added area/hooks Claude Code hook scripts (Stop, PreCompact, SessionStart) bug Something isn't working labels Apr 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/hooks Claude Code hook scripts (Stop, PreCompact, SessionStart) bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant