How to Manage User Roles and Permissions in Palmier Pro: A Complete Guide
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 and the account tier enforcement mechanisms in 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. The AgentMessage.Role enum is Codable and supports two cases:
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:
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 defines four distinct permission levels:
none: No AI generation allowed; only local editing permittedfree: Limited AI usage with exhaustible creditspro: Full AI generation with paid creditsmax: 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:
if account.isPaid {
// Show AI generation UI
} else {
// Show upgrade prompt
}
Upgrading and Downgrading Subscriptions
The subscription management UI resides in AccountPane.swift. Users upgrade their tier by calling account.subscribe(tier:), which communicates with the backend via the Convex client and updates the AccountService:
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:
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:
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:
import PalmierPro
func upgrade(to tier: AccountTier) async {
await AccountService.shared.subscribe(tier: tier)
}
Summary
- Agent roles (
userandassistant) defined inAgentService.swiftcontrol conversation flow but do not enforce permissions. - Account tiers (
none,free,pro,max) defined inAccountService.swiftgate feature access based on subscription status. - Use
account.isPaidoraccount.tierchecks to restrict AI generation features to appropriate users. - Upgrade subscriptions programmatically using
AccountService.shared.subscribe(tier:), which updates the@Bindableaccount model and refreshes the UI automatically. - Reference
AccountPane.swiftfor 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 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 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →