# How to Manage User Roles and Permissions in Palmier Pro: A Complete Guide

> Master user roles and permissions in Palmier Pro. Learn to control chat flow with agent roles and manage feature access through account tiers for seamless administration.

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

---

**Palmier Pro implements a dual permission system where agent conversation roles (`user` and `assistant`) control chat flow, while account tiers (`none`, `free`, `pro`, `max`) enforce feature access through `AccountService` checks.**

Palmier Pro uses a sophisticated access control architecture that distinguishes between AI conversation participants and subscription-based capabilities. To effectively manage user roles and permissions in Palmier Pro, you must navigate both the agent messaging system defined in [`AgentService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AgentService.swift) and the account tier enforcement mechanisms in [`AccountService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountService.swift). This guide examines the actual source code implementation to show you exactly how these systems work together.

## Understanding Agent Conversation Roles

Agent roles determine how the backend processes messages in the AI conversation flow. These are distinct from account permissions and only control the messaging protocol between the user and the assistant.

### Role Definitions in AgentService.swift

The AI assistant layer models each chat message with a role property defined in [`AgentService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AgentService.swift). The `AgentMessage.Role` enum is `Codable` and supports two cases:

```swift
enum Role: String, Codable {
    case user
    case assistant
}

```

This enum determines how the backend treats each message. For example, the system requires a `user` role before the assistant can generate a reply.

### Usage in AnthropicRequestBody

When building requests to the Anthropic API, the role converts directly to its string representation (`"user"` or `"assistant"`). The request builder in `AnthropicRequestBody` embeds these role strings into the API payload to maintain proper conversation context.

UI code typically inspects `msg.role` to decide when to insert synthetic user messages or display tool use buttons:

```swift
if messages[next].role == .user {
    // Handle user message logic
}

```

## Managing Account Permission Tiers

Account permissions in Palmier Pro are subscription-based. The signed-in user's tier determines which features are available, including AI generation capabilities.

### The AccountTier Enum Structure

The `AccountTier` enum in [`AccountService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountService.swift) defines four distinct permission levels:

- **`none`**: No AI generation allowed; only local editing permitted
- **`free`**: Limited AI usage with exhaustible credits
- **`pro`**: Full AI generation with paid credits
- **`max`**: Highest-capacity plan with increased credits and priority access

The enum provides helper properties including `isPaid` and `planLabel` to simplify UI logic.

### Checking Permissions with isPaid

Most feature gates throughout the app check `account.isPaid` or directly inspect `account.tier`. The `AccountService` exposes the current tier through `AccountService.shared.tier`, which reflects the user's active plan (`account.tier`).

For example, the AI generation button uses this check to conditionally render:

```swift
if account.isPaid {
    // Show AI generation UI
} else {
    // Show upgrade prompt
}

```

### Upgrading and Downgrading Subscriptions

The subscription management UI resides in [`AccountPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountPane.swift). Users upgrade their tier by calling `account.subscribe(tier:)`, which communicates with the backend via the Convex client and updates the `AccountService`:

```swift
Button("Upgrade to Pro") {
    Task { await account.subscribe(tier: .pro) }
}

```

When the subscription changes, `AccountService` refreshes its `tier` property and posts the new value to the UI via the `@Bindable` property wrapper, ensuring immediate interface updates.

## Practical Implementation Examples

### Detecting Message Roles

To handle messages based on their conversation role:

```swift
import PalmierPro

func handle(message: AgentMessage) {
    switch message.role {
    case .user:
        // User-initiated request – queue for AI processing
        processUserMessage(message)
    case .assistant:
        // Assistant reply – display in UI
        displayAssistantMessage(message)
    }
}

```

### Restricting Features to Paid Users

Implement tier-based feature gates in SwiftUI views:

```swift
import PalmierPro

struct GenerateButton: View {
    @Bindable var account = AccountService.shared

    var body: some View {
        if account.isPaid {
            Button("Generate AI") {
                // Invoke AI generation
            }
            .buttonStyle(.capsule(.prominent, size: .regular))
        } else {
            Text("Upgrade to unlock AI generation")
                .foregroundStyle(AppTheme.Text.secondaryColor)
        }
    }
}

```

### Programmatic Tier Upgrades

Handle subscription changes programmatically:

```swift
import PalmierPro

func upgrade(to tier: AccountTier) async {
    await AccountService.shared.subscribe(tier: tier)
}

```

## Summary

- **Agent roles** (`user` and `assistant`) defined in [`AgentService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AgentService.swift) control conversation flow but do not enforce permissions.
- **Account tiers** (`none`, `free`, `pro`, `max`) defined in [`AccountService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountService.swift) gate feature access based on subscription status.
- Use `account.isPaid` or `account.tier` checks to restrict AI generation features to appropriate users.
- Upgrade subscriptions programmatically using `AccountService.shared.subscribe(tier:)`, which updates the `@Bindable` account model and refreshes the UI automatically.
- Reference [`AccountPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountPane.swift) for the complete subscription management interface implementation.

## Frequently Asked Questions

### What is the difference between agent roles and account tiers in Palmier Pro?

Agent roles (`user` and `assistant`) are conversation flow markers defined in `AgentMessage.Role` that determine how messages are processed in the AI pipeline. Account tiers (`none`, `free`, `pro`, `max`) are subscription levels defined in `AccountTier` that enforce business logic and feature availability. Roles control *how* the system talks; tiers control *what* the system allows.

### How do I check if a user has paid access programmatically?

Access the `isPaid` property on the shared account instance: `AccountService.shared.isPaid`. This boolean checks the underlying `tier` property and returns `true` for `pro` and `max` tiers while returning `false` for `none` and `free`. For more granular control, inspect `AccountService.shared.tier` directly against specific `AccountTier` cases.

### Where are subscription upgrades handled in the codebase?

Subscription upgrades are initiated in [`AccountPane.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountPane.swift) through the `subscribe(tier:)` method on `AccountService`. This async method communicates with the Convex backend, processes the payment or plan change, and updates the local `AccountService` state, which automatically propagates to all `@Bindable` UI observers.

### Can I create custom permission tiers beyond pro and max?

The current implementation in [`AccountService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/AccountService.swift) defines a fixed enumeration with four cases (`none`, `free`, `pro`, `max`). Adding custom tiers would require modifying the `AccountTier` enum and updating the corresponding backend logic that validates subscription states. The `isPaid` property logic would also need adjustment to recognize any new paid tiers.