-
Notifications
You must be signed in to change notification settings - Fork 1
Architecture
Christopher Murphy edited this page Feb 22, 2026
·
3 revisions
Last Updated: February 2026 Version: 1.0.14
Aegis is a macOS menu bar application that integrates with Yabai window manager to provide:
- Visual workspace/space indicators in the menu bar
- Notch-area HUD for system status (volume, brightness, media, Bluetooth devices, Focus mode)
- System status display (battery, network, Focus mode, time)
- Window management via drag-drop and gestures
- Custom app switcher (Cmd+Tab replacement)
- Multi-display support with configurable modes
- Event-driven: EventRouter pub/sub decouples services from UI
- Persistent ViewModels: ViewModels survive view rebuilds for smooth animations
- Frame-locked animation: CVDisplayLink for vsync-driven progress bars
- Window lifecycle: Windows created once at startup, reused throughout session
- Configuration-driven: Centralized AegisConfig singleton for all customization
Aegis/
├── App/ # Application entry point
├── Core/ # Configuration and services
│ ├── Config/ # Centralized settings
│ ├── Models/ # Core data models
│ └── Services/ # Business logic services
├── Components/ # UI components
│ ├── MenuBar/ # Workspace indicator UI
│ ├── Notch/ # Notch HUD system
│ ├── Systemstatus/ # System monitoring UI
│ └── SettingsPanel/ # Settings interface
├── Helpers/ # Shared utilities
└── AegisYabaiIntegration/ # Shell scripts
- SwiftUI app entry point
- Registers AppDelegate for lifecycle management
- Provides Settings window
-
Responsibilities:
- Initialize all services (Yabai, SystemInfo, Music)
- Create EventRouter and inject into services
- Setup MenuBar and Notch components
- Subscribe to events and route to UI
- Request automation permissions
- Check and show setup prompt if needed
-
Purpose: Centralized configuration singleton
-
Scope: 100+ @Published properties for every UI/behavior setting
-
Categories:
- Menu bar layout (height, padding, spacing, corner radii)
- Space indicators (size, icon display, overflow behavior)
- Typography (font sizes for labels, values, headers)
- Animation settings (spring response, damping, durations)
- System status thresholds (battery levels, WiFi strength)
- Notch HUD (size, position, progress bar dimensions)
- Color schemes and opacity values
-
Persistence: UserDefaults for settings recovery across launches
-
Access Pattern: All views use
@ObservedObject private var config = AegisConfig.shared
-
Purpose: Pub/sub event bus decoupling services from UI
-
Events:
-
.spaceChanged: Workspace switched -
.windowsChanged: Window added/removed/moved -
.volumeChanged: System volume adjusted -
.brightnessChanged: Display brightness adjusted -
.musicPlaybackChanged: Music track changed
-
-
Thread Safety: All handler calls dispatched to main thread
- Purpose: Interface to Yabai window manager
-
Responsibilities:
- Query spaces and windows
- Execute commands (focus, move, create, destroy)
- Monitor Yabai events via FIFO pipe
- Provide window icons from app bundles
- Purpose: Monitor hardware state (volume, brightness, battery)
-
Components:
- Volume: CoreAudio API for system volume and mute state
- Brightness: Private API via Objective-C helper
- Battery: IOKit for battery level, charging state, time remaining
- Purpose: Integrate with media sources for now-playing display
-
Capabilities:
- Query current track (title, artist, album) from any media source
- Fetch album artwork asynchronously
- Detect playback state (playing/paused)
- Works with Music.app, Spotify, browsers, video players, etc.
- Purpose: Monitor Bluetooth device connections/disconnections
-
Capabilities:
- Detect device connect/disconnect events via IOBluetooth
- Identify device types (AirPods, keyboards, mice, etc.)
- Fetch battery levels via system_profiler
- Purpose: Custom Cmd+Tab window switcher
-
Capabilities:
- Intercept Cmd+Tab via CGEvent tap
- Display windows organized by space
- Multiple input methods: keyboard, mouse hover, two-finger scroll
- Type-to-filter search
Purpose: Display Yabai workspaces as interactive indicators
MenuBarController (Facade)
↓
MenuBarCoordinator (Orchestrator)
↓ creates
MenuBarWindowController (Window management)
MenuBarViewModel (State)
MenuBarInteractionMonitor (Native menu bar tracking)
↓ renders
SpaceIndicatorView (UI)
- DisplayMenuBarManager.swift: Manages menu bars across multiple displays
- MenuBarCoordinator.swift: Central orchestrator for a single display
- MenuBarViewModel.swift: State management with @Published properties
- SpaceIndicatorView.swift: Main UI view for workspace display
- SpaceDropController.swift: Drag-drop delegate for moving windows
DisplayMenuBarManager (Multi-display orchestrator)
↓ creates one per display
MenuBarCoordinator (Per-display orchestrator)
↓ with display-specific
MenuBarViewModel (spaceFilterMode: .display(index))
↓ renders filtered
SpaceIndicatorView (Only spaces for this display)
Display detection:
-
NSApplication.didChangeScreenParametersNotificationfor high-level changes -
CGDisplayRegisterReconfigurationCallbackfor instant, granular detection - Supports add/remove/move/setMain display events
Multi-monitor modes:
- Auto: Single display = primary only, multiple = per monitor
- Primary Only: Menu bar only on main display
- Per Monitor: Each display shows only its own spaces
- All Show All: Every display shows all spaces
Purpose: Display system notifications at notch location
NotchHUDController (Window + visibility management)
↓ owns
OverlayHUDViewModel (Volume/brightness state)
↓ contains
ProgressBarAnimator (Frame-locked interpolation)
↓ renders
MinimalHUDWrapper (UI)
NotchHUDController
↓ also owns
MediaHUDViewModel → MediaHUDView (Now Playing)
DeviceHUDViewModel → DeviceHUDView (Bluetooth devices)
FocusHUDViewModel → FocusHUDView (Focus mode)
- Frame-locked interpolation for smooth progress bar
- Uses
CVDisplayLinkfor vsync-driven callbacks (60Hz) - Exponential smoothing:
displayed += (target - displayed) * 0.35
- Displays album art and either visualizer or track info
- Marquee scrolling for long text
- Works with all media sources via MediaRemote framework
- Shows Bluetooth device connections/disconnections
- Battery ring indicator
- Supports AirPods, headphones, keyboards, mice, etc.
- Shows Focus mode changes
- Displays mode name and icon from user's configuration
Purpose: Display system information in menu bar
SystemStatusMonitor (Aggregates all status)
↓
BatteryStatusMonitor (Battery specific)
NetworkStatus (Network model)
FocusStatusMonitor (Focus mode detection)
↓
SystemStatusView (Container)
↓
Individual icon views (Battery, Network, Focus, Clock, Date)
- Watches
~/Library/DoNotDisturb/DB/for Focus mode changes - Parses Assertions.json to detect active Focus mode
- Reads ModeConfigurations.json for mode names and SF Symbols
User presses volume key
↓
SystemInfoService detects change (CoreAudio listener)
↓
EventRouter.publish(.volumeChanged, level: 0.75)
↓
AppDelegate subscription fires
↓
NotchHUDController.showVolume(level: 0.75)
↓
overlayViewModel.progressAnimator.setTarget(0.75)
↓
CVDisplayLink ticks at 60Hz (vsync)
↓
ProgressBarAnimator interpolates displayed value
↓
SwiftUI re-renders progress bar
User switches space (Yabai command)
↓
Yabai writes event to FIFO pipe
↓
YabaiService reads pipe, parses event
↓
EventRouter.publish(.spaceChanged)
↓
MenuBarCoordinator subscription fires
↓
MenuBarCoordinator.updateSpaces()
↓
SpaceIndicatorView re-renders with new active state
- CVDisplayLink provides vsync-driven interpolation independent of main thread
- Coalescing with
updatePendingflag prevents SwiftUI re-render storms - Bypass ViewModel updates during rapid input
- Windows created once at startup, reused throughout session
-
isReleasedWhenClosed = falseprevents deallocation - Force layout pass before first show prevents jank
- FIFO pipe provides real-time Yabai events
- EventRouter decouples services from UI
- Fallback polling every 10s if pipe unavailable
- ViewModels owned by controllers, survive view rebuilds
- ProgressBarAnimator instance persists in ViewModel
- State survives SwiftUI view invalidation
-
Communication: Shell commands via
Process -
Event Monitoring: FIFO pipe at
~/.config/aegis/yabai.pipe - Setup: User configures yabairc to write events to pipe
- Communication: MediaRemote framework via mediaremote-adapter
- Sources: Music.app, Spotify, Safari, Chrome, Firefox, video players, etc.
- Queries: Current track, playback state, bundle identifier
- Artwork: Fetched asynchronously, cached per-track
- CoreAudio: Volume level and mute state
- CoreGraphics: Display reconfiguration callbacks for monitor detection
- IOKit: Battery status
- IOBluetooth: Device connection/disconnection notifications
- Private API: Brightness monitoring
- AppKit: Window management, screen geometry
- DispatchSource: File system monitoring for Focus mode changes
| Component | Files | Total Lines (approx) |
|---|---|---|
| App | 2 | 200 |
| Core/Config | 2 | 1,800 |
| Core/Services | 6 | 1,600 |
| MenuBar | 13 | 2,500 |
| Notch | 12 | 1,200 |
| Systemstatus | 12 | 900 |
| SettingsPanel | 3 | 1,500 |
| Total | ~50 | ~9,700 |
| File | Purpose |
|---|---|
AppDelegate.swift |
App initialization, service setup, event routing |
AegisConfig.swift |
Centralized configuration singleton |
AegisConfigFile.swift |
JSON config file support with hot-reload |
EventRouter.swift |
Pub/sub event bus |
YabaiService.swift |
Yabai WM integration |
BluetoothDeviceService.swift |
Bluetooth device monitoring |
AppSwitcherService.swift |
Custom Cmd+Tab window switcher |
DisplayMenuBarManager.swift |
Multi-display menu bar management |
MenuBarCoordinator.swift |
Per-display menu bar orchestration |
SpaceIndicatorView.swift |
Workspace UI display |
NotchHUDController.swift |
Notch HUD window management |
ProgressBarAnimator.swift |
Frame-locked interpolation |
MediaHUDView.swift |
Now Playing UI |
DeviceHUDView.swift |
Bluetooth device HUD |
FocusStatusMonitor.swift |
Focus mode detection |