Skip to content

Reduce shell integration prompt latency - #2109

Merged
lawrencecchen merged 2 commits into
mainfrom
feat-shell-integration-hotpath
Mar 25, 2026
Merged

lawrencecchen merged 2 commits into
mainfrom
feat-shell-integration-hotpath

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented Mar 25, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Use zsh/net/unix (zsocket) for socket sends, eliminating fork+exec of ncat/socat/nc per telemetry send (~3ms each, 3-4 per prompt cycle)
  • Replace _cmux_kill_process_tree (synchronous /bin/ps -ax | awk) with direct kill in _cmux_stop_pr_poll_loop, removing ~5-13ms of synchronous process enumeration per command
  • Guard _cmux_patch_ghostty_semantic_redraw after first success, make _cmux_clear_pr_for_panel async, cache bash send tool choice at init

Estimated savings: ~10-15ms per prompt cycle on zsh with zsocket, ~5-13ms on bash (from tree-kill removal).

Testing

  • zsh -n and bash -n syntax checks pass
  • zsocket path: connect, write, close per send (same semantics as ncat --send-only)
  • Fallback path: unchanged behavior when zsh/net/unix unavailable
  • Direct kill: orphaned gh / sleep processes self-terminate within seconds

Related

  • Task: shell integration hotpath causing slightly slower prompt than vanilla Ghostty

Summary by cubic

Reduce shell prompt latency by ~10–15ms on zsh and ~5–13ms on bash with faster socket sends, cheaper poll shutdown, and fewer forks. Addresses the shell integration hotpath performance task.

  • Refactors
    • zsh: Use zsh/net/unix (zsocket) for socket sends with fallback; add _cmux_send_bg (sync with zsocket, bg otherwise).
    • bash: Cache send tool once after _cmux_fix_path; keep _cmux_clear_pr_for_panel synchronous to avoid races.
    • Replace _cmux_kill_process_tree with process-group SIGKILL (kill -KILL -- -$PID) in _cmux_stop_pr_poll_loop; guard _cmux_patch_ghostty_semantic_redraw to run once.

Written for commit 84ef9e5. Summary will update on new commits.

Summary by CodeRabbit

  • Chores
    • Optimized shell integration startup by implementing caching for transport tool selection, reducing repeated detection overhead
    • Improved process cleanup and resource management across bash and zsh through refined termination mechanisms
    • Enhanced communication efficiency in zsh with faster socket handling for background operations
    • Refined transport tool detection to ensure reliable compatibility across diverse system configurations

Three changes to cut ~10-15ms from every precmd/preexec cycle:

1. Use zsh/net/unix (zsocket) for socket sends when available. Eliminates
   fork+exec of ncat/socat/nc for every telemetry send (~3ms per send,
   3-4 sends per prompt cycle). Falls back to external tools if the
   module is unavailable.

2. Replace _cmux_kill_process_tree (synchronous /bin/ps -ax | awk) with
   direct kill in _cmux_stop_pr_poll_loop. The tree-kill enumerated all
   system processes on every command (~5-13ms). Orphaned children (gh,
   sleep) finish on their own within seconds.

3. Minor savings: guard _cmux_patch_ghostty_semantic_redraw after first
   success, make _cmux_clear_pr_for_panel async, cache bash send tool.
@vercel

vercel Bot commented Mar 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
cmux Ready Ready Preview, Comment Mar 25, 2026 5:45am

@coderabbitai

coderabbitai Bot commented Mar 25, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Shell integration scripts for both bash and zsh were refactored to optimize transport detection and process termination. Bash now caches send-tool selection via _cmux_detect_send_tool(), deferring probing until after path initialization. Zsh adds zsocket-based UNIX socket sending when available and centralizes backgrounded sends via _cmux_send_bg. Both scripts replace recursive process-tree killing with direct process-group termination.

Changes

