Skip to content

Disable Claude OSC notifications in cmux wrapper - #3418

Merged
lawrencecchen merged 7 commits into
mainfrom
task-suppress-claude-osc-notifications
May 4, 2026
Merged

lawrencecchen merged 7 commits into
mainfrom
task-suppress-claude-osc-notifications

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 1, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Set the wrapper-injected Claude Code settings to preferredNotifChannel: notifications_disabled so cmux hook notifications are the only notification source.
  • Use Claude Stop hook final assistant text (last_assistant_message / assistantPreamble) before transcript fallback, so the sidebar notification shows 2 instead of stale generic text.
  • Add focused regressions for wrapper settings and Stop hook notification content, and run both in CI.

Testing

  • ./scripts/setup.sh
  • ./scripts/reload.sh --tag closc
  • ./scripts/reload.sh --tag cstop
  • bash -n Resources/bin/claude
  • python3 scripts/swift_file_length_budget.py --budget .github/swift-file-length-budget.tsv
  • python3 tests/test_claude_wrapper_hooks.py
  • CMUX_CLI_BIN='/Users/lawrence/Library/Developer/Xcode/DerivedData/cmux-cstop/Build/Products/Debug/cmux DEV cstop.app/Contents/Resources/bin/cmux' python3 tests/test_claude_hook_stop_last_assistant.py

Issue

Task: suppress Claude Code OSC notifications when launched through the cmux Claude wrapper, and keep Stop hook notifications sourced from hook data.

Summary by CodeRabbit

  • New Features

    • CLI summaries now recognize assistant preamble content and show a “Completed” subtitle with a truncated message when present.
  • Tests

    • Added an end-to-end regression verifying stop-hook behavior and final assistant text handling.
    • Extended an existing test to assert notification channel is set to disable terminal notifications.
  • Chores

    • CI updated to run the new/regression hook tests.
    • Suppressed Claude Code terminal/OSC notifications in targeted environments.

@vercel

vercel Bot commented May 1, 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 May 1, 2026 10:51pm
cmux-staging Building Building Preview, Comment May 1, 2026 10:51pm

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@coderabbitai

coderabbitai Bot commented May 1, 2026 •

Copy link
Copy Markdown

Warning

Rate limit exceeded

@lawrencecchen has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 2 minutes and 5 seconds before requesting another review.

To keep reviews running without waiting, you can enable usage-based add-on for your organization. This allows additional reviews beyond the hourly cap. Account admins can enable it under billing.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 7d03daa0-aff8-4752-9b64-90ae8b3ab681

📥 Commits

Reviewing files that changed from the base of the PR and between 24661c4 and dcb167f.

📒 Files selected for processing (3)
  • CLI/cmux.swift
  • Resources/Localizable.xcstrings
  • tests/test_claude_hook_stop_last_assistant.py
📝 Walkthrough

Walkthrough

Adds notification suppression to the bundled Claude wrapper settings, extends CI to run two additional Claude hook regressions, updates CLI summary parsing to detect/short-circuit on assistant preamble/last-assistant fields, and adds an end-to-end test that validates cmux claude-hook stop emits notify commands containing the final assistant text.

Changes

Cohort / File(s) Summary
CI Test Commands
\.github/workflows/ci.yml
Appended two claude hook-related test invocations to the existing "Run CLI no-socket regressions" step.
Claude wrapper script
Resources/bin/claude
Added preferredNotifChannel: "notifications_disabled" to the injected --settings JSON and updated comments about notification sources.
Wrapper test assertion
tests/test_claude_wrapper_hooks.py
Added assertion verifying preferredNotifChannel is set to "notifications_disabled" in the generated --settings.
CLI summary parsing
CLI/cmux.swift
Recognizes assistantPreamble/assistant_preamble and other last-assistant keys, adds helper to extract/normalize assistant message, treats them as long content, and short-circuits summary generation to return a "Completed" subtitle with truncated body when present.
End-to-end stop test
tests/test_claude_hook_stop_last_assistant.py
New end-to-end test that resolves the cmux binary, runs a temporary capturing UNIX socket server, invokes cmux claude-hook stop with a Stop payload containing final assistant text, and asserts emitted notify_target_async commands include that final assistant text. Adds main(), resolve_cmux_cli(), and CapturingSocketServer helper.

Sequence Diagram(s)

sequenceDiagram
    participant Test as Test Runner
    participant CLI as cmux CLI
    participant Socket as Local Socket Server
    participant Notifier as notify_target_async

    Test->>Socket: start capturing UNIX socket
    Test->>CLI: run `cmux claude-hook stop` (env overrides, Stop payload)
    CLI->>Socket: connect and POST hook request (Stop payload with assistant preamble/last)
    Socket-->>CLI: respond 200 OK
    CLI->>Notifier: emit `notify_target_async` commands (includes final assistant text)
    Socket-->>Test: captured commands recorded
    Test->>Test: assert captured commands contain final assistant text
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Poem

🐰 I nudged a setting, hushed a noisy chime,

