Three independent observations surfaced while smoke-testing v3.3.3 against real Claude Code transcripts. None block the 3.3.3 cut; filing for 3.3.4 triage.
1. _wing_from_transcript_path regex is macOS-centric
File: mempalace/hooks_cli.py:490-505
The regex only matches -Projects-<project> in the transcript path:
match = re.search(r"-Projects-([^/]+?)(?:/|$)", normalized)
Claude Code encodes the full source directory into the project folder name. Users whose code lives outside ~/Projects/ — e.g. ~/dev/, ~/src/, ~/code/, or any Linux convention — get transcript paths like ~/.claude/projects/-home-user-dev-MyProject-myproject/session.jsonl with no -Projects- segment, so they fall through to the wing_sessions fallback and lose the per-project diary scoping that #659 was meant to deliver.
Repro: Stop-hook invocation with transcript_path=~/.claude/projects/-home-<user>-dev-<Parent>-<project>/*.jsonl → diary checkpoint lands in wing_sessions instead of wing_<project>.
Suggested fix: broaden the heuristic to also match the last path segment of the encoded project folder (after the final -), not just the -Projects-<x> slice.
2. mempalace_diary_read doesn't normalize empty-string wing
File: mempalace/mcp_server.py — tool_diary_read handler
#1097 fixed mempalace_search to treat wing="" / room="" as "no filter" (LLM agents frequently default optional string parameters to ""). The same fix isn't applied to mempalace_diary_read — passing wing="" returns {"entries": [], "message": "No diary entries yet."} even when entries exist under named wings.
Repro:
diary_write(agent_name="x", entry="foo", wing="mempalace-dev") # lands in mempalace-dev
diary_read(agent_name="x", wing="mempalace-dev") # finds it
diary_read(agent_name="x", wing="") # returns empty, should return all
Suggested fix: apply the same empty-string → None normalization from #1097 to diary_read (and audit other tools with optional wing/room kwargs).
3. Stop-hook auto-mine subprocess ignores MEMPALACE_PALACE_PATH env
Observed: When the Stop hook kicks off an auto-mine, the mined drawers land at the default ~/.mempalace/palace regardless of a MEMPALACE_PALACE_PATH override set in the parent env.
Repro: Set MEMPALACE_PALACE_PATH=/tmp/alt-palace in the calling environment, fire the Stop hook (mempalace hook run --hook stop --harness claude-code with a real transcript). The hook's own diary checkpoint respects the env, but the mined drawers from the auto-ingest land at the default path.
Impact: Low for single-palace users (the common case). Can cause drawers to silently disappear into the wrong palace for anyone using multiple palaces or testing with a scratch palace.
Suggested fix: audit the subprocess-launch sites in hooks_cli.py and ensure MEMPALACE_PALACE_PATH / MEMPAL_PALACE_PATH are propagated explicitly (not just inherited).
All three found on develop @ 9947ad0.
Three independent observations surfaced while smoke-testing v3.3.3 against real Claude Code transcripts. None block the 3.3.3 cut; filing for 3.3.4 triage.
1.
_wing_from_transcript_pathregex is macOS-centricFile:
mempalace/hooks_cli.py:490-505The regex only matches
-Projects-<project>in the transcript path:Claude Code encodes the full source directory into the project folder name. Users whose code lives outside
~/Projects/— e.g.~/dev/,~/src/,~/code/, or any Linux convention — get transcript paths like~/.claude/projects/-home-user-dev-MyProject-myproject/session.jsonlwith no-Projects-segment, so they fall through to thewing_sessionsfallback and lose the per-project diary scoping that #659 was meant to deliver.Repro: Stop-hook invocation with
transcript_path=~/.claude/projects/-home-<user>-dev-<Parent>-<project>/*.jsonl→ diary checkpoint lands inwing_sessionsinstead ofwing_<project>.Suggested fix: broaden the heuristic to also match the last path segment of the encoded project folder (after the final
-), not just the-Projects-<x>slice.2.
mempalace_diary_readdoesn't normalize empty-stringwingFile:
mempalace/mcp_server.py—tool_diary_readhandler#1097fixedmempalace_searchto treatwing=""/room=""as "no filter" (LLM agents frequently default optional string parameters to""). The same fix isn't applied tomempalace_diary_read— passingwing=""returns{"entries": [], "message": "No diary entries yet."}even when entries exist under named wings.Repro:
Suggested fix: apply the same empty-string →
Nonenormalization from #1097 todiary_read(and audit other tools with optional wing/room kwargs).3. Stop-hook auto-mine subprocess ignores
MEMPALACE_PALACE_PATHenvObserved: When the Stop hook kicks off an auto-mine, the mined drawers land at the default
~/.mempalace/palaceregardless of aMEMPALACE_PALACE_PATHoverride set in the parent env.Repro: Set
MEMPALACE_PALACE_PATH=/tmp/alt-palacein the calling environment, fire the Stop hook (mempalace hook run --hook stop --harness claude-codewith a real transcript). The hook's own diary checkpoint respects the env, but the mined drawers from the auto-ingest land at the default path.Impact: Low for single-palace users (the common case). Can cause drawers to silently disappear into the wrong palace for anyone using multiple palaces or testing with a scratch palace.
Suggested fix: audit the subprocess-launch sites in
hooks_cli.pyand ensureMEMPALACE_PALACE_PATH/MEMPAL_PALACE_PATHare propagated explicitly (not just inherited).All three found on
develop@ 9947ad0.