Summary
palace_graph._TUNNEL_FILE is a module-level constant initialised from os.path.expanduser("~") + "/.mempalace/tunnels.json". It ignores MempalaceConfig.palace_path (and MEMPALACE_PALACE_PATH). Every other piece of palace state — drawers, KG, people map — honours palace_path, so when $HOME and the configured palace diverge, tunnels write to a different file from drawers.
Impact
Worst case is the agentic one. A subagent with an isolated $HOME (profile sandbox, container, multi-tenant worker) sets MEMPALACE_PALACE_PATH=/shared/palace so its drawers go to the shared palace. Its tunnel writes still go to ~/.mempalace/tunnels.json inside the isolated home — invisible to every other process touching the shared palace. The same isolated list_tunnels() reads back the worker's own write, so the worker self-confirms a tunnel that doesn't exist anywhere except its own bubble and reports completion to its orchestrator.
We hit this on a real task: Hephaestus subagent created a "tunnel" pointing at a phantom room, list_tunnels confirmed it from the bubble, and the completion report shipped to the parent. The tunnel never existed in the shared palace.
Reproduction
import os, tempfile
import mempalace.mcp_server as ms
shared = tempfile.mkdtemp()
os.environ["MEMPALACE_PALACE_PATH"] = shared
os.environ["HOME"] = tempfile.mkdtemp() # simulate profile isolation
ms.tool_add_drawer("wing_test", "room_a", "content a")
ms.tool_add_drawer("wing_test", "room_b", "content b")
ms.tool_create_tunnel("wing_test", "room_a", "wing_test", "room_b")
# The tunnel writes to $HOME/.mempalace/tunnels.json, not to the configured palace.
# Reading tunnels from a fresh process that doesn't share $HOME returns nothing.
Fix
PR #TBD. _TUNNEL_FILE becomes _get_tunnel_file() deriving the path from a new MempalaceConfig.tunnel_file property (sibling of palace_path). Default install unchanged. Legacy-file detection emits a one-line WARNING when the configured tunnel file is missing but the pre-fix path has one — no auto-migration.
Summary
palace_graph._TUNNEL_FILEis a module-level constant initialised fromos.path.expanduser("~") + "/.mempalace/tunnels.json". It ignoresMempalaceConfig.palace_path(andMEMPALACE_PALACE_PATH). Every other piece of palace state — drawers, KG, people map — honourspalace_path, so when$HOMEand the configured palace diverge, tunnels write to a different file from drawers.Impact
Worst case is the agentic one. A subagent with an isolated
$HOME(profile sandbox, container, multi-tenant worker) setsMEMPALACE_PALACE_PATH=/shared/palaceso its drawers go to the shared palace. Its tunnel writes still go to~/.mempalace/tunnels.jsoninside the isolated home — invisible to every other process touching the shared palace. The same isolatedlist_tunnels()reads back the worker's own write, so the worker self-confirms a tunnel that doesn't exist anywhere except its own bubble and reports completion to its orchestrator.We hit this on a real task: Hephaestus subagent created a "tunnel" pointing at a phantom room,
list_tunnelsconfirmed it from the bubble, and the completion report shipped to the parent. The tunnel never existed in the shared palace.Reproduction
Fix
PR #TBD.
_TUNNEL_FILEbecomes_get_tunnel_file()deriving the path from a newMempalaceConfig.tunnel_fileproperty (sibling ofpalace_path). Default install unchanged. Legacy-file detection emits a one-lineWARNINGwhen the configured tunnel file is missing but the pre-fix path has one — no auto-migration.