Skip to content

emrg: the GUI never asks the daemon where a session lives, so an unplaced id opens at the home directory #2484

Closed

Description

@argszero

What is observed

The GUI works out a session's project directory itself, reading ~/.emrg/sessions_index.json from disk (emrg/gui/main.js, resolveSessionCwd). When that read yields nothing for an id — no entry yet, an unreadable or half-written index, a session created moments ago by another writer — every caller continues with resolveSessionCwd(sid) || os.homedir(), which is what fourteen call sites in main.js do. The id is then opened at the home directory.

The daemon answers this exact question. resolve_session_cwd replies with a session_cwd_result frame: {"cwd": <project>, "source": "index"} when the global session index knows the session, {"cwd": null, "source": "unknown"} when it does not, and it deliberately never relabels the caller's guess as canonical. The TUI asks it before every open — the /resume <id> path and the session picker both go through emrg/client/app.py. The GUI has no call site for it at all.

Measured on this host

Two sessions carry the same id feishu-inbox:

dir message_count cwd created
~/.emrg/sessions/feishu-inbox 0 /Users/argszero (home) 2026-10-22T16:37:28
~/.emrg/.emrg/sessions/feishu-inbox 57 /Users/argszero/.emrg 2026-10-22T16:37:58

The first is the shape the || os.homedir() substitution produces, and the daemon's own _handle_resume_session docstring names the failure: a client whose cwd falls back to the home directory creates a 0-message ghost session under ~/.emrg/sessions/<sid>/, and the real session is then unreachable.

That defence runs only on resume_session. The GUI's send path does not resume: emrg:sendMessage opens its connection with openSession(sessionId, cwd, { resume: false }), so no resume_session frame is sent, the ghost check never runs, and the first task on that connection reaches the daemon's create path with whatever cwd this side supplied — the home directory whenever the local index lookup returned nothing.

What the fix must satisfy

  1. The GUI asks the daemon (resolve_session_cwd) before opening a session whose project an open connection does not already hold, and opens at the answered cwd when the answer is index.
  2. An unknown answer is not a fact. The caller's own candidate — the project the host opened the session from — stands, and the fallback chain must not end at os.homedir() for an id the daemon's index does know.
  3. A send that has to open a connection first is subject to the same check a resume gets; the ghost window is the pre-open, not the message.
  4. The GUI's copy of the daemon's index rule is not the arbiter. One rule, one owner: the daemon answers, the client obeys.

What is not the fix

Refusing an unknown id outright. A session the renderer has just created has no index entry yet, and unknown is the correct answer for it — the fix must keep that session openable at the project the host is working in.

Activity

  1. argszero commented on Oct 22, 2026

    @argszero
    OwnerAuthor

    Handled by #2485

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions