fix: thread caller pane ID for cross-instance session isolation#151
Merged
bfly123 merged 3 commits intobfly123:mainfrom Mar 30, 2026
Merged
Conversation
… response When the completion hook delivers a Codex/Gemini response back to a Claude Code pane, the multi-line message was sent with --no-paste, causing each \n character to arrive as a raw LF keystroke. Claude Code runs as a raw-mode TUI that does not submit on LF (0x0A) — it requires a real Enter key event. As a result, the response was pasted into the input buffer but never auto-submitted, requiring the user to press Enter manually. The send path (terminal.py WeztermBackend.send_text) already handles this correctly: it uses bracketed paste mode for multi-line content, then calls _send_enter() which uses `wezterm cli send-key --key Enter`. The completion hook's send_via_wezterm() was inconsistent with this pattern. Fix: - Send the response body using bracketed paste mode (omit --no-paste) so intermediate \n chars are treated as literal newlines in a paste block - After a brief pause (0.1s) to let the TUI process the paste, send a proper Enter key event via `wezterm cli send-key`, trying both --key Enter and positional Enter across WezTerm CLI versions, with a \r byte fallback Tmux is not affected: send_via_tmux() already uses paste-buffer + send-keys Enter. May also reduce cases reported in bfly123#142 where fragmented \n keystrokes caused incomplete delivery of the response to Claude Code's input.
…tion When multiple Claude Code instances run in the same project directory, completion hook responses were routed to the wrong instance because all instances share a single session file (.claude-session). The session file contains one pane_id, which gets overwritten by whichever instance wrote last — so responses always went to that instance, not the one that originated the request. Fix: capture the caller's terminal pane ID (WEZTERM_PANE or TMUX_PANE) at ask-time and thread it through the entire request chain: ask (capture) → daemon RPC → ProviderRequest → adapter → notify_completion → completion hook env → direct terminal send When CCB_CALLER_PANE_ID is set, the completion hook sends directly to that pane, bypassing the session file lookup entirely. When unset (older ask clients), the existing session-file-based routing is preserved as fallback. Also fixes auto-submit on older WezTerm versions (pre-send-key): replaces the send-key Enter approach with a trailing \n in the bracketed paste payload, which triggers submission in raw-mode TUIs like Claude Code across all WezTerm versions. Changes (13 files): - bin/ask: _caller_pane_info() helper, threads pane ID through daemon request and background script env vars - bin/ccb-completion-hook: direct pane routing fast path; session file search moved to else branch (skipped when direct pane available); simplified send_via_wezterm using trailing \n instead of send-key - lib/askd/adapters/base.py: caller_pane_id/caller_terminal fields on ProviderRequest - lib/askd/daemon.py: reads caller_pane_id/caller_terminal from RPC msg - lib/completion_hook.py: passes CCB_CALLER_PANE_ID/CCB_CALLER_TERMINAL env vars to hook subprocess - All 7 adapter files: forward caller_pane_id/caller_terminal to notify_completion Related: bfly123#142, bfly123#149 268/268 tests pass.
M-Marbouh
added a commit
to M-Marbouh/claude_code_bridge
that referenced
this pull request
Mar 30, 2026
WezTerm builds pre-dating send-key (e.g. 20240203) fall through to the CR byte fallback immediately after send-text completes. Without a short delay, the \r arrives before the TUI has finished processing the bracketed paste sequence, causing Claude Code to ignore it and require a manual Enter. Add time.sleep(0.1) before any Enter-sending attempt so the bracketed paste is fully consumed first. Reproduces the timing that was present in bfly123#149 and was inadvertently dropped in bfly123#151. Fixes: bfly123#149 regression introduced by bfly123#151 on older WezTerm versions.
2 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When multiple Claude Code instances run in the same project directory and both
use
ask codex(or any provider), completion hook responses are routed to thewrong instance. This happens because all instances share a single session
file (e.g.,
.claude-session), which contains onepane_id. Whichever instancewrites the session file last "wins" — all responses go to that pane, regardless
of which instance originated the request.
Additionally, the
send-key Enterapproach from #149 does not work on olderWezTerm versions (e.g.,
20240203) that lack thesend-keysubcommand, causingresponses to paste into the input buffer but never auto-submit.
Environment:
ask codexconcurrentlyRoot Cause
Session file collision: The completion hook resolves the caller's pane by
reading
.claude-session→pane_id. With multiple instances, this file isa shared mutable resource with last-writer-wins semantics.
Missing
send-key: WezTerm versions before ~2024.06 don't havewezterm cli send-key. The hook tries 4 variants, all fail silently, and the\rbyte fallback doesn't trigger submission in raw-mode TUIs.Fix
Pane ID threading (cross-instance isolation)
Capture the caller's terminal pane ID (
WEZTERM_PANEorTMUX_PANE) atask-time and thread it through the entire request chain:When
CCB_CALLER_PANE_IDis set, the completion hook sends directly to thatpane, bypassing the session file lookup entirely. When unset (older
askclients), the existing session-file-based routing is preserved as fallback.
Auto-submit on older WezTerm
Replace the
send-key Enterapproach with a trailing\nappended to themessage payload inside the bracketed paste. After the paste bracket closes, the
\ntriggers submission in raw-mode TUIs. This works across all WezTermversions since it only uses
send-text.Changes (13 files, +161 / -109)
bin/ask_caller_pane_info()helper; threads pane ID via daemon RPC and background script envlib/askd/adapters/base.pycaller_pane_id,caller_terminalfields onProviderRequestlib/askd/daemon.pycaller_pane_id/caller_terminalfrom RPC messagelib/completion_hook.pyCCB_CALLER_PANE_ID/CCB_CALLER_TERMINALenv vars to hook scriptbin/ccb-completion-hookelsebranch; simplifiedsend_via_weztermcodex,gemini,opencode,droid,claude,copilot,codebuddy,qwen)caller_pane_id/caller_terminaltonotify_completionTest plan
ask codex "reply PING"from instance A → response arrives in instance A (not B)ask codex "reply PING"from instance B → response arrives in instance B (not A)CCB_CALLER_PANE_IDis not set, falls back to session file lookupReduces cases in #142. Improves on #149 for older WezTerm versions.