Cohort / File(s) Summary
Bash Integration Send Tool Caching
Resources/shell-integration/cmux-bash-integration.bash
Introduced _CMUX_SEND_TOOL global and _cmux_detect_send_tool() function to probe and cache transport selection (ncat → socat → nc). Refactored _cmux_send to dispatch via case statement instead of inline detection. Deferred tool detection until after _cmux_fix_path execution.
Bash Process Poll Loop Termination
Resources/shell-integration/cmux-bash-integration.bash
Replaced recursive _cmux_kill_process_tree logic in _cmux_stop_pr_poll_loop with direct process-group kill using kill -KILL -- -"$_CMUX_PR_POLL_PID".
Zsh Socket-Based Send Optimization
Resources/shell-integration/cmux-zsh-integration.zsh
Added dynamic detection and loading of zsh/net/unix module to enable in-process UNIX socket sending via zsocket. Introduced _cmux_send_bg helper to conditionally background sends based on socket availability, consolidating multiple ad-hoc backgrounded invocations across tty reporting, shell activity, PR clearing, and directory change reporting.
Zsh Process Poll Loop & Semantic Patch
Resources/shell-integration/cmux-zsh-integration.zsh
Updated _cmux_stop_pr_poll_loop to terminate via process-group kill -KILL. Added guard to run Ghostty semantic patch only if not already patched (conditional on _CMUX_GHOSTTY_SEMANTIC_PATCHED).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Whiskers twitch with glee—
Send tools cached, swift and spry,
Sockets dance, UNIX-fast!
Process groups meet SIGKILL's might,
Bash and zsh harmonize in flight. ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Reduce shell integration prompt latency' directly and accurately summarizes the main change—optimization work to improve prompt response time through socket sends, process-tree elimination, and caching.
Description check ✅ Passed The description includes a comprehensive summary with what changed and why, testing methodology (syntax checks, fallback behavior, process self-termination), and estimated savings. It aligns well with the repository template, though the demo video section is omitted (acceptable for non-UI changes) and the checklist is not filled in.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat-shell-integration-hotpath

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 34049e41b7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +283 to +285
{
_cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
} >/dev/null 2>&1 & disown

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Keep clear_pr synchronous before restarting PR polling

_cmux_prompt_command calls _cmux_clear_pr_for_panel right before _cmux_start_pr_poll_loop when repo context changes, and this change makes clear_pr fire in a detached background job. That introduces a race where the new poll can send report_pr ... first and the delayed clear_pr arrives afterward, clearing a newly correct PR badge until the next poll cycle. This is a user-visible correctness regression during fast branch/directory switches.

Useful? React with 👍 / 👎.

Comment on lines 459 to 462
# Direct kill avoids the synchronous /bin/ps + awk of tree-kill (~5-13ms).
# Orphaned children (gh, sleep) finish on their own within seconds.
kill -KILL "$_CMUX_PR_POLL_PID" 2>/dev/null || true
_CMUX_PR_POLL_PID=""

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Kill PR poll children when stopping the polling loop

Stopping the poller now sends SIGKILL only to _CMUX_PR_POLL_PID, but the loop can have an active _cmux_run_pr_probe_with_timeout child (gh pr view) that survives as an orphan and can still emit PR updates for stale context. That means old report_pr/clear_pr messages may arrive after context switches and overwrite newer sidebar state, which did not happen when the full process tree was terminated.

Useful? React with 👍 / 👎.

@greptile-apps

greptile-apps Bot commented Mar 25, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR reduces shell integration prompt latency by eliminating the most expensive synchronous operations in the zsh and bash hotpath. The primary gains come from three targeted changes: using zsh/net/unix (zsocket) for in-process Unix socket writes instead of fork+exec of ncat/socat/nc (~3 ms saved per send, 3–4 sends per prompt cycle), replacing the recursive _cmux_kill_process_tree (which ran /bin/ps -ax | awk synchronously in preexec) with a direct kill -KILL (~5–13 ms saved), and skipping the ghostty semantic-redraw patch after it has already succeeded. The bash side gains a one-time tool-detection cache and async clear_pr to match the zsh optimizations.

  • zsocket fast path (zsh): zmodload zsh/net/unix at init sets _CMUX_HAS_ZSOCKET; new _cmux_send_bg() calls _cmux_send() synchronously (~0.2 ms, no fork) when available, otherwise backgrounds. Falls back transparently to ncat/socat/nc.
  • Direct kill (zsh + bash): _cmux_stop_pr_poll_loop now uses kill -KILL on just the poll-loop PID. Orphaned gh/sleep children self-terminate within seconds; this is an explicit, documented trade-off.
  • Ghostty patch guard (zsh): (( _CMUX_GHOSTTY_SEMANTIC_PATCHED )) || in _cmux_precmd skips the patch scan after first success, avoiding repeated string substitutions on function bodies every prompt.
  • Bash tool cache: _cmux_detect_send_tool runs once at source time; _cmux_send switches on _CMUX_SEND_TOOL instead of re-running command -v on every send.
  • Orphaned gh accumulation: Under rapid-fire commands (< one gh call completion apart), each _cmux_stop_pr_poll_loop call in preexec leaves a new orphaned gh pr view in flight. In normal interactive use this is harmless, but it could briefly stack multiple concurrent GitHub API calls under scripted or agent-driven workloads.

