You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
memtomem-server writes ~/.memtomem/.server.pid at startup to hold an
advisory fcntl.flock for the server-lifetime and to give the uninstall
command a liveness probe target. That single write is the last thing
keeping ~/.memtomem/ from being fully lazy — #399 Phase 3 (ea 00e948b)
moved the SQLite DB + scheduler startup to the first tool call, but Path("~/.memtomem").mkdir(...) in server/__init__.py:main still fires
on every MCP handshake (claude mcp list, Cursor/Windsurf probe, etc.),
even for a client that connects and never calls a tool.
Secondary concern: .server.pid is transient runtime state (auto-release
on process death), but it lives beside persistent data
(memtomem.db, config.json, memories/). Mixing the two means a rm -rf ~/.memtomem workflow also deletes runtime-state knowledge about
live writers, and tooling has to special-case .server.pid when walking
the state dir.
This was called out as out-of-scope in the #399 Phase 3 plan and
referenced in #384 / #387 as "relocate to $XDG_RUNTIME_DIR".
Proposal
Relocate the server pid / lock file from ~/.memtomem/.server.pid to:
Linux w/ systemd: $XDG_RUNTIME_DIR/memtomem/server.pid
(e.g. /run/user/1000/memtomem/server.pid). Kernel auto-cleans at
logout; no stale files after reboot.
macOS, Linux w/o $XDG_RUNTIME_DIR, BSD: {tempfile.gettempdir()}/memtomem-{uid}/server.pid.
On macOS this resolves to the per-user /var/folders/.../T/memtomem-{uid}/
(already user-owned); on Linux fallback it's /tmp/memtomem-{uid}/
created with mode 0700.
Windows: server is POSIX-only (fcntl), so not relevant for the
write side. Uninstall probe is a no-op there.
With this change, ~/.memtomem/ is created only by code paths that
actually need persistent storage — index, add, first tool call. A user
who only ever runs claude mcp list against a clean machine gets a
truly empty home, closing the last gap from #399.
Design
New helper memtomem._runtime_paths.runtime_dir() -> Path:
Check $XDG_RUNTIME_DIR; if set and is a dir, use {XDG}/memtomem.
Otherwise {tempfile.gettempdir()}/memtomem-{uid}.
mkdir(mode=0o700, exist_ok=True) on first access.
Server (server/__init__.py:main) writes runtime_dir() / "server.pid"
(drops the leading dot — dedicated runtime dir, no need to hide).
Uninstall (cli/uninstall_cmd.py:_check_server_liveness) probes the
new location; during the transition period also probes the legacy ~/.memtomem/.server.pid so a mixed-version upgrade (old server
running, new uninstall) still refuses correctly.
Uninstall cleanup removes the legacy file if present but does NOT
rmdir $XDG_RUNTIME_DIR/memtomem — the kernel handles it.
Problem
memtomem-serverwrites~/.memtomem/.server.pidat startup to hold anadvisory
fcntl.flockfor the server-lifetime and to give the uninstallcommand a liveness probe target. That single write is the last thing
keeping
~/.memtomem/from being fully lazy — #399 Phase 3 (ea00e948b)moved the SQLite DB + scheduler startup to the first tool call, but
Path("~/.memtomem").mkdir(...)inserver/__init__.py:mainstill fireson every MCP handshake (
claude mcp list, Cursor/Windsurf probe, etc.),even for a client that connects and never calls a tool.
Secondary concern:
.server.pidis transient runtime state (auto-releaseon process death), but it lives beside persistent data
(
memtomem.db,config.json,memories/). Mixing the two means arm -rf ~/.memtomemworkflow also deletes runtime-state knowledge aboutlive writers, and tooling has to special-case
.server.pidwhen walkingthe state dir.
This was called out as out-of-scope in the #399 Phase 3 plan and
referenced in #384 / #387 as "relocate to
$XDG_RUNTIME_DIR".Proposal
Relocate the server pid / lock file from
~/.memtomem/.server.pidto:$XDG_RUNTIME_DIR/memtomem/server.pid(e.g.
/run/user/1000/memtomem/server.pid). Kernel auto-cleans atlogout; no stale files after reboot.
$XDG_RUNTIME_DIR, BSD:{tempfile.gettempdir()}/memtomem-{uid}/server.pid.On macOS this resolves to the per-user
/var/folders/.../T/memtomem-{uid}/(already user-owned); on Linux fallback it's
/tmp/memtomem-{uid}/created with mode 0700.
fcntl), so not relevant for thewrite side. Uninstall probe is a no-op there.
With this change,
~/.memtomem/is created only by code paths thatactually need persistent storage — index, add, first tool call. A user
who only ever runs
claude mcp listagainst a clean machine gets atruly empty home, closing the last gap from #399.
Design
memtomem._runtime_paths.runtime_dir() -> Path:$XDG_RUNTIME_DIR; if set and is a dir, use{XDG}/memtomem.{tempfile.gettempdir()}/memtomem-{uid}.mkdir(mode=0o700, exist_ok=True)on first access.server/__init__.py:main) writesruntime_dir() / "server.pid"(drops the leading dot — dedicated runtime dir, no need to hide).
cli/uninstall_cmd.py:_check_server_liveness) probes thenew location; during the transition period also probes the legacy
~/.memtomem/.server.pidso a mixed-version upgrade (old serverrunning, new uninstall) still refuses correctly.
rmdir
$XDG_RUNTIME_DIR/memtomem— the kernel handles it.Non-goals
mm uninstallliveness check only sees MCP server pid — silently ignoresmm weband other DB writers #384 (liveness probe only sees MCP server, ignoresmm web/mm watchdog). That's a separate expansion — registerper-process lock files and scan the directory. Out of scope here; the
new runtime dir is the right place for those future lock files,
but adding them is its own PR.
.current_session. Session state is persistent(mm remembers the user's current session across reboots); it stays
in the state dir.
Backward compat
~/.memtomem/.server.pid.New uninstall probe checks both locations for one release cycle.
Related
mm uninstallliveness check only sees MCP server pid — silently ignoresmm weband other DB writers #384 — liveness probe only sees MCP server (this PR prepares theground; expansion is separate)
memtomem-serverleaves stale.server.pidon exit — risksmm uninstallliveness false-positive via PID recycling #387 — CLOSED, stale pid file after SIGTERM (addressed by flock +SIGTERM handler in
81bbdd5)