Skip to content

Claude Code plugin: Stop-hook summarizer re-triggers plugin hooks, scattering phantom session headers (and a stray watcher + junk collection) into ~/.memsearch #604

Description

@Jiri-Kudela

Environment

  • memsearch 0.4.7 (Claude Code plugin from zilliztech/memsearch marketplace); hook scripts verified byte-identical on 0.4.12 / current main
  • Claude Code on Windows 11 (Git Bash hooks), embedding.provider = onnx, Milvus server mode (milvus.uri = http://<host>:19530)

Symptoms

  1. ~/.memsearch/memory/*.md files accumulate that contain only empty ## Session HH:MM headers — never any ### turn summaries — even though all real work happens in per-project .memsearch/memory/ dirs.

  2. Some headers are duplicated within the same minute despite the dedup guard:

    ## Session 16:05
    ## Session 16:05
    
    ## Session 16:08
    
    ## Session 16:08
    
  3. A stray memsearch watch C:/Users/<user>/.memsearch/memory --collection ms_<user>_<hash> process runs alongside the legitimate project watcher, and a junk Milvus collection for the home directory gets created and indexed on the server.

  4. Occasional phantom empty ## Session headers also appear in the project memory file between real sessions.

Root cause (three interacting issues)

1. The summarizer child re-fires the plugin's own hooks.
hooks/stop.sh summarizes each turn by spawning claude -p (line ~143). That child is a full Claude Code session and runs the plugin's SessionStart hook again — nothing disables hooks/plugins for it. Every completed turn therefore spawns a headless session that appends a ## Session HH:MM header somewhere.

Reproduction: run stop.sh's exact child command from inside any project repo:

MEMSEARCH_NO_WATCH=1 CLAUDECODE= claude -p --strict-mcp-config --tools "" \
  --model haiku --no-session-persistence --no-chrome "Reply with the single word: ok"

→ a phantom ## Session HH:MM is appended to that project's memory file. Adding --settings '{"disableAllHooks": true}' to the same command → no header (verified).

2. The $HOME / CWD fallback in directory resolution.
hooks/common.sh (lines ~24–34) resolves the memory dir as: git root of the hook process's CWD → CLAUDE_PROJECT_DIR.. Headless children and desktop-app helper sessions often run with a CWD outside any repo and with CLAUDE_PROJECT_DIR unset, so they resolve to ~/.memsearch. session-start.sh then writes the header there and calls start_watch, which is where the stray home-dir watcher and the junk ms_<user>_<hash> Milvus collection come from.

3. The same-minute dedup guard is not atomic.
session-start.sh (lines ~113–115) does grep -qF "## Session $NOW" then appends. Two hook processes starting in the same minute both pass the grep before either writes — check-then-write race → duplicated headers.

Suggested fixes

  1. stop.sh: add --settings '{"disableAllHooks": true}' to the claude -p invocation so the summarizer cannot recursively trigger plugin hooks. One line; verified working locally.
  2. session-start.sh / common.sh: when no project resolves (no git root and no CLAUDE_PROJECT_DIR), skip the header write and start_watch entirely instead of falling back to $HOME/CWD. A header-only memory file with no possibility of summaries has no value, and the fallback silently creates a per-home watcher + collection.
  3. session-start.sh: make the header append atomic (e.g. flock on the memory file) or dedupe after writing.

Happy to open a PR for (1) if useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    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