Confidence Score: 4/5

  • Safe to merge with the orphaned-process trade-off acknowledged; one targeted follow-up could harden rapid-command scenarios.
  • All three optimizations are technically correct: the zsocket path has a clean fallback, the ghostty guard behaves identically to the old code for the non-ghostty case, and the tool cache is a pure latency win. The only behavioral change with real-world implications is replacing tree-kill with direct kill — the PR explicitly documents the orphaned-gh trade-off, and under normal interactive use it is harmless. The potential for brief API-rate-limit pressure under heavy scripted/agent workloads is a P2 concern, not a blocking issue. Score docked one point to reward that concrete follow-up path.
  • No files require special attention beyond the noted orphaned-process trade-off in both shell integration files.

Important Files Changed

Filename Overview
Resources/shell-integration/cmux-zsh-integration.zsh Adds zsh/net/unix (zsocket) fast path for socket sends (~0.2 ms vs ~3 ms fork+exec), introduces _cmux_send_bg() helper that is synchronous on zsocket and backgrounded otherwise, guards ghostty semantic patching after first success, and replaces _cmux_kill_process_tree with direct kill -KILL in _cmux_stop_pr_poll_loop. The zsocket path is correct and well-guarded with a fallback. The tree-kill replacement leaves orphaned gh subprocesses that self-terminate, which is documented and acceptable in normal interactive use but could cause rate-limit pressure under rapid command sequences.
Resources/shell-integration/cmux-bash-integration.bash Caches the selected send tool (_CMUX_SEND_TOOL) at source time instead of re-probing PATH on every _cmux_send call, makes _cmux_clear_pr_for_panel async (consistent with zsh), and replaces _cmux_kill_process_tree with direct kill -KILL in _cmux_stop_pr_poll_loop. The tool detection runs slightly before _cmux_fix_path re-orders PATH, which is harmless today but fragile for future changes.

Sequence Diagram

sequenceDiagram
    participant Shell as Shell (preexec/precmd)
    participant SendBg as _cmux_send_bg()
    participant ZSocket as zsocket (zsh/net/unix)
    participant Extern as ncat/socat/nc (fork+exec)
    participant Server as cmux daemon (Unix socket)
    participant PollLoop as PR Poll Loop (bg process)
    participant GH as gh pr view (subprocess)

    Note over Shell,Server: ZSH with zsh/net/unix available (new fast path)
    Shell->>SendBg: _cmux_send_bg("report_shell_state ...")
    SendBg->>ZSocket: zsocket $CMUX_SOCKET_PATH
    ZSocket-->>SendBg: fd = REPLY (~0.2ms, no fork)
    SendBg->>Server: print -u fd (payload + newline)
    SendBg->>ZSocket: exec {fd}>&- (close)

    Note over Shell,Server: Fallback path (no zsocket / bash)
    Shell->>SendBg: _cmux_send_bg("report_shell_state ...")
    SendBg->>Extern: { _cmux_send ... } &! (background fork)
    Extern->>Server: pipe payload via ncat/socat/nc (~3ms fork cost)

    Note over Shell,PollLoop: preexec — stopping the PR poll loop (new direct kill)
    Shell->>PollLoop: kill -KILL $_CMUX_PR_POLL_PID
    PollLoop--xPollLoop: terminated immediately
    Note over GH: orphaned gh process self-terminates within seconds
    GH-->>GH: (continues until network call completes)

    Note over Shell,PollLoop: precmd — starting new PR poll loop
    Shell->>PollLoop: _cmux_start_pr_poll_loop (new background job)
    PollLoop->>GH: gh pr view (subshell)
    GH-->>Server: _cmux_send("report_pr ...")
Loading

Reviews (1): Last reviewed commit: "Reduce shell integration prompt latency" | Re-trigger Greptile

