Skip to content

fix(hook): key session_map under the session readers resolve against - #138

Open
paskal wants to merge 1 commit into
alexei-led:mainfrom
paskal:fix/session-map-key-linked-window
Open

fix(hook): key session_map under the session readers resolve against#138
paskal wants to merge 1 commit into
alexei-led:mainfrom
paskal:fix/session-map-key-linked-window

Conversation

@paskal

@paskal paskal commented Jul 28, 2026

Copy link
Copy Markdown

Follow-up to #135, independent of it — same underlying setup (driving agents that another tool launched), different bug.

Problem

_resolve_window_id keys session_map from the session tmux reports for the firing pane:

session_window_key = f"{tmux_session_name}:{window_id}"

Readers resolve entries by session_map_prefix_for(mux, config.tmux_session_name), i.e. ccgram:<window_id> (window_resolver.py:39-41, status_cmd.py:151-152, session_map.prune_session_map).

Those agree only while the window's sole session is ccgram's. A window linked in with tmux link-window belongs to several sessions, and tmux reports the one that owns the pane. The hook then writes agentdeck_foo_1234:@12 while every reader looks up ccgram:@12.

Nothing fails loudly. The hook logs Updated session_map, the topic binds and shows status, and ccgram status reports Monitored sessions: 0 with no transcript ever relayed. Adding to the confusion, prune_session_map skips the mis-keyed entry precisely because it doesn't match the prefix, so it lingers.

This matters because adopting foreign windows is supported on purpose — the manual_discovered origin marker exists for it — and link-window is the natural way to hand ccgram an agent that something else started. In my case that's agent-deck, which names a tmux session per agent, so every adopted window is affected.

Change

Ask tmux for #{window_linked_sessions} in the display-message call the resolver already makes, and only when the window is genuinely linked, confirm which session to key under. Unlinked windows keep the pane's own session and cost no extra subprocess, so the ordinary single-session path is untouched — which is also why the existing TestTabDelimitedParsing cases still pass unchanged.

Alternative

Possibly better as a reader-side fix: tmux window ids are server-global, so resolving entries by their @N suffix rather than a session-name prefix would sidestep the ambiguity for any multi-session arrangement, not just linked windows. I went with the smaller change here, but happy to rework it that way if you prefer.

Verified

tests/ccgram/test_hook.py passes (72), including five new cases covering linked, unlinked, already-ours, tmux-failure and timeout. Full suite is green apart from test_send_failure_replies_error, which fails identically on an unmodified checkout here. ruff check and ruff format --check clean.

On a real machine: before this, an adopted agent-deck window bound its topic and stayed silent at Monitored sessions: 0; after it, the binding is found and transcripts relay.

A window linked into ccgram's tmux session belongs to more than one session,
and tmux reports whichever one owns the firing pane. The hook keyed
session_map from that, while every reader resolves entries by
session_map_prefix_for(mux, config.tmux_session_name), i.e. "ccgram:<window_id>".

So adopting a window that another tool created — `tmux link-window` being the
natural way to hand ccgram an existing agent — writes a binding no reader can
find. Nothing errors: the hook logs "Updated session_map", the topic binds, and
`ccgram status` reports "Monitored sessions: 0" forever with no transcript
relay. Concretely this is what happens with agent-deck, which names a tmux
session per agent.

Ask tmux for #{window_linked_sessions} in the display-message call the resolver
already makes, and only when the window really is linked, confirm which session
to key under. Unlinked windows keep the pane's own session and take no extra
subprocess, so the single-session path is unchanged.

An alternative worth considering is fixing this on the reader side instead:
window ids are server-global, so matching entries by their "@n" suffix rather
than a session-name prefix would cover any multi-session arrangement. This
patch is the smaller change; happy to rework it that way if you prefer.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant