# cmux Notification System Architecture: Technical Deep Dive into manaflow-ai/cmux

> Explore the cmux notification system architecture a three-layer reactive stack. Learn how TerminalNotificationStore bridges CLI commands to SwiftUI with intelligent spam prevention.

- Repository: [manaflow-ai/cmux](https://github.com/manaflow-ai/cmux)
- Tags: deep-dive
- Published: 2026-03-29

---

**The cmux notification system architecture implements a three-layer reactive stack where `TerminalNotificationStore` serves as the central hub, bridging CLI socket commands through macOS `UNUserNotificationCenter` to SwiftUI interface components, with intelligent suppression logic that prevents notification spam when the user is focused on the target terminal panel.**

The cmux notification system architecture enables seamless integration between terminal multiplexing workflows and macOS notification infrastructure. As implemented in the `manaflow-ai/cmux` repository, this design pattern coordinates socket-based CLI entry points, reactive state management, and system-level notification delivery through a centralized store that maintains consistency across menu bar indicators, sidebar badges, and system alerts.

## Three-Layer Architecture Overview

### Model and Store Layer

At the foundation lies the **Model & Store** layer responsible for data persistence and state management. The `TerminalNotification` struct defines the notification data model, while the `TerminalNotificationStore` singleton acts as the single source of truth for the entire cmux notification system architecture.

The store maintains the `notifications` array and manages read/unread states that drive UI elements including the sidebar badge indicators and menu bar pop-over content. As observed by SwiftUI views throughout the application, any mutation to the store immediately triggers interface updates across the workspace sidebar and title-bar accessories.

### System Integration Layer

The **System Integration** layer handles macOS-specific notification infrastructure and permission management. This layer implements the `ensureAuthorization` method (lines 1266-1284 in [`Sources/TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalNotificationStore.swift)) to request and monitor notification permissions, routing users to System Settings via `openNotificationSettings` when access is denied.

The `scheduleUserNotification` method (lines 1019-1034) constructs `UNMutableNotificationContent` instances and posts requests to `UNUserNotificationCenter`. This layer also implements intelligent suppression logic—when cmux is the foreground application focused on the notification's target tab, the system skips external delivery while still executing `suppressedNotificationFeedbackHandler` (lines 1337-1344) to play sounds and custom commands without displaying system alerts.

### UI and Entry Points Layer

The **UI & Entry Points** layer exposes three distinct interaction patterns. **CLI commands** including `cmux notify`, `notify_surface`, and `notify_target` parse socket requests in [`Sources/TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalController.swift) (lines 1708-1715) and route them to the store's `addNotification` method.

The **Menu and Pop-over** interface utilizes `showNotificationsPopover()` defined in [`Sources/cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/cmuxApp.swift) (lines 139-150), while individual notification rows render through the `NotificationPopoverRow` struct in [`Sources/Update/UpdateTitlebarAccessory.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/Update/UpdateTitlebarAccessory.swift) (lines 1140-1195). The **Sidebar Badge** system queries `notificationStore.unreadCount(forTabId:)` to color workspace indicators according to unread notification counts.

## Notification Flow Pipeline

### Step 1: CLI and Socket Entry

Notifications originate through socket commands parsed in [`TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalController.swift). The controller implements three entry points:

- `notifyCurrent(args)` for general notifications
- `notifySurface` for surface-specific alerts  
- `notifyTarget` for targeted delivery

These methods transform command-line arguments into calls to `TerminalNotificationStore.shared.addNotification(...)`.

### Step 2: Store Insertion and Deduplication

The `addNotification(tabId:surfaceId:title:subtitle:body:)` method (lines 93-114 in [`TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalNotificationStore.swift)) handles core insertion logic. The store first deduplicates existing notifications for the same tab/surface combination, then determines whether the target panel is currently focused.

If focused, the store calls `setFocusedReadIndicator` to mark the notification as contextually read. The new `TerminalNotification` instance prepends to the `notifications` array, triggering SwiftUI observation updates.

### Step 3: Delivery Decision and System Integration

Following insertion, the store evaluates `shouldSuppressExternalDelivery`. When suppression is active—indicating the user already views the relevant terminal panel—the architecture routes to `suppressedNotificationFeedbackHandler`, playing the selected sound via `NotificationSoundSettings.sound()` and executing any custom commands without generating system notifications.

For background or unrelated panels, `notificationDeliveryHandler` invokes `scheduleUserNotification`, which ensures authorization before constructing and posting the `UNNotificationRequest` to macOS notification centers.

### Step 4: UI Synchronization

SwiftUI views observe `TerminalNotificationStore.notifications` through property wrappers. The **menu bar** utilizes `NotificationMenuSnapshotBuilder` referenced in [`cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/cmuxApp.swift) to list recent items, while the **title-bar pop-over** renders entries via `NotificationPopoverRow` with accessibility identifiers formatted as `NotificationPopoverRow.<UUID>` for UI testing purposes.

## Advanced Features and Configuration

### Permission Handling Workflow

When authorization status is denied or undetermined, cmux displays modal prompts directing users to System Settings. The `ensureAuthorization(origin: .notificationDelivery)` callback pattern ensures graceful degradation when permissions are unavailable, preventing application crashes while maintaining functionality for local sound and command execution.

### Custom Sounds and Command Execution

The `NotificationSoundSettings` struct (lines 32-58) manages audio preferences and custom command execution. Users configure system sounds, custom audio files staged in `~/Library/Sounds`, or shell commands that execute on every notification via `NotificationSoundSettings.runCustomCommand`. All sound preparation runs off-main to preserve UI responsiveness.

### Dock Badge Composition

The `dockBadgeLabel` property (lines 57-74) generates badge strings formatted as `<tag>:<count>`, respecting the optional tagged run badge setting. This provides at-a-glance unread counts directly on the application dock icon without requiring users to open the notification panel.

## Key Source Files

- **[`Sources/TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalNotificationStore.swift)** – Central store implementation, `UNUserNotificationCenter` integration, permission flow, and `TerminalNotification` model definition.
- **[`Sources/TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalController.swift)** – Socket and CLI entry points for `notify`, `notify_surface`, and `notify_target` commands (lines 1708-1715).
- **[`Sources/cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/cmuxApp.swift)** – SwiftUI application entry point, menu item definitions, and pop-over trigger logic (lines 139-150).
- **[`Sources/Update/UpdateTitlebarAccessory.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/Update/UpdateTitlebarAccessory.swift)** – Title-bar notification pop-over UI and `NotificationPopoverRow` view implementation (lines 1140-1195).

## Practical Implementation Examples

```swift
// CLI routing in TerminalController.swift
case "notify":
    return notifyCurrent(args)          // Routes to TerminalNotificationStore.shared.addNotification(...)

```

```swift
// Core store insertion with delivery logic
func addNotification(tabId: UUID, surfaceId: UUID?, title: String, subtitle: String, body: String) {
    // Deduplication logic for existing tab/surface notifications...
    let isFocusedPanel = /* App-focus and tab-focus evaluation */
    if isFocusedPanel { setFocusedReadIndicator(forTabId: tabId, surfaceId: surfaceId) }
    
    let notification = TerminalNotification(id: UUID(), tabId: tabId, surfaceId: surfaceId, 
                                          title: title, subtitle: subtitle, body: body, 
                                          timestamp: Date(), isRead: false)
    
    notifications = [notification] + notifications   // Prepend to array
    
    if shouldSuppressExternalDelivery {               
        suppressedNotificationFeedbackHandler(self, notification)  // UI-only feedback
    } else {
        notificationDeliveryHandler(self, notification)            // System notification
    }
}

```

```swift
// System notification scheduling implementation
private func scheduleUserNotification(_ notification: TerminalNotification) {
    ensureAuthorization(origin: .notificationDelivery) { authorized in
        guard authorized else { return }
        let content = UNMutableNotificationContent()
        content.title = resolvedNotificationTitle(for: notification)
        content.subtitle = notification.subtitle
        content.body = notification.body
        content.sound = NotificationSoundSettings.sound()
        content.categoryIdentifier = Self.categoryIdentifier
        // Tab and surface IDs attached to userInfo for routing...
        
        let request = UNNotificationRequest(
            identifier: notification.id.uuidString,
            content: content,
            trigger: nil)
            
        self.center.add(request) { _ in
            NotificationSoundSettings.runCustomCommand(
                title: content.title,
                subtitle: content.subtitle,
                body: content.body)
        }
    }
}

```

```swift
// SwiftUI pop-over row with accessibility support
struct NotificationPopoverRow: View {
    let notification: TerminalNotification
    
    var body: some View {
        Button(action: { openNotification(notification) }) {
            HStack {
                Image(systemName: "bell")
                VStack(alignment: .leading) {
                    Text(notification.title).bold()
                    Text(notification.body).lineLimit(2)
                }
            }
        }
        .accessibilityIdentifier("NotificationPopoverRow.\(notification.id.uuidString)")
    }
}

```

## Summary

- The cmux notification system architecture separates concerns across three distinct layers: Model & Store, System Integration, and UI Entry Points.
- `TerminalNotificationStore` functions as the central reactive hub, implementing the `ObservableObject` pattern to synchronize state between CLI commands and SwiftUI interfaces.
- Intelligent suppression logic in `shouldSuppressExternalDelivery` prevents notification spam when users actively view the target terminal panel, while still executing custom commands and sounds.
- File-specific implementations in [`TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalController.swift) (CLI), [`TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalNotificationStore.swift) (macOS integration), and [`UpdateTitlebarAccessory.swift`](https://github.com/manaflow-ai/cmux/blob/main/UpdateTitlebarAccessory.swift) (UI) create a testable, maintainable notification pipeline.

## Frequently Asked Questions

### How does cmux prevent notification spam when the terminal is already focused?

The architecture implements focus-aware suppression in [`TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalNotificationStore.swift) (lines 1337-1344). When `shouldSuppressExternalDelivery` evaluates to true—indicating the application is frontmost and the target tab is active—cmux routes notifications through `suppressedNotificationFeedbackHandler` instead of `notificationDeliveryHandler`. This executes custom sounds and commands without posting to `UNUserNotificationCenter`, keeping the UI quiet while the user already views the relevant content.

### Which source file handles CLI notification commands?

Socket and CLI parsing for notification commands resides in [`Sources/TerminalController.swift`](https://github.com/manaflow-ai/cmux/blob/main/Sources/TerminalController.swift) (lines 1708-1715). This file implements `notifyCurrent`, `notifySurface`, and `notifyTarget` methods that parse arguments from socket clients and route them to `TerminalNotificationStore.shared.addNotification(...)`, serving as the primary entry point for programmatic notification generation.

### How are custom notification sounds and commands configured?

The `NotificationSoundSettings` struct within [`TerminalNotificationStore.swift`](https://github.com/manaflow-ai/cmux/blob/main/TerminalNotificationStore.swift) (lines 32-58) manages audio selection and command execution. Users select system sounds, custom audio files from `~/Library/Sounds`, or shell scripts that execute via `NotificationSoundSettings.runCustomCommand`. All audio preparation runs on background queues to prevent main-thread blocking, ensuring the terminal interface remains responsive during notification processing.

### Where is the notification pop-over UI implemented in the codebase?

The title-bar notification pop-over renders through [`UpdateTitlebarAccessory.swift`](https://github.com/manaflow-ai/cmux/blob/main/UpdateTitlebarAccessory.swift) (lines 1140-1195), specifically via the `NotificationPopoverRow` struct. This SwiftUI view generates accessible list items with identifiers formatted as `NotificationPopoverRow.<UUID>`, while the parent container `showNotificationsPopover()` in [`cmuxApp.swift`](https://github.com/manaflow-ai/cmux/blob/main/cmuxApp.swift) (lines 139-150) manages the pop-over presentation state and positioning relative to the menu bar.