# How vorssaint-utils Handles macOS Accessibility Permissions: Inside the TCC Singleton

> Discover how vorssaint-utils manages macOS TCC accessibility permissions with its Permissions singleton. Learn about live-polling and automatic SwiftUI updates.

- Repository: [vorssaint/vorssaint-utils](https://github.com/vorssaint/vorssaint-utils)
- Tags: internals
- Published: 2026-09-09

---

**vorssaint-utils centralizes all macOS Transparency, Consent, and Control (TCC) permission handling in a single `Permissions` singleton that live-polls system state, prompts users once per TCC reset, and automatically updates SwiftUI views via `@Published` properties.**

Managing macOS Accessibility permissions in a Swift macOS application requires careful coordination between system APIs, user interface state, and background service availability. The vorssaint-utils repository solves this challenge through a centralized permission architecture that abstracts the complexity of macOS TCC into a reactive, observable singleton. This approach ensures that features requiring Accessibility access—such as scroll inversion and window activation—remain synchronized with the system's current permission grant status.

## Centralized Permission Management in Permissions.swift

### The ObservableObject Pattern

At the core of vorssaint-utils lies the `Permissions` class in [`Sources/Vorssaint/Core/Permissions.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Core/Permissions.swift), which conforms to `ObservableObject` to provide reactive state management. The singleton exposes **published properties** including `accessibility` and `screenRecording` that automatically propagate changes to SwiftUI views throughout the application. This design eliminates the need for scattered permission checks across view models and service layers.

### Live Polling Architecture

When active features require Accessibility access, the permissions system enters a polling state via `scheduleActivePermissionPolling()`. This method creates a `Timer` whose interval is dynamically computed from `desiredPollInterval` based on currently required features. The timer fires only when permission-aware features become active, minimizing system overhead while ensuring real-time accuracy.

## Fast Permission Checks and System Integration

### Low-Overhead State Verification

The `refreshActivePermissions()` method performs lightweight permission validation using native macOS APIs. For Accessibility status, the implementation calls `AXIsProcessTrusted()`, while screen recording checks use `CGPreflightScreenCaptureAccess()`. These calls execute on the main queue and update the published properties, triggering immediate UI updates when permission states change.

### User-Initiated Permission Requests

When users enable features requiring Accessibility access through the UI, the system invokes `requestAccessibility()`. This method constructs a dictionary containing `kAXTrustedCheckOptionPrompt` and passes it to `AXIsProcessTrustedWithOptions()`, displaying the system prompt once per TCC reset. If the user denies access, the system presents `PermissionGuideOverlay` to provide contextual guidance.

## System Settings Integration and Feature Gating

### Deep-Linking to Privacy Preferences

The `openAccessibilitySettings()` method streamlines manual permission granting by constructing a URL with the scheme `x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility` and opening it via `NSWorkspace`. This deep-link navigates users directly to the Accessibility pane in Privacy & Security settings, reducing friction in the permission workflow.

### Service-Level Feature Gating

Throughout the codebase, services guard their functionality using `Permissions.shared.accessibility`. For example, [`ScrollInverter.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ScrollInverter.swift) and [`WindowActivator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/WindowActivator.swift) check this property before executing Accessibility-dependent operations. In [`SettingsView.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/SettingsView.swift), UI toggles for brightness and OSD features automatically trigger `requestAccessibility()` when users attempt to enable them, ensuring the system prompt appears at the point of need.

## Implementation Example

```swift
// Check current permission status
if Permissions.shared.accessibility {
    // Execute Accessibility-dependent logic
    scrollInverter.enable()
}

// Request permission with system prompt
Permissions.shared.requestAccessibility()

// Open System Settings if previously denied
Permissions.shared.openAccessibilitySettings()

```

These patterns appear throughout the codebase, particularly in [`SettingsView.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/SettingsView.swift) where brightness toggles invoke permission requests, and in service files that guard core logic with `Permissions.shared.accessibility` checks.

## Summary

- vorssaint-utils consolidates macOS TCC management in the `Permissions` singleton located at [`Sources/Vorssaint/Core/Permissions.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/Sources/Vorssaint/Core/Permissions.swift)
- The system uses `AXIsProcessTrusted()` for fast checks and `AXIsProcessTrustedWithOptions()` for user prompts, updating `@Published` properties reactively
- Live polling via `scheduleActivePermissionPolling()` ensures real-time state synchronization without excessive resource consumption
- Deep-link integration via `openAccessibilitySettings()` directs users straight to Privacy & Security preferences
- Services like `ScrollInverter` and `WindowActivator` gate functionality using `Permissions.shared.accessibility` checks

## Frequently Asked Questions

### How does vorssaint-utils check if Accessibility permissions are granted?

The system calls `AXIsProcessTrusted()` in the `refreshActivePermissions()` method to perform lightweight, non-blocking permission checks. This updates the `@Published` properties, triggering reactive UI updates across the application.

### What happens when a user denies the Accessibility permission prompt?

If `requestAccessibility()` detects an ungranted state after prompting, it displays `PermissionGuideOverlay` to guide users toward manually enabling the permission. Users can then invoke `openAccessibilitySettings()`, which launches System Settings directly to the Accessibility pane.

### How does the permission system handle app lifecycle events?

The `Permissions` initializer registers for `NSApplication.didBecomeActiveNotification` and `UserDefaults.didChangeNotification`, triggering `refresh()` when the app returns from background or when relevant preferences change. This ensures UI state remains synchronized with system permissions when users return from manually adjusting settings.

### Which vorssaint-utils features require macOS Accessibility permissions?

Features including the scroll inverter ([`ScrollInverter.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/ScrollInverter.swift)), window activation ([`WindowActivator.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/WindowActivator.swift)), and brightness/OSD controls all depend on Accessibility access. These components check `Permissions.shared.accessibility` before executing and automatically request permission when users enable related toggles in [`SettingsView.swift`](https://github.com/vorssaint/vorssaint-utils/blob/main/SettingsView.swift).