Generates pre-permission priming screens that explain benefits before showing iOS system permission dialogs. Use when user wants to increase permission grant rates, add pre-permission screens, or explain why the app needs access.
npx skills add https://github.com/rshankras/claude-code-apple-skills --skill permission-priming
Generate pre-permission priming screens — shown before iOS system permission dialogs to explain WHY the app needs access. Dramatically increases permission grant rates vs. cold-prompting users with the system alert.
Use this skill when the user:
Search for existing permission handling:
Glob: **/*Permission*.swift, **/*Authorization*.swift
Grep: "requestAuthorization" or "AVCaptureDevice" or "UNUserNotificationCenter" or "CLLocationManager" or "PHPhotoLibrary"
If existing permission code found:
Search for required usage description keys:
Grep: "NSCameraUsageDescription" or "NSMicrophoneUsageDescription" or "NSLocationWhenInUseUsageDescription" or "NSPhotoLibraryUsageDescription" or "NSContactsUsageDescription" or "NSHealthShareUsageDescription"
If missing keys found for requested permissions:
Ask user via AskUserQuestion:
Read templates.md for production Swift code.
Generate these files:
PermissionType.swift — Enum of all permission types with metadataPermissionStatus.swift — Unified status enum wrapping platform-specific statusesPermissionManager.swift — @Observable class that checks, requests, and opens SettingsPermissionPrimingView.swift — Pre-permission screen with benefits and CTAPermissionStatusTracker.swift — Monitors status changes from SettingsPermissionGatedModifier.swift — ViewModifier that gates content behind permission checkCheck project structure:
Sources/ exists -> Sources/Permissions/App/ exists -> App/Permissions/Permissions/After generation, provide:
Permissions/
├── PermissionType.swift # Permission enum with metadata
├── PermissionStatus.swift # Unified status wrapper
├── PermissionManager.swift # Check, request, open Settings
├── PermissionPrimingView.swift # Pre-permission priming screen
├── PermissionStatusTracker.swift # Monitor status changes
└── PermissionGatedModifier.swift # Gate content behind permission
Basic priming before system prompt:
// Show priming screen, then request system permission on tap
PermissionPrimingView(permissionType: .notifications) {
// User granted — proceed with feature
startSendingNotifications()
} onDenied: {
// User denied or tapped "Not Now"
showLaterPrompt()
}
Gate a feature behind permission:
// Camera feature gated behind permission
CameraView()
.permissionGated(.camera) {
// Priming screen shown automatically if not yet authorized
}
In onboarding flow:
struct OnboardingPermissionsView: View {
@State private var permissionManager = PermissionManager()
var body: some View {
VStack(spacing: 32) {
PermissionPrimingView(permissionType: .notifications) {
// Move to next permission
} onDenied: {
// Skip, ask later
}
}
}
}
Check status and re-prompt after denial:
struct SettingsView: View {
@State private var permissionManager = PermissionManager()
var body: some View {
Section("Permissions") {
ForEach(PermissionType.allCases, id: \.self) { type in
PermissionRow(
type: type,
status: permissionManager.status(for: type),
onRequest: { permissionManager.openSettings() }
)
}
}
}
}
@Test
func primingViewShowsBeforeSystemPrompt() async throws {
let manager = PermissionManager()
let status = await manager.status(for: .notifications)
#expect(status == .notDetermined)
// Priming view should appear before system dialog
}
@Test
func deniedPermissionDirectsToSettings() async throws {
let manager = PermissionManager()
// After denial, tapping "Enable" should open Settings
let settingsURL = manager.settingsURL
#expect(settingsURL != nil)
}
@Test
func permissionGatedModifierShowsPrimingWhenNotAuthorized() async throws {
// ViewModifier should show priming screen when permission is .notDetermined
// and show content when .authorized
}
Show priming screen at the natural moment the user first needs the feature, not during onboarding:
// User taps "Take Photo" -> show camera priming -> then system prompt
Button("Take Photo") {
showCameraPriming = true
}
.sheet(isPresented: $showCameraPriming) {
PermissionPrimingView(permissionType: .camera,
onGranted: { openCamera() },
onDenied: { showCameraPriming = false })
}
Explain the benefit in context of what the user is trying to do:
PermissionPrimingView(
permissionType: .location(.whenInUse),
customTitle: "Find Nearby Restaurants",
customDescription: "We use your location to show restaurants within walking distance."
) { ... }
After denial, the system prompt cannot be shown again. Direct to Settings:
if permissionManager.status(for: .camera) == .denied {
// Show explanation + "Open Settings" button
PermissionDeniedView(permissionType: .camera) {
permissionManager.openSettings()
}
}
.denied state gracefully..whenInUse, then separately request .always. iOS shows a follow-up prompt only after the user has used the app with When In Use access. Do not request Always upfront..provisional, notifications are delivered silently to Notification Center without asking. Consider whether quiet delivery is acceptable before building a priming screen.NS*UsageDescription key in Info.plist, the app will crash immediately. Always verify these keys exist.generators/push-notifications — Push notification setup and handlinggenerators/consent-flow — GDPR/privacy consent flowsIntegration with protocols.io API for managing scientific protocols. This skill should be used when working with protocols.io to search, create, update, or publish protocols; manage protocol steps and materials; handle discussions and comments; organize workspaces; upload and manage files; or integrate protocols.io functionality into workflows. Applicable for protocol discovery, collaborative protocol development, experiment tracking, lab protocol management, and scientific documentation.
Analyzes job descriptions and generates tailored resumes that highlight relevant experience, skills, and achievements to maximize interview chances
Generate Excalidraw diagrams from natural language descriptions. Use when asked to "create a diagram", "make a flowchart", "visualize a process", "draw a system architecture", "create a mind map", or "generate an Excalidraw file". Supports flowcharts, relationship diagrams, mind maps, and system architecture diagrams. Outputs .excalidraw JSON files that can be opened directly in Excalidraw.
Build and distribute Expo development clients locally or via TestFlight
Use when you have a written implementation plan to execute in a separate session with review checkpoints
Data structure for annotated matrices in single-cell analysis. Use when working with .h5ad files or integrating with the scverse ecosystem. This is the data format skill—for analysis workflows use scanpy; for probabilistic models use scvi-tools; for population-scale queries use cellxgene-census.
Benchling R&D platform integration. Access registry (DNA, proteins), inventory, ELN entries, workflows via API, build Benchling Apps, query Data Warehouse, for lab data management automation.
Comprehensive molecular biology toolkit. Use for sequence manipulation, file parsing (FASTA/GenBank/PDB), phylogenetics, and programmatic NCBI/PubMed access (Bio.Entrez). Best for batch processing, custom bioinformatics pipelines, BLAST automation. For quick lookups use gget; for multi-service integration use bioservices.
Take rshankras/permission-priming from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.