Comment on lines 580 to 587
_cmux_stop_pr_poll_loop() {
if [[ -n "$_CMUX_PR_POLL_PID" ]]; then
# Use SIGKILL directly to avoid blocking sleep in preexec.
# The poll loop is lightweight and safe to kill abruptly.
_cmux_kill_process_tree "$_CMUX_PR_POLL_PID" KILL
# Direct kill avoids the synchronous /bin/ps + awk of tree-kill (~5-13ms).
# Orphaned children (gh, sleep) finish on their own within seconds.
kill -KILL "$_CMUX_PR_POLL_PID" 2>/dev/null || true
_CMUX_PR_POLL_PID=""
fi
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Orphaned gh processes may accumulate across rapid commands

kill -KILL $_CMUX_PR_POLL_PID kills only the top-level poll loop process. The subshell chain it spawned—_cmux_run_pr_probe_with_timeout → _cmux_report_pr_for_path → gh pr view—is reparented to launchd and continues running until the network call completes (up to _CMUX_ASYNC_JOB_TIMEOUT = 20 s).

In normal interactive use this is fine (one gh call per 45 s poll, single orphan lives for ≤ 5 s). However, in rapid-fire scenarios—running many commands in quick succession, or an agent loop executing commands at < 5 s intervals—each preexec call to _cmux_stop_pr_poll_loop leaves a new orphaned gh pr view behind while the previous one is still in flight. This can stack up multiple simultaneous gh API calls, risk GitHub's per-minute rate limit, and add unnecessary background CPU/network pressure.

The same change exists in the bash integration at line 461.

If the trade-off is intentional (it is explicitly called out in the PR description), consider at minimum capping the orphan window by signaling the intermediate subshell group. For example, if _CMUX_PR_POLL_PID is set as a process group leader, kill -KILL -- -$_CMUX_PR_POLL_PID kills the entire group without the ps+awk cost.

_CMUX_SEND_TOOL=nc
fi
}
_cmux_detect_send_tool

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Tool detection runs before _cmux_fix_path prepends Resources/bin

_cmux_detect_send_tool is called at line 14, but _cmux_fix_path (which prepends Resources/bin to PATH) is called near the bottom of the file (line 713). If any of the send tools ever ship inside Resources/bin, the cached _CMUX_SEND_TOOL would be empty because they aren't on PATH yet at detection time.

Today ncat, socat, and nc are all standard system tools and not in Resources/bin, so there is no practical regression. Just worth documenting or moving the detection call to after _cmux_fix_path is executed to keep ordering safe for future changes.

Suggested change
_cmux_detect_send_tool
_cmux_fix_path
unset -f _cmux_fix_path
_cmux_detect_send_tool
_cmux_install_prompt_command

(move the _cmux_detect_send_tool call just after _cmux_fix_path at the bottom of the file)

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Resources/shell-integration/cmux-bash-integration.bash">

<violation number="1" location="Resources/shell-integration/cmux-bash-integration.bash:461">
P2: Killing only the poll-loop PID can orphan in-flight PR probe children, which may emit stale PR updates for the panel after a poll-loop restart.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

Comment thread Resources/shell-integration/cmux-bash-integration.bash Outdated
1. Use kill -KILL -- -$PID (process-group kill) instead of plain kill.
   Background jobs are process-group leaders, so this kills all
   descendants (gh, sleep) without /bin/ps overhead.

2. Keep bash _cmux_clear_pr_for_panel synchronous to prevent race
   with the next report_pr from the poll loop. Zsh version uses
   _cmux_send_bg which is synchronous when zsocket is available.

3. Move _cmux_detect_send_tool after _cmux_fix_path in bash so the
   cached tool lookup runs with the final PATH.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 84ef9e52c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0
_cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
_cmux_send_bg "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep zsh clear_pr ordered before restarting PR polling

_cmux_clear_pr_for_panel now uses _cmux_send_bg, and in the fallback path (_CMUX_HAS_ZSOCKET=0) that send is detached. In _cmux_precmd, this clear runs immediately before _cmux_start_pr_poll_loop, so a delayed clear_pr can arrive after a fresh report_pr from the restarted poller and wipe a correct badge until the next poll cycle. This is a user-visible correctness regression on systems where zsh/net/unix is unavailable.

Useful? React with 👍 / 👎.

_cmux_fix_path
unset -f _cmux_fix_path

_cmux_detect_send_tool

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Re-resolve bash send transport after PATH changes

The transport is detected once at startup (_cmux_detect_send_tool) and then _cmux_send trusts the cached command forever. If the user later mutates PATH (common with direnv/venv/nix shells), the cached tool can disappear while another compatible tool is still present; _cmux_send then fails instead of falling back, so sidebar telemetry updates stop. The previous behavior re-checked availability per send and did not regress on post-startup PATH changes.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

2 issues found across 2 files (changes from recent commits).

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="Resources/shell-integration/cmux-bash-integration.bash">

<violation number="1" location="Resources/shell-integration/cmux-bash-integration.bash:284">
P2: The new synchronous `clear_pr` send no longer suppresses transport stderr, so `ncat` errors can print into the prompt.</violation>

<violation number="2" location="Resources/shell-integration/cmux-bash-integration.bash:461">
P2: Process-group kill assumes `$!` is always a PGID leader; when that isn’t true, stop can fail silently and leave orphaned PR poll loops running.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

# Process-group kill: background jobs are process-group leaders, so
# negative PID kills the loop + all descendants (gh, sleep) without
# the synchronous /bin/ps + awk of tree-kill (~5-13ms).
kill -KILL -- -"$_CMUX_PR_POLL_PID" 2>/dev/null || true

@cubic-dev-ai cubic-dev-ai Bot Mar 25, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Process-group kill assumes $! is always a PGID leader; when that isn’t true, stop can fail silently and leave orphaned PR poll loops running.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/shell-integration/cmux-bash-integration.bash, line 461:

<comment>Process-group kill assumes `$!` is always a PGID leader; when that isn’t true, stop can fail silently and leave orphaned PR poll loops running.</comment>

<file context>
@@ -456,9 +455,10 @@ _cmux_run_pr_probe_with_timeout() {
+        # Process-group kill: background jobs are process-group leaders, so
+        # negative PID kills the loop + all descendants (gh, sleep) without
+        # the synchronous /bin/ps + awk of tree-kill (~5-13ms).
+        kill -KILL -- -"$_CMUX_PR_POLL_PID" 2>/dev/null || true
         _CMUX_PR_POLL_PID=""
     fi
</file context>
Suggested change
kill -KILL -- -"$_CMUX_PR_POLL_PID" 2>/dev/null || true
kill -KILL -- -"$_CMUX_PR_POLL_PID" 2>/dev/null || kill -KILL "$_CMUX_PR_POLL_PID" 2>/dev/null || true
Fix with Cubic

[[ -n "$CMUX_TAB_ID" ]] || return 0
[[ -n "$CMUX_PANEL_ID" ]] || return 0
# Synchronous: must arrive before the next report_pr from the poll loop.
_cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"

@cubic-dev-ai cubic-dev-ai Bot Mar 25, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: The new synchronous clear_pr send no longer suppresses transport stderr, so ncat errors can print into the prompt.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At Resources/shell-integration/cmux-bash-integration.bash, line 284:

<comment>The new synchronous `clear_pr` send no longer suppresses transport stderr, so `ncat` errors can print into the prompt.</comment>

<file context>
@@ -280,9 +280,8 @@ _cmux_clear_pr_for_panel() {
-        _cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
-    } >/dev/null 2>&1 & disown
+    # Synchronous: must arrive before the next report_pr from the poll loop.
+    _cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
 }
 
</file context>
Suggested change
_cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
_cmux_send "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID" >/dev/null 2>&1
Fix with Cubic

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
Resources/shell-integration/cmux-zsh-integration.zsh (1)

403-408: Note: _cmux_clear_pr_for_panel may have a race condition without zsocket.

In bash, this send is explicitly synchronous with a comment explaining it must complete before the poll loop's next report_pr. Here in zsh, _cmux_send_bg makes it synchronous only when zsocket is available.

When zsocket is unavailable and external tools are used, the backgrounded clear could race with the poll loop. The window is likely small, and the trade-off for reduced latency seems intentional per the PR objectives.

