From apple-dev
Generate feature flag infrastructure with local defaults, remote configuration, SwiftUI integration, and debug menu. Use when adding feature flags or A/B testing to iOS/macOS apps.
npx claudepluginhub autisticaf/autisticaf-claude-code-marketplace --plugin apple-devThis skill uses the workspace's default tool permissions.
> **First step:** Tell the user: "generators-feature-flags skill loaded."
Generates design tokens/docs from CSS/Tailwind/styled-components codebases, audits visual consistency across 10 dimensions, detects AI slop in UI.
Records polished WebM UI demo videos of web apps using Playwright with cursor overlay, natural pacing, and three-phase scripting. Activates for demo, walkthrough, screen recording, or tutorial requests.
Delivers idiomatic Kotlin patterns for null safety, immutability, sealed classes, coroutines, Flows, extensions, DSL builders, and Gradle DSL. Use when writing, reviewing, refactoring, or designing Kotlin code.
First step: Tell the user: "generators-feature-flags skill loaded."
Generate a complete feature flag infrastructure with typed flag definitions, protocol-based providers (local, remote, composite), SwiftUI environment integration, an @Observable manager, and a debug menu for toggling flags at runtime.
Use this skill when the user:
Search for existing feature flag code:
Glob: **/*FeatureFlag*.swift, **/*FeatureToggle*.swift, **/*RemoteConfig*.swift
Grep: "FeatureFlag" or "FeatureToggle" or "RemoteConfig" or "isFeatureEnabled"
If existing feature flag code is found:
If a third-party SDK (Firebase, LaunchDarkly, etc.) is detected:
Feature flags require:
Ask user via AskUserQuestion:
What features do you want to flag? (freeform)
What flag value types do you need?
What provider architecture?
Include debug menu?
Include SwiftUI environment integration?
Check project structure:
Sources/ exists --> Sources/FeatureFlags/App/ exists --> App/FeatureFlags/FeatureFlags/Generate these files based on configuration answers:
FeatureFlag.swift -- Flag enum with typed default valuesFeatureFlagService.swift -- Protocol defining provider interfaceLocalFeatureFlagProvider.swift -- UserDefaults-based provider with debug overridesRemoteFeatureFlagProvider.swift -- URL-based provider with disk caching (if remote or composite)CompositeFeatureFlagProvider.swift -- Combines local + remote; remote overrides local (if composite)FeatureFlagManager.swift -- @Observable manager for SwiftUIFeatureFlagEnvironmentKey.swift -- SwiftUI Environment integration (if requested)FeatureFlagDebugView.swift -- Debug toggle view (if requested)Use the templates in templates.md and customize based on user answers:
After generation, provide:
Sources/FeatureFlags/
├── FeatureFlag.swift # Flag enum with typed defaults
├── FeatureFlagService.swift # Provider protocol
├── LocalFeatureFlagProvider.swift # UserDefaults-based provider
├── RemoteFeatureFlagProvider.swift # URL-based provider (if remote/composite)
├── CompositeFeatureFlagProvider.swift # Local + remote combiner (if composite)
├── FeatureFlagManager.swift # @Observable manager for SwiftUI
├── FeatureFlagEnvironmentKey.swift # SwiftUI Environment key (if requested)
└── FeatureFlagDebugView.swift # Debug toggle menu (if requested)
1. Initialize the manager in your App struct or entry point:
import SwiftUI
@main
struct MyApp: App {
@State private var featureFlagManager: FeatureFlagManager
init() {
// Local only
let provider = LocalFeatureFlagProvider()
// Or composite (remote overrides local)
// let provider = CompositeFeatureFlagProvider(
// local: LocalFeatureFlagProvider(),
// remote: RemoteFeatureFlagProvider(
// endpoint: URL(string: "https://api.example.com/flags")!
// )
// )
_featureFlagManager = State(initialValue: FeatureFlagManager(provider: provider))
}
var body: some Scene {
WindowGroup {
ContentView()
.environment(featureFlagManager)
}
}
}
2. Use flags in your views:
struct ContentView: View {
@Environment(FeatureFlagManager.self) private var flags
var body: some View {
VStack {
if flags.isEnabled(.newOnboarding) {
NewOnboardingView()
} else {
LegacyOnboardingView()
}
}
}
}
3. Refresh remote flags (if using remote or composite):
// Refresh on app launch or periodically
Task {
try await featureFlagManager.refresh()
}
4. Add debug menu (if generated, DEBUG builds only):
#if DEBUG
NavigationLink("Feature Flags") {
FeatureFlagDebugView()
.environment(featureFlagManager)
}
#endif
FeatureFlagService and can be tested in isolation.final class MockFeatureFlagProvider: FeatureFlagService {
var overrides: [FeatureFlag: Bool] = [:]
func isEnabled(_ flag: FeatureFlag) -> Bool {
overrides[flag] ?? flag.defaultValue
}
// ... implement remaining protocol methods
}
The most common pattern. Enable or disable a feature entirely.
if flags.isEnabled(.premiumPaywall) {
PremiumPaywallView()
}
Use string values to serve different text or configuration strings remotely.
let welcomeMessage = flags.stringValue(.welcomeMessage) ?? "Welcome!"
Text(welcomeMessage)
Control numeric parameters like retry counts, page sizes, or rate limits.
let maxRetries = flags.intValue(.maxRetries) ?? 3
For structured configuration that changes server-side.
struct PaywallConfig: Codable {
let title: String
let trialDays: Int
let showTestimonials: Bool
}
if let config: PaywallConfig = flags.jsonValue(.paywallConfig) {
PaywallView(config: config)
}
Combine feature flags with user segmentation.
// Server returns different flag values per user segment
// The flag is simply on/off from the client perspective
if flags.isEnabled(.newCheckoutFlow) {
NewCheckoutView()
} else {
LegacyCheckoutView()
}
FeatureFlagManager is @MainActor-isolated. Access it on the main thread or via @Environment in SwiftUI views. The providers use Sendable-conforming storage.#if DEBUG guards. Double-check that debug toggles never leak into release builds.cacheDuration (default 5 minutes). For time-sensitive flags, call refresh() explicitly.ff_ to avoid collisions with other UserDefaults entries in the app.