Skip to content

Suppress nested agent hook notifications - #4334

Merged
lawrencecchen merged 10 commits into
mainfrom
feat-subagent-notification-suppression
May 21, 2026
Merged

lawrencecchen merged 10 commits into
mainfrom
feat-subagent-notification-suppression

Conversation

@lawrencecchen

@lawrencecchen lawrencecchen commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Summary:

  • Suppress visible hook mutations when a Codex or Claude hook belongs to a child agent under another Codex or Claude process.
  • Keep child-agent events in Feed telemetry, including Claude SubagentStop as feed-only telemetry.
  • Add regression coverage for nested versus direct Codex Stop behavior and Claude wrapper hook wiring.

Verification:

  • xcodebuild -project cmux.xcodeproj -scheme cmux-unit -configuration Debug -derivedDataPath /tmp/cmux-subagentnotif -destination 'platform=macOS,arch=arm64' '-only-testing:cmuxTests/CLINotifyProcessIntegrationRegressionTests/testNestedCodexStopDoesNotTriggerVisibleNotificationOrIdleStatus' '-only-testing:cmuxTests/CLINotifyProcessIntegrationRegressionTests/testDirectCodexStopStillTriggersVisibleNotification' test
  • CMUX_CLI_BIN=/tmp/cmux-subagentnotif/Build/Products/Debug/cmux python3 tests/test_codex_feed_hooks.py
  • CMUX_CLI_BIN=/tmp/cmux-subagentnotif/Build/Products/Debug/cmux python3 tests/test_claude_wrapper_hooks.py
  • ./scripts/reload.sh --tag subnotif

Note

Medium Risk
Changes core agent-hook lifecycle handling (PID/status/notifications/resume bindings) based on process ancestry and transcript signals, which could unintentionally hide or fail to clear visible state. Risk is mitigated by new regression tests but spans CLI, app runtime, settings, and hook installers.

Overview
Suppresses visible agent-hook side effects (status/PID updates, resume bindings, completion notifications, and raw terminal notifications) for nested/child Codex and Claude sessions, while keeping those events flowing to Feed telemetry.

Adds a default-on automation.suppressSubagentNotifications setting (UI, Command Palette, cmux.json schema/docs/localizations) and propagates it via CMUX_SUPPRESS_SUBAGENT_NOTIFICATIONS; introduces Claude SubagentStop as feed-only telemetry.

Implements nested-session detection via prompt-depth tracking in the session store, managed-subagent startup env (startup_environment plumbed through socket pane.create/splits), process ancestry heuristics, and Codex transcript markers to avoid suppressing parent completion when relays are stale. Expands Swift and Python test coverage for nested vs direct stop behavior, settings import/toggle, and hook wiring.

Reviewed by Cursor Bugbot for commit bed1feb. Bugbot is set up for automated code reviews on this repo. Configure here.


Summary by cubic

Suppresses notifications and status updates from nested Codex/Claude subagents while keeping all events in Feed. Adds a default‑on toggle, feed‑only Claude SubagentStop, and per‑panel notification suppression.

  • New Features

    • “Suppress Subagent Notifications” (automation.suppressSubagentNotifications, default true) in Settings, Command Palette, and cmux.json; forwarded via CMUX_SUPPRESS_SUBAGENT_NOTIFICATIONS. Claude wrapper adds SubagentStop as Feed‑only telemetry. Docs/schema/locales updated.
    • Terminal pane creation now accepts startup_environment/initial_env to mark managed subagents; Workspace uses this to suppress panel‑scoped terminal/desktop notifications.
  • Bug Fixes

    • Suppresses visible mutations for nested agents using process ancestry, prompt depth, Codex Teams env tags, and transcript markers; env overrides supported.
    • Preserves parent PID/status/resume binding; nested Claude PromptSubmit/PreToolUse/PermissionRequest/Notification/Stop and Codex Stop are Feed‑only. Tests cover resume binding guard, pane env marking, toggle defaults/import, palette toggle, and SubagentStop wiring.

Written for commit bed1feb. Summary will update on new commits. Review in cubic

Summary by CodeRabbit

  • New Features

    • SubagentStop lifecycle hook with async telemetry feed and a Settings toggle: "Suppress Subagent Notifications" (default: On).
  • Improvements

    • Option to suppress visible completion notifications and status/PID changes from nested child agents while still recording their telemetry; terminal and runtime flows respect this setting.
  • Tests

    • Added integration and unit tests covering nested stops, suppression behavior, telemetry, and the toggle.
  • Docs & Localization

    • Settings schema, UI, examples, command palette entry, and translations updated.

Review Change Stack

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

@vercel

vercel Bot commented May 19, 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 21, 2026 3:06am
cmux-staging Building Building Preview, Comment May 21, 2026 3:06am

@coderabbitai

coderabbitai Bot commented May 19, 2026 •

Copy link
Copy Markdown

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds nested prompt depth tracking and centralized session record helpers; implements process-ancestry suppression to avoid visible agent mutations for nested/subagent runs; introduces a Claude SubagentStop feed-only hook; applies suppression across Claude and Codex handlers; and adds tests, UI toggle, localization, schema, and environment wiring.

Changes

Nested Agent Visible Mutations Suppression with SubagentStop Hook