Consider adding a comment documenting this trade-off
 _cmux_clear_pr_for_panel() {
     [[ -S "$CMUX_SOCKET_PATH" ]] || return 0
     [[ -n "$CMUX_TAB_ID" ]] || return 0
     [[ -n "$CMUX_PANEL_ID" ]] || return 0
+    # Synchronous when zsocket is available; backgrounded otherwise.
+    # Small race window with poll loop is acceptable for latency trade-off.
     _cmux_send_bg "clear_pr --tab=$CMUX_TAB_ID --panel=$CMUX_PANEL_ID"
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Resources/shell-integration/cmux-zsh-integration.zsh` around lines 403 - 408,
The helper _cmux_clear_pr_for_panel calls _cmux_send_bg which is synchronous
only when zsocket is present, otherwise it backgrounds the clear and can race
with the poll loop's next report_pr; update _cmux_clear_pr_for_panel to include
a concise inline comment documenting this trade-off (that zsocket makes the send
synchronous, external-tool fallback is backgrounded and may race, and this is an
intentional latency vs. consistency choice) and reference _cmux_send_bg and the
poll/report_pr flow so future readers know why no explicit synchronization was
added.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@Resources/shell-integration/cmux-zsh-integration.zsh`:
- Around line 403-408: The helper _cmux_clear_pr_for_panel calls _cmux_send_bg
which is synchronous only when zsocket is present, otherwise it backgrounds the
clear and can race with the poll loop's next report_pr; update
_cmux_clear_pr_for_panel to include a concise inline comment documenting this
trade-off (that zsocket makes the send synchronous, external-tool fallback is
backgrounded and may race, and this is an intentional latency vs. consistency
choice) and reference _cmux_send_bg and the poll/report_pr flow so future
readers know why no explicit synchronization was added.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7ad659e2-03a3-4ea4-bfe8-2b88e8511bbf

📥 Commits

Reviewing files that changed from the base of the PR and between b919541 and 84ef9e5.

📒 Files selected for processing (2)
  • Resources/shell-integration/cmux-bash-integration.bash
  • Resources/shell-integration/cmux-zsh-integration.zsh

@lawrencecchen
lawrencecchen merged commit 71828fe into main Mar 25, 2026
14 checks passed
@lawrencecchen
lawrencecchen deleted the feat-shell-integration-hotpath branch March 25, 2026 06:08
Jesssullivan added a commit to Jesssullivan/cmux that referenced this pull request Mar 26, 2026
Ingests all upstream fixes since 2026-03-22 including:
- Fix Cmd+N crash: retain snapshot workspaces (manaflow-ai#2183, manaflow-ai#2181, manaflow-ai#2178, manaflow-ai#2173)
- Fix browser pane restore after reopen (manaflow-ai#2141)
- Fix Ghostty resize_split keybind (manaflow-ai#1899)
- Reduce shell integration prompt latency (manaflow-ai#2109)
- Fix command palette focus after terminal find (manaflow-ai#2089)
- Add Codex CLI hooks (manaflow-ai#2103)
- Add cmux.json custom commands (manaflow-ai#2011)
- Fix window position restore on relaunch (manaflow-ai#2129)

Conflict resolution:
- BrowserPanel.swift: accepted upstream configureWebViewConfiguration()
  refactor (already includes our forMainFrameOnly:true CAPTCHA fix from PR manaflow-ai#1877)

Fork-specific files preserved:
- Sources/Panels/WebAuthn{Coordinator,BridgeJavaScript}.swift
- Sources/FIDO2/module.modulemap
- vendor/ctap2 submodule
- cmux.entitlements (with camera/audio-input removed)
- cmux.embedded.entitlements
- .github/workflows/fork-{ci,release}.yml
bn-l pushed a commit to bn-l/cmux that referenced this pull request Apr 3, 2026
* Reduce shell integration prompt latency

Three changes to cut ~10-15ms from every precmd/preexec cycle:

1. Use zsh/net/unix (zsocket) for socket sends when available. Eliminates
   fork+exec of ncat/socat/nc for every telemetry send (~3ms per send,
   3-4 sends per prompt cycle). Falls back to external tools if the
   module is unavailable.

2. Replace _cmux_kill_process_tree (synchronous /bin/ps -ax | awk) with
   direct kill in _cmux_stop_pr_poll_loop. The tree-kill enumerated all
   system processes on every command (~5-13ms). Orphaned children (gh,
   sleep) finish on their own within seconds.

3. Minor savings: guard _cmux_patch_ghostty_semantic_redraw after first
   success, make _cmux_clear_pr_for_panel async, cache bash send tool.

* Address review: process-group kill, fix clear_pr race, reorder bash init

1. Use kill -KILL -- -$PID (process-group kill) instead of plain kill.
   Background jobs are process-group leaders, so this kills all
   descendants (gh, sleep) without /bin/ps overhead.

2. Keep bash _cmux_clear_pr_for_panel synchronous to prevent race
   with the next report_pr from the poll loop. Zsh version uses
   _cmux_send_bg which is synchronous when zsocket is available.

3. Move _cmux_detect_send_tool after _cmux_fix_path in bash so the
   cached tool lookup runs with the final PATH.

---------

Co-authored-by: Lawrence Chen <lawrencecchen@users.noreply.github.com>

This branch was successfully deployed

1 active deployment
Preview — 84ef9e52 Deployed Mar 25, 2026 by vercel[bot]
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