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
{{ message }}
Repository navigation
emrg: the GUI never asks the daemon where a session lives, so an unplaced id opens at the home directory #2484
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
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.
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.
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.
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
argszero commentedon Oct 22, 2026
Handled by #2485