Layer / File(s) Summary
Session depth, record helpers, and enums
CLI/cmux.swift
Adds activePromptDepth, recordPromptSubmit/recordPromptStop, makeSessionRecord/update helpers, and HookAgentProcessKind/constants used by suppression.
Process-kind detection and suppression decision
CLI/cmux.swift
Implements claudeAgentPID parsing, native process-kind classification, parent-process ancestry traversal, and shouldSuppressNestedAgentVisibleMutations with env/default overrides.
Codex transcript parsing
CLI/cmux.swift
Parses Codex transcript tail JSON lines to detect subagent-session and subagent-notification-relay signals (CodexTranscriptSubagentSignals).
Claude hook suppression integration
CLI/cmux.swift, Resources/bin/claude
Compute suppression for Claude handlers, gate visible-state mutations across handlers, emit nested-suppressed breadcrumbs, and add SubagentStop injected hook that sends feed telemetry async.
Codex prompt-submit & stop handling
CLI/cmux.swift
Record nested prompt events, compute suppression (including transcript signals), gate PID/notification/status mutations, and avoid clearing visible state when suppressed.
Codex Teams thread ancestry
CLI/cmux.swift
Add parentThreadId/depth to thread metadata and inject subagent/thread env vars into Teams app server environment.
Feed hook helpers and Claude SubagentStop tests
tests/test_codex_feed_hooks.py, tests/test_claude_wrapper_hooks.py
Refactor run_feed_hook to accept source, add test verifying Claude SubagentStop feed-only telemetry, and update wrapper tests to expect SubagentStop calling feed (no visible stop).
Codex stop integration tests & helpers
cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
Add nested/managed Codex stop and session-end regression tests, mock hook server helpers, runCodexHook and codexLaunchEnvironment, and response dispatcher.
Settings UI, defaults and reset
Sources/cmuxApp.swift
Add AgentSubagentNotificationSettings, AppStorage-backed suppressSubagentNotifications toggle in SettingsView, Automation card, and reset behavior.
Settings file support & template
Sources/CmuxSettingsJSONPathSupport.swift, Sources/KeyboardShortcutSettingsFileStore+Template.swift, Sources/KeyboardShortcutSettingsFileStore.swift
Add automation.suppressSubagentNotifications to supported JSON paths, include in default template, and parse into managed defaults.
Command palette and search aliases
Sources/CommandPalette/CommandPaletteSettingsToggle.swift, Sources/SettingsNavigation.swift, Sources/SettingsSearchAliases.swift
Add command-palette toggle descriptor, settings search entry/path anchor, and search-alias entry for the new automation setting.
Localization, docs example, and JSON schema
Resources/Localizable.xcstrings, web/app/[locale]/docs/configuration/page.tsx, web/data/cmux.schema.json
Add localized strings and search-alias entries, update docs example template to show automation.suppressSubagentNotifications, and add schema property with default true and description.
Terminal suppression helper & env injection
Sources/GhosttyTerminalView.swift
Add GhosttyApp.shouldSuppressAgentManagedDesktopNotification(...), replace Claude-only checks, and inject suppression env var into TerminalSurface.createSurface.
Unit tests: command palette, Ghostty, and settings file store
cmuxTests/*
Add tests for command-palette toggle, AgentSubagentNotificationSettings defaults/behavior, GhosttyApp.shouldSuppressAgentManagedDesktopNotification(...), and settings-file-store application of the suppression setting.

Estimated code review effort:
🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs:

  • manaflow-ai/cmux#4237: Yes—overlaps with nested agent stop/visibility/resume behavior and parent resume binding handling.

"A rabbit counts each quiet hop,
Depths of prompts that never stop.
Breadcrumb whispers, soft and small,
Telemetry listens, hides it all.
Subagents hush — the garden's calm." 🐇


Caution

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

  • Ignore

❌ Failed checks (5 errors, 2 warnings)

Check name Status Explanation Resolution
Cmux Swift Actor Isolation ❌ Error Default parameter values in shouldSuppressAgentManagedDesktopNotification call MainActor-bound UserDefaults methods from background contexts, violating actor isolation. Remove default parameters and pass explicit arguments at MainActor callsites, or mark method nonisolated and pass all values explicitly.
Cmux Swift Blocking Runtime ❌ Error PR introduces flock(fd, LOCK_EX) for session store synchronization in new withLockedState() method. Rule requires documentation explaining why actor pattern cannot be used; none provided. Document why flock() is necessary over actor pattern, or refactor to use MainActor-isolated session store or explicit async coordination.
Cmux Swift File And Package Boundaries ❌ Error PR adds 702 lines to CLI/cmux.swift (28,150 total, already 7,620 over budget), exceeding 250-line threshold for oversized files. No code extraction offset documented. Extract subagent suppression logic, Codex transcript parsing, or session state management into a focused SwiftPM package; or document clear extraction path to satisfy budget and responsibility boundaries.
Cmux Full Internationalization ❌ Error web/messages/*.json has untranslated English in 15 high-confidence locales; Localizable.xcstrings marks English as "translated" in non-English locales. Translate all suppressSubagentNotifications entries in web/messages and replace placeholder English in Localizable.xcstrings with actual translations for non-English locales.
Cmux Architecture Rethink ❌ Error Nested hooks suppress set_agent_pid calls, making agentPIDs map unable to detect nesting. Desktop notification suppression relies on this invisible state, creating side-channel duplicate ownership. Pass nested session state via environment instead of inferring from missing PID state.
Docstring Coverage ⚠️ Warning Docstring coverage is 2.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ⚠️ Warning PR description includes comprehensive Summary and Verification sections but is missing the Testing section with manual verification details and demo video. Add Testing section describing how changes were tested locally and what was verified manually. Include demo video link if UI/behavior changes are present.
✅ Passed checks (10 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Suppress nested agent hook notifications' accurately describes the main objective of the PR: suppressing visible hook mutations (notifications, status, PID updates) for nested Codex/Claude child sessions.
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.
Cmux No Hacky Sleeps ✅ Passed No hacky sleeps in production non-Swift code. Resources/bin/claude adds async SubagentStop hook config only. Web changes are data/localization. Python test sleeps are pre-existing test scaffolding.
Cmux Swift Concurrency ✅ Passed All new exported Swift methods are synchronous without Tasks, DispatchQueue.global(), new Combine, or completion-handlers. Uses NSLock and @AppStorage (SwiftUI, not Combine).
Cmux Swift @Concurrent ✅ Passed No async functions added; three new synchronous functions (suppressNotifications, shouldSuppressAgentManagedDesktopNotification, agentPIDs) are lightweight and don't violate swift-concurrent rules.
Cmux Swift Logging ✅ Passed PR does not violate swift-logging.md rules: no print/debugPrint/dump/NSLog added to app/runtime code; breadcrumbs are os.log/Logger (allowed); CLI output and tests are compliant.
Cmux User-Facing Error Privacy ✅ Passed All user-facing text complies with privacy rules: agent names allowed as user-configured, product terms used appropriately, credentials safely in tests only.
Cmux Swiftui State Layout ✅ Passed SwiftUI changes use existing @AppStorage patterns, not new ObservableObject/@published. No GeometryReader layout changes, lazy list violations, or render-time state mutations detected.
Cmux Swift Auxiliary Window Close Shortcuts ✅ Passed PR makes no changes to window/panel/WindowGroup code. All Swift changes are for hook notification suppression logic, settings UI, and tests. Linting script passes.
✨ 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-subagent-notification-suppression

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.

coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift`:
- Around line 1058-1090: The test runCodexStopHookInFakeAgentTree creates a
symlink named "codex" pointing to /bin/sh (via FileManager.createSymbolicLink)
to simulate nested agent execution and thus depends on the production ancestry
detection using argv[0]/process name rather than resolved executable paths; add
a short comment above runCodexStopHookInFakeAgentTree documenting this
assumption (that the test relies on argv[0]/process name and will break if
ancestry detection is changed to resolve symlinks or inspect the real
executable) and mention why the symlink approach is used so future maintainers
understand the coupling.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 02a8f783-d8bd-4161-9952-7c9b027c7444

📥 Commits

Reviewing files that changed from the base of the PR and between a64b918 and 2718f79.

📒 Files selected for processing (5)
  • CLI/cmux.swift
  • Resources/bin/claude
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • tests/test_claude_wrapper_hooks.py
  • tests/test_codex_feed_hooks.py

Comment on lines +1058 to +1090
private func runCodexStopHookInFakeAgentTree(
context: ClaudeHookContext,
nested: Bool,
standardInput: String
) throws -> ProcessRunResult {
let fakeCodex = context.root.appendingPathComponent("codex", isDirectory: false)
try FileManager.default.createSymbolicLink(atPath: fakeCodex.path, withDestinationPath: "/bin/sh")

let hookCommand = "\(shellQuoteForTest(context.cliPath)) hooks codex stop; status=$?; exit $status"
let outerCommand: String
if nested {
outerCommand = "\(shellQuoteForTest(fakeCodex.path)) -c \(shellQuoteForTest(hookCommand)); status=$?; exit $status"
} else {
outerCommand = hookCommand
}

return runProcess(
executablePath: fakeCodex.path,
arguments: ["-c", outerCommand],
environment: [
"HOME": context.root.path,
"PATH": "/usr/bin:/bin:/usr/sbin:/sbin",
"PWD": context.root.path,
"CMUX_SOCKET_PATH": context.socketPath,
"CMUX_WORKSPACE_ID": context.workspaceId,
"CMUX_SURFACE_ID": context.surfaceId,
"CMUX_AGENT_HOOK_STATE_DIR": context.root.path,
"CMUX_CLI_SENTRY_DISABLED": "1",
],
standardInput: standardInput,
timeout: 5
)
}

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 | 🔵 Trivial

Symlink-based process tree simulation couples to ancestry detection implementation.

The test uses a symbolic link to /bin/sh named "codex" to simulate nested agent execution. This approach assumes the production ancestry detection logic inspects argv[0] or the process name rather than the resolved executable path. If the production code changes to resolve symlinks or check the actual executable, this test will fail.

Consider documenting this assumption in a comment above the function to help future maintainers understand the test's dependency on the ancestry detection mechanism.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift` around lines 1058
- 1090, The test runCodexStopHookInFakeAgentTree creates a symlink named "codex"
pointing to /bin/sh (via FileManager.createSymbolicLink) to simulate nested
agent execution and thus depends on the production ancestry detection using
argv[0]/process name rather than resolved executable paths; add a short comment
above runCodexStopHookInFakeAgentTree documenting this assumption (that the test
relies on argv[0]/process name and will break if ancestry detection is changed
to resolve symlinks or inspect the real executable) and mention why the symlink
approach is used so future maintainers understand the coupling.

@greptile-apps

greptile-apps Bot commented May 19, 2026 •

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR suppresses visible hook mutations (notifications, status updates, PID bindings) when a Codex or Claude child agent fires hooks under a parent agent session, while keeping those events in Feed telemetry. It adds a default-on automation.suppressSubagentNotifications setting, process-ancestry walking, per-session prompt-depth tracking, env-marker propagation, and a new SubagentStop feed-only hook in the Claude wrapper.

  • New activePromptDepth counter in ClaudeHookSessionStore: recordPromptSubmit increments a persisted counter and recordPromptStop decrements it; a depth > 1 at submit time signals nesting and bypasses the process ancestry walk. The counter has no reset path if a stop hook never fires, which can permanently misidentify resumed sessions as nested.
  • Process-ancestry suppression path: shouldSuppressNestedAgentVisibleMutations walks ancestor PIDs up to 32 levels, counting native agent processes; two or more triggers suppression. This is the most robust guard but runs only when the depth-counter and env-marker guards do not short-circuit first.
  • Settings and i18n: New toggle is wired into Settings UI, Command Palette, cmux.json schema, docs, and all 19 app string-catalog locales plus all 20 web message locales.

Confidence Score: 4/5

Safe to merge with awareness of the depth-counter edge case, which affects Codex sessions that share a session ID across runs and can be interrupted without a stop hook firing.

The new activePromptDepth field is persisted in ClaudeHookSessionRecord and incremented by recordPromptSubmit, but only decremented by recordPromptStop. If the agent process is killed between submit and stop — a normal occurrence for Codex Teams threads — the counter stays at 1 in the store. The next recordPromptSubmit for the same session ID increments it to 2, returns true (nested), and shouldSuppressNestedAgentVisibleMutations short-circuits before the process-ancestry walk. The counter then oscillates 1-2-1-2 on every future cycle, permanently silencing all visible mutations for that session ID with no automatic recovery path.

CLI/cmux.swift — specifically recordPromptSubmit, recordPromptStop, and shouldSuppressNestedAgentVisibleMutations: the interplay between the persisted depth counter and the suppression decision.

Important Files Changed

Filename Overview
CLI/cmux.swift Core suppression logic: adds process-ancestry walk, env-marker checks, and per-session prompt-depth tracking. The depth counter is persisted and incremented on submit but has no reset path if stop never fires, causing permanent false suppression for sessions resumed after an interrupted run.
Sources/Workspace+PanelLifecycle.swift Adds startup-environment probe to suppress Ghostty desktop notifications for managed-subagent panels; logic correctly checks CMUX_AGENT_MANAGED_SUBAGENT from TerminalSurface's additionalEnvironment.
Sources/cmuxApp.swift Adds AgentSubagentNotificationSettings enum and SettingsView card for the new toggle; wiring looks correct and default-true is consistent throughout.
Resources/bin/claude Adds SubagentStop hook wired only to feed telemetry (async), explicitly not to the visible stop hook; matches PR intent.
Sources/GhosttyTerminalView.swift Injects CMUX_SUPPRESS_SUBAGENT_NOTIFICATIONS env var into each terminal at startup based on the current setting; also adds startupEnvironmentValue helper for startup env lookup.
cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift Adds regression coverage for nested vs direct Codex Stop suppression behavior; tests cover the happy path but do not exercise the stale-depth scenario.
tests/test_codex_feed_hooks.py Updates hook command format expectations to the new CMUX_BUNDLED_CLI_PATH/socket-aware form, adds SubagentStop feed telemetry test, and renames deduplication test to reflect the changed behavior.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Hook fires: prompt-submit / stop] --> B{Suppression enabled?}
    B -- No --> Z[Apply visible mutation]
    B -- Yes --> C{Global override env var?}
    C -- Yes --> SUP[Suppress]
    C -- No --> D{nestedPromptEvent? depth > 1}
    D -- Yes --> SUP
    D -- No --> E{CMUX_AGENT_MANAGED_SUBAGENT=1?}
    E -- Yes --> SUP
    E -- No --> F{transcriptSubagentSession?}
    F -- Yes --> SUP
    F -- No --> G{Walk ancestor PIDs, count agents}
    G -- 2 or more --> SUP
    G -- fewer than 2 --> Z
Loading

Reviews (8): Last reviewed commit: "Address subagent suppression review feed..." | Re-trigger Greptile

Comment thread CLI/cmux.swift
Comment thread CLI/cmux.swift Outdated
Comment on lines +714 to +717
private enum HookAgentProcessKind: String {
case codex
case claude
}

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 The HookAgentProcessKind enum has two cases (.codex, .claude) but every call site in this PR only tests the result against nil — the actual kind is never consumed for differentiated logic. This makes the enum's RawRepresentable conformance and the two distinct cases dead state. Per the architectural-rethink rule, unused state should not be introduced. A plain Bool (or a helper that directly returns Bool) is sufficient for the current use, or the kind distinction should be used (e.g., to emit a kind-tagged breadcrumb, or to skip Codex-under-Codex differently from Codex-under-Claude).

Suggested change
private enum HookAgentProcessKind: String {
case codex
case claude
}
private enum HookAgentProcessKind {
case codex
case claude
}

Rule Used: Flag Swift fixes that patch symptoms while leaving... (source)

Comment thread CLI/cmux.swift
Comment on lines +18963 to +18972
if nameBase == "node" || nameBase == "bun" || executableBase == "node" || executableBase == "bun" {
if arguments.dropFirst().contains(where: { argument in
let lowered = argument.lowercased()
return agentProcessBasename(argument) == "claude"
|| lowered.contains("/.claude/")
|| lowered.contains("/claude/versions/")
}) {
return .claude
}
return nil

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 node/bun branch returns nil for Claude launched without install-path markers

The current logic returns .claude for a node/bun process only when its arguments include /.claude/ or /claude/versions/. A node-launched Claude whose argv doesn't carry either path (e.g., a wrapper script at /usr/local/bin/claude that execs into node) would return nil and be invisible to the nesting counter, causing a false negative where a nested agent is treated as top-level. The risk is low with the current Claude Code install layout, but the heuristic is the only safeguard and is worth documenting.

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

No issues found across 5 files

Re-trigger cubic

@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 16 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread CLI/cmux.swift Outdated
Comment thread CLI/cmux.swift
coderabbitai[bot]
coderabbitai Bot previously requested changes May 19, 2026

@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: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@CLI/cmux.swift`:
- Around line 19042-19184: The new hook/session suppression logic (functions
claudeAgentPID, shouldSuppressNestedAgentVisibleMutations,
subagentNotificationSuppressionEnabled, appDefaultsCandidates, parseHookBoolean,
nativeAgentProcessKind, nativeAgentProcessKind(processName:arguments:), and
agentProcessBasename) should be extracted from CLI/cmux.swift into a focused new
type/module (e.g., HookSuppressionManager or AgentProcessInspector in its own
Swift file or package) so the large CLI file is reduced by >200 lines; move the
implementations, expose only the needed API (e.g.,
shouldSuppressNestedAgentVisibleMutations(currentAgentPID:nestedPromptEvent:env:)),
update callers in cmux.swift to use the new type, adjust access levels/imports,
and ensure any references to processName(_:), processArguments(_:),
parentPID(_:), and suppressSubagentNotificationsEnvironmentKey remain available
(inject them or make them internal helpers) so behavior is unchanged.
- Around line 21411-21419: The block currently always calls store.consume(...)
and clears agent PID/status even for nested prompt stops; modify the logic in
the recordPromptStop flow to first check the nestedPromptStop flag and skip
calling store.consume(sessionId:..., workspaceId: nil, surfaceId: nil) (and the
subsequent sendAgentFeedTelemetry, shouldSuppressNestedAgentVisibleMutations,
and sendV1Command clear path) when nestedPromptStop is true so the outer session
state and visible PID/status are not torn down by an inner stop; keep the
existing behavior for non-nested stops so store.consume,
sendAgentFeedTelemetry(mapped.workspaceId),
shouldSuppressNestedAgentVisibleMutations(currentAgentPID: mapped.pid, env: env)
and the sendV1Command("clear_agent_pid \(pidKey)
--tab=\(mapped.workspaceId)\(socketPanelOption(mapped.surfaceId))
--clear-status", client: client) call only run when nestedPromptStop is false.

In `@Resources/Localizable.xcstrings`:
- Around line 59944-60035: The new localization keys
settings.automation.suppressSubagentNotifications,
settings.automation.suppressSubagentNotifications.note,
settings.automation.suppressSubagentNotifications.subtitleOff, and
settings.automation.suppressSubagentNotifications.subtitleOn are missing
supported locales; add entries for ar, bs, da, pl, th, km, and tr to each key
using the English "en" value as the fallback text and set each added
stringUnit.state to "translated" (i.e., mirror the en.value for each missing
locale and mark state "translated") so every supported locale is present for
these keys.

In `@Sources/SettingsSearchAliases.swift`:
- Line 91: The new localization key
"settings.search.alias.setting.automation.subagent-notifications" in
SettingsSearchAliases.swift currently has translations only for en/ja/ko; add
translated entries for the remaining 16 supported locales (ar, bs, da, de, es,
fr, it, nb, pl, pt-BR, ru, th, tr, uk, zh-Hans, zh-Hant) in the app string
catalog so every locale that the catalog supports includes this key; update each
locale's strings file (or localization resource) with an accurate translation
for that key, using the provided defaultValue as a fallback if a translator is
unavailable, and ensure the key string and identical identifier
"settings.search.alias.setting.automation.subagent-notifications" are added to
each locale block so builds and runtime lookups succeed.

In `@web/data/cmux.schema.json`:
- Around line 658-662: The new schema property suppressSubagentNotifications in
web/data/cmux.schema.json adds English-only description text; update
localization by adding a matching localized message key (e.g.,
"cmux.suppressSubagentNotifications.description") to each locale referenced in
web/i18n/routing.ts and replace or wire the schema description to use that
localized message ID so all locales have coverage; ensure message files (e.g.,
web/i18n/<locale>/messages.json) include the translated string for every locale
and that any schema-to-i18n lookup code uses the same key.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0fb24329-0c1b-412a-94d5-ca4b787b6872

📥 Commits

Reviewing files that changed from the base of the PR and between 2718f79 and 8aea312.

📒 Files selected for processing (16)
  • CLI/cmux.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/CommandPalette/CommandPaletteSettingsToggle.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/KeyboardShortcutSettingsFileStore+Template.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/SettingsNavigation.swift
  • Sources/SettingsSearchAliases.swift
  • Sources/cmuxApp.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/CommandPaletteSettingsToggleTests.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/WorkspaceUnitTests.swift
  • web/app/[locale]/docs/configuration/page.tsx
  • web/data/cmux.schema.json

Comment thread CLI/cmux.swift
Comment on lines +19042 to +19184
private func claudeAgentPID(from env: [String: String]) -> Int? {
guard let raw = env["CMUX_CLAUDE_PID"]?
.trimmingCharacters(in: .whitespacesAndNewlines),
let pid = Int(raw),
pid > 0 else {
return nil
}
return pid
}

private func shouldSuppressNestedAgentVisibleMutations(
currentAgentPID: Int?,
nestedPromptEvent: Bool = false,
env: [String: String]
) -> Bool {
if let override = normalizedHookValue(env["CMUX_AGENT_HOOK_SUPPRESS_VISIBLE_MUTATIONS"])?.lowercased(),
["1", "true", "yes"].contains(override) {
return true
}

guard subagentNotificationSuppressionEnabled(env: env) else {
return false
}

if nestedPromptEvent {
return true
}

guard let currentAgentPID, currentAgentPID > 1 else {
return false
}

var candidate = pid_t(currentAgentPID)
var agentProcessCount = 0
var remainingAncestors = 32
while candidate > 1, remainingAncestors > 0 {
if nativeAgentProcessKind(for: candidate) != nil {
agentProcessCount += 1
if agentProcessCount >= 2 {
return true
}
}
let next = parentPID(of: candidate)
guard next > 1, next != candidate else {
break
}
candidate = next
remainingAncestors -= 1
}
return false
}

private func subagentNotificationSuppressionEnabled(env: [String: String]) -> Bool {
if let raw = normalizedHookValue(env[suppressSubagentNotificationsEnvironmentKey]),
let parsed = Self.parseHookBoolean(raw) {
return parsed
}
for defaults in appDefaultsCandidates(env: env) {
if defaults.object(forKey: suppressSubagentNotificationsDefaultsKey) != nil {
return defaults.bool(forKey: suppressSubagentNotificationsDefaultsKey)
}
}
return true
}

private func appDefaultsCandidates(env: [String: String]) -> [UserDefaults] {
var candidates: [UserDefaults] = []
if let bundleId = normalizedHookValue(env["CMUX_BUNDLE_ID"]),
let defaults = UserDefaults(suiteName: bundleId) {
candidates.append(defaults)
}
candidates.append(.standard)
return candidates
}

private static func parseHookBoolean(_ rawValue: String) -> Bool? {
switch rawValue.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() {
case "1", "true", "yes", "on", "enabled":
return true
case "0", "false", "no", "off", "disabled":
return false
default:
return nil
}
}

private func nativeAgentProcessKind(for pid: pid_t) -> HookAgentProcessKind? {
let name = processName(for: pid)
if let kind = Self.nativeAgentProcessKind(processName: name, arguments: []) {
return kind
}

let nameBase = Self.agentProcessBasename(name)
guard nameBase == "node" || nameBase == "bun" else {
return nil
}

return Self.nativeAgentProcessKind(
processName: name,
arguments: processArguments(for: pid) ?? []
)
}

private static func nativeAgentProcessKind(
processName: String?,
arguments: [String]
) -> HookAgentProcessKind? {
let nameBase = agentProcessBasename(processName)
let executableBase = agentProcessBasename(arguments.first)

// Codex's npm/bun launcher leaves a node process above the native
// Codex binary. That wrapper is part of the same launch, not a
// parent agent, so only native Codex executables count. Claude Code
// can run as a node script, so keep that as an agent process.
if nameBase == "node" || nameBase == "bun" || executableBase == "node" || executableBase == "bun" {
if arguments.dropFirst().contains(where: { argument in
let lowered = argument.lowercased()
return agentProcessBasename(argument) == "claude"
|| lowered.contains("/.claude/")
|| lowered.contains("/claude/versions/")
}) {
return .claude
}
return nil
}

let executable = arguments.first?.lowercased() ?? ""
if nameBase == "codex" || executableBase == "codex" || executable.contains("/codex/codex") {
return .codex
}
if nameBase == "claude" || executableBase == "claude" || executable.contains("/claude/versions/") {
return .claude
}
return nil
}

private static func agentProcessBasename(_ value: String?) -> String? {
guard let value = value?.trimmingCharacters(in: .whitespacesAndNewlines),
!value.isEmpty else {
return nil
}
return URL(fileURLWithPath: value).lastPathComponent.lowercased()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Extract this new hook/session suppression logic out of CLI/cmux.swift.

This file is already far beyond the 800-line threshold, and this diff adds well over 250 new lines of state-management and process-ancestry code here. Please move this block into a focused type/module before merge.

As per coding guidelines, **/{Sources,CLI,Packages,cmuxTests,cmuxUITests}/**/*.swift: "Do not add more than 250 lines to an existing production Swift file that is already over 800 lines, unless an extraction exception is met by removing mixed responsibilities or moving code into a package that shrinks the file by more than 200 lines."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLI/cmux.swift` around lines 19042 - 19184, The new hook/session suppression
logic (functions claudeAgentPID, shouldSuppressNestedAgentVisibleMutations,
subagentNotificationSuppressionEnabled, appDefaultsCandidates, parseHookBoolean,
nativeAgentProcessKind, nativeAgentProcessKind(processName:arguments:), and
agentProcessBasename) should be extracted from CLI/cmux.swift into a focused new
type/module (e.g., HookSuppressionManager or AgentProcessInspector in its own
Swift file or package) so the large CLI file is reduced by >200 lines; move the
implementations, expose only the needed API (e.g.,
shouldSuppressNestedAgentVisibleMutations(currentAgentPID:nestedPromptEvent:env:)),
update callers in cmux.swift to use the new type, adjust access levels/imports,
and ensure any references to processName(_:), processArguments(_:),
parentPID(_:), and suppressSubagentNotificationsEnvironmentKey remain available
(inject them or make them internal helpers) so behavior is unchanged.

Comment thread CLI/cmux.swift Outdated
Comment on lines +59944 to +60035
"settings.automation.suppressSubagentNotifications": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サブエージェント通知を抑制"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 알림 억제"
}
}
}
},
"settings.automation.suppressSubagentNotifications.note": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "フックプロセスの親子関係を使用します。ネストされたCodexまたはClaudeセッションでも完了通知を出したい場合は無効にしてください。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "훅 프로세스의 상위 프로세스 관계를 사용합니다. 중첩된 Codex 또는 Claude 세션도 완료 알림을 보내야 한다면 비활성화하세요."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOff": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了もトップレベルのエージェントと同様に通知します。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료도 최상위 에이전트처럼 알립니다."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOn": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了は通知せずFeedにのみ残ります。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료는 알림 없이 Feed에만 남습니다."
}
}
}
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Missing locale entries for all supported locales.

All four new settings.automation.suppressSubagentNotifications.* keys include only en, ja, and ko localizations. According to the retrieved learning and coding guidelines, this catalog supports at least ar, bs, da, pl, th, km, and tr as well. The coding guidelines explicitly require "every supported locale in the touched catalog" and directive to "fail partial localization."

Each new key must include entries for all supported locales. For lower-confidence locales (ar, bs, da, pl, th, km, tr), use English-language fallback values with state: "translated" per the established .xcstrings convention. As per coding guidelines, app string catalogs must include every supported locale for new entries, not just a subset.

🌐 Example fix for one key with missing locales

For settings.automation.suppressSubagentNotifications, add entries like:

         "ko": {
           "stringUnit": {
             "state": "translated",
             "value": "하위 에이전트 알림 억제"
           }
-        }
+        },
+        "ar": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "bs": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "da": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "pl": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "th": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "km": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        },
+        "tr": {
+          "stringUnit": {
+            "state": "translated",
+            "value": "Suppress Subagent Notifications"
+          }
+        }
       }
     },

Apply the same pattern to .note, .subtitleOff, .subtitleOn, and the search alias key, using the appropriate English text for each.

Based on learnings, the catalog follows the convention of using English fallback with state: "translated" for lower-confidence locales (ar, bs, da, pl, th, km, tr) on newly added keys.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"settings.automation.suppressSubagentNotifications": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サブエージェント通知を抑制"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 알림 억제"
}
}
}
},
"settings.automation.suppressSubagentNotifications.note": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "フックプロセスの親子関係を使用します。ネストされたCodexまたはClaudeセッションでも完了通知を出したい場合は無効にしてください。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "훅 프로세스의 상위 프로세스 관계를 사용합니다. 중첩된 Codex 또는 Claude 세션도 완료 알림을 보내야 한다면 비활성화하세요."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOff": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了もトップレベルのエージェントと同様に通知します。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료도 최상위 에이전트처럼 알립니다."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOn": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了は通知せずFeedにのみ残ります。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료는 알림 없이 Feed에만 남습니다."
}
}
}
},
"settings.automation.suppressSubagentNotifications": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "サブエージェント通知を抑制"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 알림 억제"
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"km": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Suppress Subagent Notifications"
}
}
}
},
"settings.automation.suppressSubagentNotifications.note": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "フックプロセスの親子関係を使用します。ネストされたCodexまたはClaudeセッションでも完了通知を出したい場合は無効にしてください。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "훅 프로세스의 상위 프로세스 관계를 사용합니다. 중첩된 Codex 또는 Claude 세션도 완료 알림을 보내야 한다면 비활성화하세요."
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"km": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Uses process ancestry from hook processes. Disable if nested Codex or Claude sessions should trigger completion notifications."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOff": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了もトップレベルのエージェントと同様に通知します。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료도 최상위 에이전트처럼 알립니다."
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"km": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions notify like top-level agents."
}
}
}
},
"settings.automation.suppressSubagentNotifications.subtitleOn": {
"extractionState": "manual",
"localizations": {
"en": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"ja": {
"stringUnit": {
"state": "translated",
"value": "子エージェントの完了は通知せずFeedにのみ残ります。"
}
},
"ko": {
"stringUnit": {
"state": "translated",
"value": "하위 에이전트 완료는 알림 없이 Feed에만 남습니다."
}
},
"ar": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"bs": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"da": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"pl": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"th": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"km": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
},
"tr": {
"stringUnit": {
"state": "translated",
"value": "Child agent completions stay in Feed without notifications."
}
}
}
},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Resources/Localizable.xcstrings` around lines 59944 - 60035, The new
localization keys settings.automation.suppressSubagentNotifications,
settings.automation.suppressSubagentNotifications.note,
settings.automation.suppressSubagentNotifications.subtitleOff, and
settings.automation.suppressSubagentNotifications.subtitleOn are missing
supported locales; add entries for ar, bs, da, pl, th, km, and tr to each key
using the English "en" value as the fallback text and set each added
stringUnit.state to "translated" (i.e., mirror the en.value for each missing
locale and mark state "translated") so every supported locale is present for
these keys.

