Install any skill in seconds. Free to start, no credit card required.
Get Started Free →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.
.claude/skills/rshankras-feature-flags/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-12 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-14 | ✗→✓ | ▲ Improved | 77% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 95% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 67% | 0% |
| case-22 | ✗→✓ | ▲ Improved | 159% | 0% |
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:
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:
swiftimport 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:
swiftstruct 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):
swift// Refresh on app launch or periodically Task { try await featureFlagManager.refresh() }
4. Add debug menu (if generated, DEBUG builds only):
swift#if DEBUG NavigationLink("Feature Flags") { FeatureFlagDebugView() .environment(featureFlagManager) } #endif
FeatureFlagService and can be tested in isolation.swift final class MockFeatureFlagProvider: FeatureFlagService { var overrides: FeatureFlag: Bool] = :]
func isEnabled(_ flag: FeatureFlag) -> Bool { overridesflag] ?? flag.defaultValue } // ... implement remaining protocol methods }
The most common pattern. Enable or disable a feature entirely.
swiftif flags.isEnabled(.premiumPaywall) { PremiumPaywallView() }
Use string values to serve different text or configuration strings remotely.
swiftlet welcomeMessage = flags.stringValue(.welcomeMessage) ?? "Welcome!" Text(welcomeMessage)
Control numeric parameters like retry counts, page sizes, or rate limits.
swiftlet maxRetries = flags.intValue(.maxRetries) ?? 3
For structured configuration that changes server-side.
swiftstruct 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.
swift// 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.Other measured skills in the registry, with their headline benchmark lift.