Skip to content

memory.dashboard.backend.presence

memory.dashboard.backend.presence

Backend-owned "dashboard is live" presence sidecar.

The Sessions view shows a live card for every running memory MCP process by reading its active-session sidecar from .memory/active-sessions/. When no editor (Cursor/Claude) is open and you haven't started a dashboard chat, there is no such process — so the live area is empty.

Rather than spawn a full memory MCP server just to publish a heartbeat (which would load the embedding model and, via dead-sidecar finalization on startup, could trigger git commits/pushes), the dashboard backend writes its own single heartbeating sidecar. It does no git, loads no model, and is cleaned up two ways:

  • graceful shutdown deletes the file (see stop_presence);
  • a crash leaves it behind, but the /sessions reader drops any sidecar whose PID is dead and that has no recorded activity — which is exactly this card — so it never lingers as a stale "live" session.

The card uses a stable id, so relaunching the dashboard refreshes the same card instead of accumulating duplicates. Disable it with DASHBOARD_PRESENCE=0.

start_presence

start_presence() -> None

Begin publishing the live presence sidecar (no-op if disabled/running).

Source code in memory/dashboard/backend/presence.py
def start_presence() -> None:
    """Begin publishing the live presence sidecar (no-op if disabled/running)."""
    global _thread, _started_at
    if not _enabled():
        return
    if _thread is not None and _thread.is_alive():
        return
    _started_at = datetime.now(timezone.utc).isoformat()
    _stop.clear()
    _thread = threading.Thread(target=_loop, name="dashboard-presence", daemon=True)
    _thread.start()

stop_presence

stop_presence() -> None

Stop the heartbeat and remove the presence sidecar.

Source code in memory/dashboard/backend/presence.py
def stop_presence() -> None:
    """Stop the heartbeat and remove the presence sidecar."""
    _stop.set()
    thread = _thread
    if thread is not None and thread.is_alive():
        thread.join(timeout=2)
    try:
        _sidecar_path().unlink(missing_ok=True)
    except OSError:
        pass