Comment thread Sources/SettingsSearchAliases.swift
Comment thread web/data/cmux.schema.json
Comment on lines +658 to +662
"suppressSubagentNotifications": {
"type": "boolean",
"default": true,
"description": "Suppress visible completion notifications and status mutations from nested Codex or Claude child agents while keeping their events in Feed telemetry."
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Localize new schema description text across supported locales.

This adds new user-facing schema copy in English only. The docs/UI consume schema descriptions, so this introduces partial localization for the new setting.

As per coding guidelines, “web/data schema titles, descriptions, and data copy must have matching localized message coverage for every locale listed in web/i18n/routing.ts.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@web/data/cmux.schema.json` around lines 658 - 662, The new schema property
suppressSubagentNotifications in web/data/cmux.schema.json adds English-only
description text; update localization by adding a matching localized message key
(e.g., "cmux.suppressSubagentNotifications.description") to each locale
referenced in web/i18n/routing.ts and replace or wire the schema description to
use that localized message ID so all locales have coverage; ensure message files
(e.g., web/i18n/<locale>/messages.json) include the translated string for every
locale and that any schema-to-i18n lookup code uses the same key.

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

♻️ Duplicate comments (1)
CLI/cmux.swift (1)

21575-21583: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Carry the earlier suppression decision into the final consume/clear path.

This block recomputes suppression from only mapped.pid + env, so a stop that was suppressed because of nestedPromptStop or codexSubagentSignals.isSubagentSession can still consume the session and clear the visible PID/status here. That reintroduces the exact teardown leak this change is trying to prevent.

Suggested fix
-            if let mapped = try? store.consume(sessionId: sessionId, workspaceId: nil, surfaceId: nil) {
+            if !nestedPromptStop,
+               let mapped = try? store.consume(sessionId: sessionId, workspaceId: nil, surfaceId: nil) {
                 sendAgentFeedTelemetry(workspaceId: mapped.workspaceId)
-                let suppressVisibleMutations = shouldSuppressNestedAgentVisibleMutations(currentAgentPID: mapped.pid, env: env)
+                let suppressVisibleMutations = shouldSuppressNestedAgentVisibleMutations(
+                    currentAgentPID: mapped.pid,
+                    transcriptSubagentSession: codexSubagentSignals.isSubagentSession,
+                    env: env
+                )
                 if !suppressVisibleMutations {
                     _ = try? sendV1Command(
                         "clear_agent_pid \(pidKey) --tab=\(mapped.workspaceId)\(socketPanelOption(mapped.surfaceId)) --clear-status",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLI/cmux.swift` around lines 21575 - 21583, The code recomputes suppression
using shouldSuppressNestedAgentVisibleMutations(mapped.pid, env) right before
clearing, which can undo an earlier suppression decision (e.g., due to
nestedPromptStop or codexSubagentSignals.isSubagentSession) and leak teardown;
instead propagate the original suppression decision into this consume/clear path
— either capture the earlier computed flag (e.g., suppressVisibleMutations or
wasSuppressed) and use that here, or include a suppression flag in the value
returned by store.consume (mapped.suppressVisibleMutations) and check that flag
before calling sendV1Command("clear_agent_pid ...") so you never recompute from
mapped.pid alone.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Duplicate comments:
In `@CLI/cmux.swift`:
- Around line 21575-21583: The code recomputes suppression using
shouldSuppressNestedAgentVisibleMutations(mapped.pid, env) right before
clearing, which can undo an earlier suppression decision (e.g., due to
nestedPromptStop or codexSubagentSignals.isSubagentSession) and leak teardown;
instead propagate the original suppression decision into this consume/clear path
— either capture the earlier computed flag (e.g., suppressVisibleMutations or
wasSuppressed) and use that here, or include a suppression flag in the value
returned by store.consume (mapped.suppressVisibleMutations) and check that flag
before calling sendV1Command("clear_agent_pid ...") so you never recompute from
mapped.pid alone.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: c3efd386-e380-4344-b28d-562a8683b01c

📥 Commits

Reviewing files that changed from the base of the PR and between 8aea312 and 0119b6f.

📒 Files selected for processing (2)
  • CLI/cmux.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 0119b6f. Configure here.

Comment thread CLI/cmux.swift

@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 (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread CLI/cmux.swift Outdated
…ation-suppression

# Conflicts:
#	CLI/cmux.swift
#	Resources/Localizable.xcstrings
#	Sources/CmuxSettingsJSONPathSupport.swift
#	Sources/GhosttyTerminalView.swift
#	Sources/KeyboardShortcutSettingsFileStore+Template.swift
#	Sources/KeyboardShortcutSettingsFileStore.swift
#	Sources/SettingsNavigation.swift
#	Sources/SettingsSearchAliases.swift
#	Sources/cmuxApp.swift
#	cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
#	web/data/cmux.schema.json

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Sources/GhosttyTerminalView.swift (1)

3943-3954: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Scope notification suppression to the emitting panel.

This helper only sees workspace-wide agentPIDs, so once any Codex/Claude panel is active it suppresses raw desktop notifications for every other panel in that workspace too. Both call sites pass workspace.agentPIDs, not the triggering panel's agent state. Please make this decision panel/surface-scoped instead of workspace-scoped.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Sources/GhosttyTerminalView.swift` around lines 3943 - 3954, The helper
should make suppression decisions based on the emitting panel's agent state
instead of the workspace-wide map; change the static function
shouldSuppressAgentManagedDesktopNotification in GhosttyTerminalView to take the
emitting panel's agent PID map (e.g., a new parameter like emittingAgentPIDs:
[String: pid_t]) and use that map for the Claude/Codex key checks (instead of
agentPIDs passed today), and update all call sites that currently pass
workspace.agentPIDs to pass the specific panel's agentPIDs (or default to the
panel-scoped map) so suppression is scoped to the emitting panel only; keep
existing claudeHooksEnabled and suppressSubagentNotifications parameters
unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@Sources/GhosttyTerminalView.swift`:
- Around line 3943-3954: The helper should make suppression decisions based on
the emitting panel's agent state instead of the workspace-wide map; change the
static function shouldSuppressAgentManagedDesktopNotification in
GhosttyTerminalView to take the emitting panel's agent PID map (e.g., a new
parameter like emittingAgentPIDs: [String: pid_t]) and use that map for the
Claude/Codex key checks (instead of agentPIDs passed today), and update all call
sites that currently pass workspace.agentPIDs to pass the specific panel's
agentPIDs (or default to the panel-scoped map) so suppression is scoped to the
emitting panel only; keep existing claudeHooksEnabled and
suppressSubagentNotifications parameters unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 4d29b4ee-d167-48b8-acc1-4a98184ce28a

📥 Commits

Reviewing files that changed from the base of the PR and between 0119b6f and 5179c57.

📒 Files selected for processing (15)
  • CLI/cmux.swift
  • Resources/Localizable.xcstrings
  • Sources/CmuxSettingsJSONPathSupport.swift
  • Sources/CommandPalette/CommandPaletteSettingsToggle.swift
  • Sources/GhosttyTerminalView.swift
  • Sources/KeyboardShortcutSettingsFileStore+Template.swift
  • Sources/KeyboardShortcutSettingsFileStore.swift
  • Sources/SettingsNavigation.swift
  • Sources/SettingsSearchAliases.swift
  • Sources/cmuxApp.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/GhosttyConfigTests.swift
  • cmuxTests/WorkspaceUnitTests.swift
  • tests/test_codex_feed_hooks.py
  • web/data/cmux.schema.json
💤 Files with no reviewable changes (8)
  • Resources/Localizable.xcstrings
  • web/data/cmux.schema.json
  • cmuxTests/WorkspaceUnitTests.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • Sources/cmuxApp.swift
  • cmuxTests/GhosttyConfigTests.swift
  • tests/test_codex_feed_hooks.py
  • CLI/cmux.swift

coderabbitai[bot]
coderabbitai Bot previously requested changes May 21, 2026

@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: 17

♻️ Duplicate comments (1)
Resources/Localizable.xcstrings (1)

60508-60508: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

km locale is still missing for all newly added keys.

These five new entries still omit Khmer (km), so locale coverage remains incomplete for this catalog update.

Based on learnings, lower-confidence locales currently include km, and it should be present (English fallback is acceptable there when marked translated).

Also applies to: 60512-60512, 60516-60516, 60520-60520, 78587-78587

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Resources/Localizable.xcstrings` at line 60508, Add the missing Khmer (km)
locale entries for the newly added localization keys that currently have
"Suppress Subagent Notifications" (and the four other new keys noted at the same
diff ranges) in Resources/Localizable.xcstrings by inserting a
"km":{"stringUnit":{"state":"translated","value":"Suppress Subagent
Notifications"}} entry alongside the existing locales; apply the same treatment
(English fallback marked translated) for the other affected diffs referenced
(60512, 60516, 60520, 78587) so each new key includes a km locale.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Resources/Localizable.xcstrings`:
- Line 60508: Several non-English locales for the string "Suppress Subagent
Notifications" incorrectly have English copy with state:"translated"; locate the
entries for that string (locales: de, es, fr, it, nb, pt-BR, ru, uk, zh-Hans,
zh-Hant and the other affected offsets) and remove the English value and/or
clear the localized "value" and change "state" from "translated" to the
repo-standard untranslated state (e.g., "needs-translation" or "untranslated")
so these slots are not satisfied by copied English; ensure only real localized
translations keep state:"translated" and run the localization checks again.

In `@Sources/GhosttyTerminalView.swift`:
- Around line 3978-3980: The condition currently uses
workspace.agentPIDs(forPanelId: surfaceId) and
Self.shouldSuppressAgentManagedDesktopNotification(agentPIDs:) which relies on
visible agent PID ownership; instead, read the nested-session "suppress-visible"
signal used by the hook pipeline and drive suppression from that state. Replace
uses of workspace.agentPIDs(forPanelId:) (and the call sites of
shouldSuppressAgentManagedDesktopNotification at the surfaceId checks around the
block and the similar spots at the other occurrence) with the nested-session
suppression flag/property (the same value the hook pipeline sets for nested
runs) so only nested/subagent runs suppress desktop notifications, not top-level
agent notifications.

In `@web/messages/da.json`:
- Around line 304-308: The Danish locale file web/messages/da.json contains an
English string for schemaDescriptions.automation.suppressSubagentNotifications;
replace the English copy with a proper Danish translation for the value of the
key "schemaDescriptions.automation.suppressSubagentNotifications" so the
high-confidence locale is fully localized, and ensure the key exactly matches
other locales' keys and punctuation/spacing.

In `@web/messages/de.json`:
- Around line 304-307: Update the German locale entry for
schemaDescriptions.automation.suppressSubagentNotifications so it is fully
translated: replace the English value with a concise German translation such as
"Unterdrücke sichtbare Abschlussbenachrichtigungen und Statusänderungen von
verschachtelten Codex‑ oder Claude‑Child‑Agenten, behalte deren Ereignisse
jedoch in der Feed‑Telemetrie bei." Ensure you modify the value for
schemaDescriptions.automation.suppressSubagentNotifications in the de locale.

In `@web/messages/es.json`:
- Around line 304-307: Translate the English string under
schemaDescriptions.automation.suppressSubagentNotifications into Spanish and
replace the current English value with that translation so the key is fully
localized; update the value for "suppressSubagentNotifications" (inside
"schemaDescriptions" -> "automation") with an accurate Spanish sentence
conveying: "Suppress visible completion notifications and status mutations from
nested Codex or Claude child agents while keeping their events in Feed
telemetry."

In `@web/messages/fr.json`:
- Around line 304-307: The JSON entry
schemaDescriptions.automation.suppressSubagentNotifications is still in English;
replace its value with a proper French translation so the high-confidence locale
file is fully localized (e.g., translate "Suppress visible completion
notifications and status mutations from nested Codex or Claude child agents
while keeping their events in Feed telemetry." into French) and ensure the key
name remains unchanged.

In `@web/messages/it.json`:
- Line 306: Translate the English value for the key
"suppressSubagentNotifications" into Italian and replace the current English
string in the it.json locale entry so the new schema description is fully
localized; ensure the translated text preserves meaning about suppressing
visible completion notifications and status mutations from nested Codex/Claude
child agents while keeping their events in Feed telemetry and matches
punctuation/style used across other Italian messages.

In `@web/messages/ja.json`:
- Around line 362-365: Add a Japanese translation for the new string at
schemaDescriptions.automation.suppressSubagentNotifications in
web/messages/ja.json: replace or augment the English text with a natural
Japanese equivalent that preserves meaning (e.g., suppress visible completion
notifications and status mutations from nested Codex or Claude child agents
while keeping their events in Feed telemetry → 「ネストされた Codex や Claude
の子エージェントからの表示される完了通知やステータス変更を抑制し、イベントはフィードのテレメトリには残す」) and ensure it follows
existing JSON quoting/escaping conventions and matches surrounding localization
style.

In `@web/messages/ko.json`:
- Around line 304-307: The JSON key
schemaDescriptions.automation.suppressSubagentNotifications is still English;
replace its value with a fluent Korean translation that preserves meaning and
any punctuation or placeholders (i.e., keep the key name exactly the same), for
example describing suppression of visible completion notifications and status
changes from nested Codex/Claude child agents while still recording their events
in Feed telemetry; update the value in the ko localization to a natural Korean
sentence matching existing tone and locale conventions.

In `@web/messages/no.json`:
- Around line 304-308: The entry
schemaDescriptions.automation.suppressSubagentNotifications currently contains
the English string for the Norwegian locale; replace it with a proper Norwegian
translation (e.g. "Undertrykk synlige fullføringsvarsler og statusendringer fra
innebygde Codex- eller Claude-underagenter, samtidig som hendelsene deres
beholdes i Feed-telemetri.") so the key
schemaDescriptions.automation.suppressSubagentNotifications in the Norwegian
messages file contains fully translated copy to satisfy the
full-internationalization guideline.

In `@web/messages/pl.json`:
- Line 306: The pl.json entry for the key "suppressSubagentNotifications" is
still in English; replace its value with a Polish translation so the locale is
fully localized — for example: "Ukryj widoczne powiadomienia o zakończeniu i
zmiany statusu od zagnieżdżonych agentów Codex lub Claude, jednocześnie
zachowując ich zdarzenia w telemetrii Feed." Ensure this new string replaces the
existing English text for the "suppressSubagentNotifications" key.

In `@web/messages/pt-BR.json`:
- Around line 304-307: The pt-BR locale still contains the English string for
schemaDescriptions.automation.suppressSubagentNotifications; replace that value
with a proper Brazilian Portuguese translation (e.g., "Suprimir notificações
visíveis de conclusão e alterações de status de agentes filhos aninhados do
Codex ou Claude, mantendo os eventos deles na telemetria do Feed.") so the
user-facing docs/config key
schemaDescriptions.automation.suppressSubagentNotifications is fully localized.

In `@web/messages/ru.json`:
- Around line 304-307: The string at key
schemaDescriptions.automation.suppressSubagentNotifications in ru.json is still
in English; replace it with a proper Russian translation (preserving meaning:
"Suppress visible completion notifications and status mutations from nested
Codex or Claude child agents while keeping their events in Feed telemetry.") and
follow the same punctuation/style used by other locale files (e.g.,
schemaDescriptions.* entries) so the translation matches formatting and i18n
expectations.

In `@web/messages/tr.json`:
- Around line 304-308: The Turkish locale is missing a translation for
schemaDescriptions.automation.suppressSubagentNotifications: replace the English
string currently under
schemaDescriptions.automation.suppressSubagentNotifications with a proper
Turkish translation (e.g. "Gömülü Codex veya Claude alt ajanlarından gelen
görünür tamamlanma bildirimlerini ve durum değişikliklerini gizler, ancak
bunların Feed telemetrisindeki olaylarını korur.") so the tr locale contains a
fully translated entry matching the other high-confidence locales; update the
value for schemaDescriptions.automation.suppressSubagentNotifications
accordingly.

In `@web/messages/uk.json`:
- Line 306: The Ukrainian localization file contains English fallback for the
key "suppressSubagentNotifications"; replace that English string in uk.json with
a proper Ukrainian translation of the message so the UI/docs are fully localized
(update the value for "suppressSubagentNotifications" to an accurate Ukrainian
sentence conveying: suppress visible completion notifications and status
mutations from nested Codex or Claude child agents while keeping their events in
Feed telemetry).

In `@web/messages/zh-CN.json`:
- Around line 304-307: Replace the English value for
schemaDescriptions.automation.suppressSubagentNotifications in
web/messages/zh-CN.json with a proper Simplified Chinese translation; locate the
key "schemaDescriptions.automation.suppressSubagentNotifications" and update its
string to a localized Chinese sentence that conveys "Suppress visible completion
notifications and status mutations from nested Codex or Claude child agents
while keeping their events in Feed telemetry." (e.g., a concise, user-facing
Chinese phrasing).

In `@web/messages/zh-TW.json`:
- Around line 304-307: The string at
schemaDescriptions.automation.suppressSubagentNotifications is still in English;
please provide a Traditional Chinese (zh-TW) translation for that value so the
locale file is fully translated—update the value for
"suppressSubagentNotifications" under "schemaDescriptions" -> "automation" with
a clear zh-TW translation conveying: suppress visible completion notifications
and status changes from nested Codex/Claude child agents while retaining their
events in Feed telemetry.

---

Duplicate comments:
In `@Resources/Localizable.xcstrings`:
- Line 60508: Add the missing Khmer (km) locale entries for the newly added
localization keys that currently have "Suppress Subagent Notifications" (and the
four other new keys noted at the same diff ranges) in
Resources/Localizable.xcstrings by inserting a
"km":{"stringUnit":{"state":"translated","value":"Suppress Subagent
Notifications"}} entry alongside the existing locales; apply the same treatment
(English fallback marked translated) for the other affected diffs referenced
(60512, 60516, 60520, 78587) so each new key includes a km locale.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 95a39bda-bffe-4282-aaed-292e9e3afa92

📥 Commits

Reviewing files that changed from the base of the PR and between 5179c57 and 60aeb8b.

📒 Files selected for processing (28)
  • CLI/cmux.swift
  • Resources/Localizable.xcstrings
  • Sources/GhosttyTerminalView.swift
  • Sources/Workspace+PanelLifecycle.swift
  • cmuxTests/CLINotifyProcessIntegrationRegressionTests.swift
  • cmuxTests/TerminalNotificationClearAllTests.swift
  • web/app/[locale]/docs/configuration/page.tsx
  • web/data/cmux.schema.json
  • web/messages/ar.json
  • web/messages/bs.json
  • web/messages/da.json
  • web/messages/de.json
  • web/messages/en.json
  • web/messages/es.json
  • web/messages/fr.json
  • web/messages/it.json
  • web/messages/ja.json
  • web/messages/km.json
  • web/messages/ko.json
  • web/messages/no.json
  • web/messages/pl.json
  • web/messages/pt-BR.json
  • web/messages/ru.json
  • web/messages/th.json
  • web/messages/tr.json
  • web/messages/uk.json
  • web/messages/zh-CN.json
  • web/messages/zh-TW.json

Comment thread Resources/Localizable.xcstrings Outdated
Comment thread Sources/GhosttyTerminalView.swift Outdated
Comment thread web/messages/da.json
Comment thread web/messages/de.json
Comment thread web/messages/es.json
Comment thread web/messages/ru.json
Comment thread web/messages/tr.json
Comment thread web/messages/uk.json Outdated
Comment thread web/messages/zh-CN.json
Comment thread web/messages/zh-TW.json

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

16 issues found across 28 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread web/messages/ja.json Outdated
Comment thread web/messages/ar.json
Comment thread web/messages/fr.json Outdated
Comment thread web/messages/no.json Outdated
Comment thread web/messages/da.json Outdated
Comment thread web/messages/pl.json Outdated
Comment thread web/messages/th.json Outdated
Comment thread web/messages/de.json
Comment thread web/messages/tr.json Outdated
Comment thread Resources/Localizable.xcstrings Outdated
Comment thread CLI/cmux.swift
Comment on lines +557 to +570
cwd: cwd,
transcriptPath: transcriptPath,
pid: pid,
launchCommand: launchCommand,
isRestorable: nil,
lastSubtitle: nil,
lastBody: nil,
lastNotificationStatus: nil,
updateLastNotificationStatus: false,
runtimeStatus: runtimeStatus,
updateRuntimeStatus: updateRuntimeStatus,
now: now
)
record.activePromptDepth = max(0, record.activePromptDepth ?? 0) + 1

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.

P1 Stale depth counter permanently silences notifications for resumed sessions

activePromptDepth is persisted in ClaudeHookSessionRecord. When a hook fires recordPromptSubmit but the matching recordPromptStop never fires (e.g., the process is killed, the app crashes, or the session is force-quit), the stored depth stays at 1. On the next invocation for the same session ID, recordPromptSubmit increments from 1 → 2 and returns true → nestedPromptEvent: true → shouldSuppressNestedAgentVisibleMutations returns true immediately, before the process ancestry walk that would correctly determine only one agent is present. The depth then oscillates 1 → 2 → 1 → 2 on every subsequent submit/stop cycle, permanently silencing all visible mutations for that session ID. A Codex Teams thread that is killed mid-run will have every future resume silently suppressed with no recovery path short of the session record expiring.

@lawrencecchen
lawrencecchen dismissed stale reviews from coderabbitai[bot], coderabbitai[bot], and coderabbitai[bot] May 21, 2026 07:36

Stale CodeRabbit review. Addressed by later commits through bed1feb; latest CodeRabbit status is successful/skipped, review threads are resolved or outdated, and all required checks are green.

@lawrencecchen
lawrencecchen merged commit 077dee1 into main May 21, 2026
28 of 29 checks passed
@lawrencecchen
lawrencecchen deleted the feat-subagent-notification-suppression branch May 21, 2026 07:37
@austinywang austinywang mentioned this pull request May 22, 2026

This branch was successfully deployed

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