The wrapper whispers softly, so tests can rhyme.
A socket listens, catching the last line,
The final assistant text kept clear and fine.
I hop away content — a tiny, tidy sign.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main change: disabling Claude OSC notifications by injecting preferredNotifChannel settings into the cmux wrapper.
Description check ✅ Passed The PR description covers all template sections with clear summaries of what changed, comprehensive testing steps, and a related issue reference, fulfilling the repository's requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch task-suppress-claude-osc-notifications

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
Review rate limit: 0/8 reviews remaining, refill in 2 minutes and 5 seconds.

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

@greptile-apps

greptile-apps Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR suppresses Claude Code's built-in OSC/terminal notifications when launched through the cmux wrapper by prepending "preferredNotifChannel":"notifications_disabled" to the HOOKS_JSON settings object. A matching regression assertion is added to the existing wrapper-hooks test and the test is wired into the "Run CLI no-socket regressions" CI step.

Confidence Score: 5/5

Safe to merge — minimal, well-tested change to a single JSON string and its matching assertion.

The change is a single-field addition to a static JSON string, with a direct regression test and CI coverage. No logic paths are restructured, and existing tests continue to pass.

No files require special attention.

Important Files Changed

Filename Overview
Resources/bin/claude Adds "preferredNotifChannel":"notifications_disabled" to the front of HOOKS_JSON; updates the comment block to reflect the broader settings scope. Minimal, targeted change.
tests/test_claude_wrapper_hooks.py Adds assertion in test_live_socket_injects_supported_hooks that preferredNotifChannel equals "notifications_disabled" in the parsed settings; correctly covers the new JSON field.
.github/workflows/ci.yml Adds python3 tests/test_claude_wrapper_hooks.py to the "Run CLI no-socket regressions" step. Test doesn't need CMUX_CLI_BIN (it uses a fake binary harness), so placement is correct.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[claude wrapper invoked] --> B{CMUX socket live?}
    B -- yes --> C[Build HOOKS_JSON\npreferredNotifChannel: notifications_disabled\n+ lifecycle hooks]
    B -- no --> D[Skip hook injection\nbut HOOKS_JSON still passed]
    C --> E{SKIP_SESSION_ID?}
    D --> E
    E -- yes --> F[exec real claude\n--settings HOOKS_JSON]
    E -- no --> G[uuidgen session ID\nexec real claude\n--session-id ID\n--settings HOOKS_JSON]
    F --> H[Claude Code starts\nOSC notifications suppressed\ncmux hooks are only notify source]
    G --> H
Loading

Reviews (1): Last reviewed commit: "fix: disable Claude OSC notifications in..." | Re-trigger Greptile

@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.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 14655-14657: The new user-facing literals assigned to subtitle
("Completed" and "Completed in \(projectName)") must be replaced with localized
strings; update the assignment in the code that sets var subtitle (where
projectName is checked) to use String(localized: "notification.completed",
defaultValue: "Completed") for the simple case and String(localized:
"notification.completed_in_project", defaultValue: "Completed in %@" ) or
similar for the projectName case, using String format/localization APIs so the
projectName is injected into the localized template; ensure you add the
corresponding localization keys and default English values.

In `@tests/test_claude_hook_stop_last_assistant.py`:
- Around line 88-97: The post-first-chunk idle_deadline is set to 0.5s which is
too short for CI; in the receive loop inside
tests/test_claude_hook_stop_last_assistant.py (the while loop that uses
idle_deadline, conn.recv, buffer and self.stop), increase the idle window after
receiving the first chunk (the assignment idle_deadline = time.time() + 0.5) to
a larger value (for example 2.0 or 3.0 seconds) so late-arriving data on loaded
runners isn't truncated; keep the initial pre-first-chunk deadline at 6.0s
unchanged.
- Around line 19-21: When an explicit CLI path is provided in the environment
variable (the variable named explicit), fail immediately if that path does not
exist or is not executable instead of falling back to other binaries. Change the
logic around the explicit variable so: if explicit is set and not
(os.path.exists(explicit) and os.access(explicit, os.X_OK)) then raise an
exception (e.g., RuntimeError or pytest.fail) with a clear message including the
value of explicit; otherwise, if it exists and is executable return explicit.
This ensures the test fails fast when CMUX_CLI_BIN/CMUX_CLI points to an invalid
binary.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 39c19a45-f3eb-46bf-8231-2d8d9c7d2e50

📥 Commits

Reviewing files that changed from the base of the PR and between 2b8978a and 28f1a92.

📒 Files selected for processing (3)
  • .github/workflows/ci.yml
  • CLI/cmux.swift
  • tests/test_claude_hook_stop_last_assistant.py
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/ci.yml

Comment thread CLI/cmux.swift Outdated
Comment thread tests/test_claude_hook_stop_last_assistant.py Outdated
Comment thread tests/test_claude_hook_stop_last_assistant.py
@lawrencecchen
lawrencecchen merged commit ab40261 into main May 4, 2026
31 checks passed
@lawrencecchen
lawrencecchen deleted the task-suppress-claude-osc-notifications branch May 4, 2026 03:53

This branch was successfully deployed

1 active deployment
Preview – cmux — dcb167fe Deployed May 1, 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