# How to Configure Palmier Pro Settings: A Complete Guide to the macOS Preferences Window

> Master Palmier Pro settings with this guide. Learn how to configure preferences and specific tabs programmatically using `SettingsWindowController.shared.show()` for efficient macOS app management.

- Repository: [Palmier/palmier-pro](https://github.com/palmier-io/palmier-pro)
- Tags: how-to-guide
- Published: 2026-06-22

---

**To configure Palmier Pro settings programmatically, invoke `SettingsWindowController.shared.show()` to open the preferences window, or navigate directly to a specific tab using `SettingsWindowController.shared.show(tab: .models)`.**

The open-source Palmier Pro repository implements its preferences system as a native macOS window hosting a SwiftUI view hierarchy. Understanding how to configure Palmier Pro settings requires familiarity with the `SettingsWindowController` singleton and the modular pane architecture defined in `Sources/PalmierPro/Settings/`. Whether you are customizing the UI for a fork or adding new configuration options, the architecture provides a consistent pattern for extending preferences.

## Settings Architecture Overview

Palmier Pro’s preferences window is built around a **sidebar-detail** pattern managed by three core components defined in [`SettingsView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/SettingsView.swift).

### SettingsTab Enum

The `SettingsTab` enum provides stable identifiers for each configuration pane:

```swift
enum SettingsTab {
    case account
    case general
    case models
    case agent
    case storage
}

```

This enum drives both the sidebar selection and the detail view routing, ensuring type-safe navigation between preference categories.

### SettingsWindowController Singleton

The `SettingsWindowController` class inherits from `NSWindowController` and manages the window lifecycle as a singleton:

```swift
// Located in Sources/PalmierPro/Settings/SettingsView.swift
final class SettingsWindowController: NSWindowController {
    static let shared = SettingsWindowController()
    
    func show(tab: SettingsTab? = nil) {
        // Creates NSWindow with dark-aqua appearance
        // Injects SettingsView via NSHostingController
    }
}

```

When `show()` is called, it instantiates an `NSWindow` with a fixed content size and dark-aqua appearance, then injects the `SettingsView` SwiftUI hierarchy via an `NSHostingController`.

### SettingsView Structure

The `SettingsView` struct contains two subviews: `SettingsSidebar` (rendering `SidebarRowButton` items) and `SettingsDetail` (wrapping the active pane in a `ScrollView`). The sidebar dynamically filters available tabs—for example, hiding the **Account** tab when account configuration is missing.

## Opening the Settings Window Programmatically

Palmier Pro exposes a simple API for opening the Settings window from any part of the codebase, used in [`AppDelegate.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AppDelegate.swift) and [`TourOverlay.swift`](https://github.com/palmier-io/palmier-pro/blob/main/TourOverlay.swift).

### Show the Default Tab

To open the Settings window on the default **Account** tab:

```swift
// From anywhere in the app
SettingsWindowController.shared.show()

```

This is the pattern used in `AppDelegate.showSettings(_:)` for the menu command.

### Navigate to a Specific Tab

To configure Palmier Pro settings by jumping directly to a functional area:

```swift
// Open directly on the General tab (Notifications & Privacy)
SettingsWindowController.shared.show(tab: .general)

// Open on the Models tab for LLM configuration
SettingsWindowController.shared.show(tab: .models)

// Open on the Storage tab to manage cache limits
SettingsWindowController.shared.show(tab: .storage)

```

These calls are utilized in the onboarding tour ([`TourOverlay.swift`](https://github.com/palmier-io/palmier-pro/blob/main/TourOverlay.swift)) to guide users to specific configuration screens contextually.

### Observing Settings Changes

To react programmatically when a user modifies preferences, observe the underlying service via `NotificationCenter`:

```swift
// Example: React to notification preference changes
NotificationCenter.default.addObserver(
    forName: .AppNotificationsDidChange,
    object: nil,
    queue: .main
) { _ in
    // Update UI or reschedule background tasks
}

```

The individual panes use `onChange` handlers to wire UI controls (like `SettingsToggleRow`) back to services such as `AppNotifications` and `Telemetry`.

## Individual Settings Panes

Each functional area is implemented as a separate SwiftUI view in `Sources/PalmierPro/Settings/`, following consistent theming from [`AppTheme.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AppTheme.swift).

### Account and Subscription

The [`AccountPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountPane.swift) file contains the subscription management interface and credit UI, binding to `AccountService.shared` via `@Bindable` to propagate account state changes.

### Notifications and Privacy

**NotificationsPane.swift** and **PrivacyPane.swift** handle system-level toggles:

- **Notifications**: Controls `notificationsEnabled` state, persisted via `AppNotifications`
- **Privacy**: Manages `telemetryEnabled` and crash-reporting preferences

Both use the `SettingsToggleRow` component with consistent spacing defined in `AppTheme.Spacing`.

### Models and Agent Configuration

The **ModelsPane** ([`ModelsPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/ModelsPane.swift)) provides LLM selection and API key configuration, while **AgentPane** ([`AgentPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AgentPane.swift)) contains agent-specific behavioral preferences. These panes interact with model configuration services and validate inputs before persisting to `UserDefaults` or secure storage.

### Storage Management

**StoragePane.swift** implements disk cache limits and cleanup controls, allowing users to configure maximum cache size and manually purge temporary files downloaded by the editor.

## Extending Settings with Custom Panes

To add a new **Appearance** pane with a dark-mode toggle, follow the established pattern in the Palmier Pro source code:

1. **Extend the enum** in [`SettingsView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/SettingsView.swift):

```swift
enum SettingsTab {
    case account
    case general
    case models
    case agent
    case storage
    case appearance  // New case
}

```

2. **Create the pane** in [`AppearancePane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AppearancePane.swift):

```swift
import SwiftUI

struct AppearancePane: View {
    @State private var darkMode = (NSApp.effectiveAppearance.name == .darkAqua)

    var body: some View {
        VStack(alignment: .leading, spacing: AppTheme.Spacing.md) {
            SettingsToggleRow(
                title: "Dark mode",
                subtitle: "Force the UI to use a dark appearance.",
                isOn: $darkMode
            )
            .onChange(of: darkMode) { _, newValue in
                NSApp.appearance = newValue 
                    ? NSAppearance(named: .darkAqua) 
                    : NSAppearance(named: .aqua)
            }

            Divider()
                .overlay(AppTheme.Border.subtleColor)
        }
    }
}

```

3. **Wire into SettingsDetail** in [`SettingsView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/SettingsView.swift):

```swift
switch selectedTab {
case .appearance:
    AppearancePane()
// existing cases...
}

```

The `SettingsSidebar` automatically displays the new tab without additional code, as it iterates over applicable `SettingsTab` cases.

## Key Implementation Files

When configuring Palmier Pro settings or extending the preferences system, reference these source files:

- **[`Sources/PalmierPro/Settings/SettingsView.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/SettingsView.swift)** – Main UI, `SettingsWindowController`, `SettingsTab` enum
- **[`Sources/PalmierPro/Settings/AccountPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/AccountPane.swift)** – Account management and subscription UI
- **[`Sources/PalmierPro/Settings/NotificationsPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/NotificationsPane.swift)** – System notification toggles
- **[`Sources/PalmierPro/Settings/PrivacyPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/PrivacyPane.swift)** – Telemetry and crash reporting
- **[`Sources/PalmierPro/Settings/ModelsPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/ModelsPane.swift)** – LLM configuration and model selection
- **[`Sources/PalmierPro/Settings/AgentPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/AgentPane.swift)** – Agent behavior preferences
- **[`Sources/PalmierPro/Settings/StoragePane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Settings/StoragePane.swift)** – Cache limits and disk management
- **[`Sources/PalmierPro/UI/AppTheme.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/UI/AppTheme.swift)** – Design tokens for consistent spacing, colors, and typography
- **[`Sources/PalmierPro/App/AppDelegate.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/App/AppDelegate.swift)** – Menu command integration for opening Settings
- **[`Sources/PalmierPro/Editor/Tour/TourOverlay.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Editor/Tour/TourOverlay.swift)** – Example of programmatic Settings navigation

## Summary

- **Entry Point**: Use `SettingsWindowController.shared.show(tab:)` to open the preferences window from any context, with `SettingsTab` providing type-safe navigation to Account, General, Models, Agent, or Storage panes.
- **Architecture**: The Settings window is a native `NSWindow` managed by `SettingsWindowController`, containing a SwiftUI hierarchy with a sidebar (`SettingsSidebar`) and detail view (`SettingsDetail`).
- **Customization**: Each functional area is a separate pane (`AccountPane`, `NotificationsPane`, etc.) using shared `AppTheme` constants and `SettingsToggleRow` components for consistency.
- **Extension**: Adding new preferences requires extending `SettingsTab`, creating a SwiftUI view following the pane pattern, and adding a case to `SettingsDetail`.
- **State Management**: Changes propagate via `@Bindable` for model objects and `@State` for local UI state, with `onChange` handlers persisting to underlying services.

## Frequently Asked Questions

### How do I open Palmier Pro settings from a menu item?

Use `SettingsWindowController.shared.show()` in your menu action handler. This is exactly how [`AppDelegate.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AppDelegate.swift) implements the **Preferences...** menu command, creating a singleton window with dark-aqua appearance and injecting the `SettingsView` hierarchy.

### Can I programmatically navigate to a specific settings tab?

Yes. Call `SettingsWindowController.shared.show(tab: .models)` (or `.account`, `.general`, `.storage`, `.agent`) to open the window directly on that pane. This pattern is used in the onboarding tour to guide users to configuration screens contextually.

### Where are Palmier Pro settings stored?

Individual panes persist data to different backends: `AccountService` handles authentication state, `AppNotifications` and `Telemetry` manage boolean toggles, and `StoragePane` interacts with the file system for cache management. The UI uses `@Bindable` and `@State` to reflect these underlying stores in real-time.

### How do I add a new toggle to the settings window?

Create a new pane file (e.g., [`CustomPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/CustomPane.swift)), use the `SettingsToggleRow` component with `AppTheme` spacing, and wire it into `SettingsDetail` by adding a case to the `SettingsTab` enum. The `SettingsSidebar` automatically includes new tabs without additional code changes.