skills/generators/debug-menu/SKILL.md
Generates a developer debug menu with feature flag toggles, environment switching, network log viewer, cache clearing, crash trigger, and diagnostic info export. Only included in DEBUG builds. Use when user wants a debug panel, dev tools menu, or shake-to-debug functionality.
npx skillsauth add rshankras/claude-code-apple-skills debug-menuInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Generate a comprehensive developer debug menu accessible via shake gesture or hidden tap. Includes feature flag toggles, environment switching, network log viewer, cache clearing, crash trigger, and diagnostic info export. All code is wrapped in #if DEBUG so it never ships to production.
Use this skill when the user:
Search for existing debug/dev menu code:
Glob: **/*Debug*Menu*.swift, **/*DevMenu*.swift, **/*DevTools*.swift, **/*DebugPanel*.swift
Grep: "DebugMenu" or "DevMenu" or "motionEnded" or "shake" in *.swift
If existing debug menu found:
Search for existing feature flag setup:
Glob: **/*FeatureFlag*.swift, **/*Feature*Toggle*.swift
Grep: "FeatureFlag" or "featureFlag" or "isFeatureEnabled"
If found, integrate debug menu toggles with existing feature flag system rather than creating a new one.
Ask user via AskUserQuestion:
Access method?
Sections to include? (multi-select)
Include push notification testing?
Include export diagnostics?
Read templates.md for production Swift code wrapped in #if DEBUG.
Generate these files (all wrapped in #if DEBUG):
DebugMenuView.swift -- Main NavigationStack with all sectionsDebugSection.swift -- Enum defining available debug sectionsBased on configuration:
3. DebugEnvironmentSwitcher.swift -- If environment switcher selected
4. DebugNetworkLogger.swift -- If network logs selected
5. DiagnosticInfo.swift -- If diagnostics or export selected
DebugMenuTrigger.swift -- ShakeDetector + hidden tap gesture + ViewModifierDebugActions.swift -- Collection of debug utility actionsCheck project structure:
Sources/ exists -> Sources/DebugMenu/App/ exists -> App/DebugMenu/DebugMenu/Entire folder is #if DEBUG and should be excluded from release builds.
After generation, provide:
DebugMenu/
├── DebugMenuView.swift # Main NavigationStack with all sections
├── DebugSection.swift # Enum of available sections
├── DebugEnvironmentSwitcher.swift # Environment switching (optional)
├── DebugNetworkLogger.swift # Network request logger (optional)
├── DiagnosticInfo.swift # Device and app diagnostics (optional)
├── DebugMenuTrigger.swift # Shake gesture + hidden tap trigger
└── DebugActions.swift # Utility actions (reset, clear, crash)
Add the debug trigger to your root view:
#if DEBUG
import SwiftUI
@main
struct MyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
.debugMenuTrigger() // Adds shake + tap to open debug menu
}
}
}
#endif
Or add only to specific views:
struct SettingsView: View {
var body: some View {
Form {
// ... your settings
}
#if DEBUG
.debugMenuTrigger(method: .hiddenTap)
#endif
}
}
Hook up the network logger to your API client:
#if DEBUG
func performRequest(_ request: URLRequest) async throws -> (Data, URLResponse) {
let start = Date()
let (data, response) = try await session.data(for: request)
DebugNetworkLogger.shared.log(request: request, response: response, data: data, duration: Date().timeIntervalSince(start))
return (data, response)
}
#endif
Register your feature flags:
#if DEBUG
extension DebugMenuView {
static let featureFlags: [FeatureFlag] = [
FeatureFlag(key: "new_onboarding", title: "New Onboarding Flow", defaultValue: false),
FeatureFlag(key: "dark_mode_v2", title: "Dark Mode V2", defaultValue: false),
FeatureFlag(key: "premium_paywall", title: "Premium Paywall", defaultValue: true),
]
}
#endif
#if DEBUG
@Test
func debugMenuSectionsRender() {
let view = DebugMenuView()
// Verify all sections are present
#expect(DebugSection.allCases.count > 0)
}
@Test
func environmentSwitcherChangesBaseURL() {
let switcher = DebugEnvironmentSwitcher()
switcher.current = .staging
#expect(switcher.baseURL.absoluteString.contains("staging"))
switcher.current = .production
#expect(switcher.baseURL.absoluteString.contains("api."))
}
@Test
func networkLoggerRecordsRequests() async {
let logger = DebugNetworkLogger.shared
await logger.clear()
let request = URLRequest(url: URL(string: "https://api.example.com/users")!)
let response = HTTPURLResponse(url: request.url!, statusCode: 200, httpVersion: nil, headerFields: nil)!
await logger.log(request: request, response: response, data: Data(), duration: 0.25)
let entries = await logger.entries
#expect(entries.count == 1)
#expect(entries.first?.statusCode == 200)
}
@Test
func diagnosticInfoCollectsDeviceData() {
let info = DiagnosticInfo.collect()
#expect(!info.appVersion.isEmpty)
#expect(!info.osVersion.isEmpty)
#expect(!info.deviceModel.isEmpty)
#expect(info.memoryUsageMB > 0)
}
#endif
#if DEBUG
// In your app's UIWindow subclass or scene delegate:
ContentView()
.debugMenuTrigger(method: .shakeGesture)
#endif
#if DEBUG
// In DebugMenuView, toggle persists to UserDefaults:
Toggle(flag.title, isOn: binding(for: flag))
.onChange(of: flag.isEnabled) {
NotificationCenter.default.post(name: .featureFlagChanged, object: flag.key)
}
#endif
#if DEBUG
DebugEnvironmentSwitcher.shared.current = .staging
// All subsequent API calls use staging base URL
// App restarts recommended for full effect
#endif
#if DEBUG
Button("Clear All Caches", role: .destructive) {
DebugActions.clearAllCaches()
}
#endif
#if DEBUG only -- every file, every type, every extension must be wrapped. Never let debug menu code ship to production.motionEnded may conflict with other shake handlers (e.g., "shake to undo"). Disable the system shake-to-undo if using shake for debug: UIApplication.shared.applicationSupportsShakeToEdit = false.debug_flag_) and provide a "Reset All" button.@MainActor for shared debug state. The network logger must be an actor since it is written to from URLSession callbacks.generators/feature-flags -- Full feature flag system with remote configgenerators/logging-setup -- Structured logging infrastructuredevelopment
Build, install, and launch an iOS app on a physical iPhone or iPad entirely from the command line (no Xcode GUI), using xcodebuild + devicectl. Use when the user wants to run, test, or screenshot their app on a real device without opening Xcode.
development
Comprehensive iOS development guidance including Swift best practices, SwiftUI patterns, UI/UX review against HIG, and app planning. Use for iOS code review, best practices, accessibility audits, or planning new iOS apps.
development
Build, install, launch, and screenshot an iOS app in the Simulator to verify a change visually. Use when the user wants to run the app, see a change live, screenshot the running app, or confirm a UI fix actually works (not just that it compiles).
development
Audits skills in this repo for consistency, API drift, and structural gaps. Produces a prioritized report grouped by severity (Critical/High/Medium/Low). Use when asked to "audit skills", "check the skill repo for drift", or when planning bulk skill cleanup. Read-only — does not apply fixes.