Skip to content

settings.json accumulates duplicate memtrace hooks on every upgrade (old-version entries become dangling) #26

@Regis-RCR

Description

@Regis-RCR

TL;DR: on each upgrade, the installer re-injects the memtrace UserPromptSubmit and PostToolUse hooks into ~/.claude/settings.json at a version-pinned package-store path without removing the previous version's entry. They accumulate (three copies each after two upgrades, at three different paths). Once an old version's store directory is pruned, that entry becomes a dangling hook whose command path no longer exists, so it fails on every matching event. The v0.6.30 transparent-install work (#25) fixed the install footprint and the uninstall, but not this dedup-on-inject axis.

This surfaced while comparing my ~/.claude/settings.json before and after upgrades on machines I use regularly, across three releases, not a synthetic case.

Environment

  • memtrace 0.6.30 (the residual was also produced by 0.6.20)
  • Claude Code 2.1.175
  • macOS, Apple Silicon

What I observed (real config)

After upgrading across 0.6.18, 0.6.20, 0.6.30, ~/.claude/settings.json carried three copies each of the two memtrace hooks:

  • UserPromptSubmit: userprompt-claude.sh at the 0.6.20 store path, the 0.6.30 store path, and the npm-global path.
  • PostToolUse: posttool-mcp-telemetry.sh at those same three paths.

The 0.6.20 store path no longer exists on disk (pruned), so that entry is a dangling hook and errors on every UserPromptSubmit / PostToolUse.

Repro

  1. Note the memtrace hook entries in ~/.claude/settings.json.
  2. Upgrade memtrace (npm global, or memtrace install).
  3. Diff ~/.claude/settings.json: the memtrace hooks are appended again at the new version path; the previous entry is not removed.
  4. Remove or let the old version's store directory be pruned; the stale hook's command path is now missing.

Impact

Suggested fix

  • Dedup on inject: match an existing memtrace hook by a stable identity (script basename, or a managed marker comment) and replace it in place rather than append.
  • Or use a version-stable command path (the memtrace CLI shim) instead of a version-pinned store path, so re-injection is idempotent and never dangles.

Separately, and for the record: a user-level ~/.claude/settings.local.json is not read by Claude Code (only the project-level .claude/settings.local.json is), so keeping the user-global hooks in ~/.claude/settings.json, as the installer does, is the correct surface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions