[FEATURE] Anchor user-scope hook commands to $HOME on POSIX targets so ~/.claude/settings.json stays portable across machines
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 3.9k
- Forks
- 365
- Avg merge
- 1d 17h
- Merged PRs (30d)
- 132
Description
Summary
User-scope installs (apm install -g) write hook command entries into ~/.claude/settings.json with the home directory expanded to a literal absolute path, e.g.
"command": "node \"/Users/alice/.claude/hooks/context-mode/hooks/pretooluse.mjs\""
~/.claude/settings.json is a file many people keep in a dotfiles repo shared across machines. A literal home prefix makes the tracked file differ per host (/Users/alice vs /home/alice), so every apm install -g on a second machine produces a diff of the same hooks with a different prefix.
The absolute rewrite itself is right (#1310 / #1354: hook commands resolve against the cwd, not the settings file), and #1394 correctly limited it to user scope. The ask is only about how user-scope paths are anchored on POSIX targets.
Proposal
For user-scope deploys on POSIX hosts, anchor the rewritten script path to $HOME instead of the expanded home directory:
"command": "node \"$HOME/.claude/hooks/context-mode/hooks/pretooluse.mjs\""
Claude Code and Codex run hook commands through a shell, so $HOME expands at invocation time regardless of cwd, which keeps the #1310 fix intact while making the merged file host-independent. Windows targets would keep the current absolute form (%USERPROFILE% semantics differ and #2408 shows cwd handling is already special there).
The same applies to the apm-hooks.json ledger, so adoption on the next install matches the $HOME form.
Evidence
Tested on apm 0.29.0 (656f3d6) with a scratch HOME:
- Rewriting the merged
settings.jsonentries to$HOME/...by hand and reinstalling re-adds the absolute entries next to them (14 → 28 hooks). - Rewriting both
settings.jsonandapm-hooks.jsonto$HOME/...and reinstalling: apm adopts them (no duplicates) but rewrites them back to absolute.apm uninstall -g <pkg>still removes the right entries in that state.
So the change is contained in _rewrite_command_for_target / _deploy_root_for_hook_rewrite in src/apm_cli/integration/hook_integrator.py: when user_scope is set and the target is a POSIX shell-executed hook, emit "$HOME/" + relative_to(home) instead of (deploy_root / target_rel).resolve().
Environment
- apm 0.29.0 from commit
656f3d6e6dbade369b6fc8727a4eb7b164409b6d - macOS 15 (arm64) and Linux x86_64, targets
claudeandcodex, user scope
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/apm_cli/integration/hook_integrator.py, reading _rewrite_command_for_target and _deploy_root_for_hook_rewrite. Trace user-scope POSIX and Windows handling, then verify that both settings.json and the apm-hooks.json ledger use the portable $HOME form on POSIX while Windows retains its existing absolute behavior.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, shell
- Domain
- cli, tooling
- Issue type
- Feature
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100