RepoPilotOpen in app →

sparrowcode/PermissionsKit

Universal API for request permission and get its statuses.

Mixed

Stale — last commit 1y ago

worst of 4 axes
Use as dependencyMixed

last commit was 1y ago; no tests detected…

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isMixed

last commit was 1y ago; no CI workflows detected

  • 21+ active contributors
  • MIT licensed
  • Stale — last commit 1y ago
Show 3 more →
  • Concentrated ownership — top contributor handles 71% of recent commits
  • No CI workflows detected
  • No test directory detected
What would change the summary?
  • Use as dependency MixedHealthy if: 1 commit in the last 365 days; add a test suite
  • Deploy as-is MixedHealthy if: 1 commit in the last 180 days

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/sparrowcode/permissionskit?axis=fork)](https://repopilot.app/r/sparrowcode/permissionskit)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/sparrowcode/permissionskit on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: sparrowcode/PermissionsKit

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/sparrowcode/PermissionsKit shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 1y ago

  • 21+ active contributors
  • MIT licensed
  • ⚠ Stale — last commit 1y ago
  • ⚠ Concentrated ownership — top contributor handles 71% of recent commits
  • ⚠ No CI workflows detected
  • ⚠ No test directory detected

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live sparrowcode/PermissionsKit repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/sparrowcode/PermissionsKit.

What it runs against: a local clone of sparrowcode/PermissionsKit — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in sparrowcode/PermissionsKit | Confirms the artifact applies here, not a fork | | 2 | License is still MIT | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 438 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>sparrowcode/PermissionsKit</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of sparrowcode/PermissionsKit. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/sparrowcode/PermissionsKit.git
#   cd PermissionsKit
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of sparrowcode/PermissionsKit and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "sparrowcode/PermissionsKit(\\.git)?\\b" \\
  && ok "origin remote is sparrowcode/PermissionsKit" \\
  || miss "origin remote is not sparrowcode/PermissionsKit (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
  && ok "license is MIT" \\
  || miss "license drift — was MIT at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "Sources/PermissionsKit/Permission.swift" \\
  && ok "Sources/PermissionsKit/Permission.swift" \\
  || miss "missing critical file: Sources/PermissionsKit/Permission.swift"
test -f "Sources/CameraPermission/CameraPermission.swift" \\
  && ok "Sources/CameraPermission/CameraPermission.swift" \\
  || miss "missing critical file: Sources/CameraPermission/CameraPermission.swift"
test -f "Sources/LocationPermission/LocationPermission.swift" \\
  && ok "Sources/LocationPermission/LocationPermission.swift" \\
  || miss "missing critical file: Sources/LocationPermission/LocationPermission.swift"
test -f "Sources/NotificationPermission/NotificationPermission.swift" \\
  && ok "Sources/NotificationPermission/NotificationPermission.swift" \\
  || miss "missing critical file: Sources/NotificationPermission/NotificationPermission.swift"
test -f "Sources/PermissionsKit/Data/Text.swift" \\
  && ok "Sources/PermissionsKit/Data/Text.swift" \\
  || miss "missing critical file: Sources/PermissionsKit/Data/Text.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 438 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~408d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/sparrowcode/PermissionsKit"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

PermissionsKit is a unified Swift framework that abstracts iOS system permission requests (Camera, Location, Bluetooth, Health, Notifications, etc.) behind a single API. Rather than writing boilerplate code for each permission type's framework (AVFoundation, CoreLocation, HealthKit), developers call a single request() method and check status with .authorized, .denied, or .notDetermined states across 16+ permission types. Modular architecture: core abstraction in Sources/PermissionsKit/ (Permission.swift as the base protocol, Data/Text.swift for strings), with one folder per permission type (BluetoothPermission/, CameraPermission/, LocationPermission/, etc.). LocationPermission is most complex, splitting logic into Handlers/ (LocationAlwaysHandler.swift, LocationWhenInUseHandler.swift) to handle iOS 11+ authorization levels. Localizations centralized in Sources/PermissionsKit/Resources/Localization/ with language-specific .strings files.

👥Who it's for

iOS app developers building features that need user permissions (camera, location tracking, health data access, notifications). They want to avoid learning each framework's idiosyncrasies and prefer a lightweight abstraction layer that handles permission dialogs consistently across their codebase.

🌱Maturity & risk

Production-ready and actively maintained. The codebase spans 74K+ lines of Swift across modular permission handlers, supports multiple languages (en, de, es, fr, ar, fa localizations in Sources/PermissionsKit/Resources/Localization/), and is packaged via both SPM (Package.swift) and CocoaPods (PermissionsKit.podspec). No visible test suite in the file list suggests some risk; commit recency unknown from provided data.

Moderate risk: the repository shows no automated test files in the provided structure, making regressions harder to catch as new iOS versions ship. Single-maintainer risk (sparrowcode organization) means dependency on one person for bug fixes and iOS API compatibility updates. Permission frameworks are tightly coupled to iOS SDK versions, requiring active maintenance when Apple changes permission request flows.

Active areas of work

No specific commit history visible in provided data. The file structure suggests active support for modern iOS (FaceIDPermission, HealthPermission present), but without recent PR or issue data, ongoing development status is unclear.

🚀Get running

Clone via git clone https://github.com/sparrowcode/PermissionsKit.git && cd PermissionsKit. Install dependencies with swift build (SPM) or pod install if using CocoaPods. The repo is a library, not a runnable app—see the README for integration examples into your own iOS project.

Daily commands: This is a library, not a runnable application. To integrate: add SPM dependency: .package(url: "https://github.com/sparrowcode/PermissionsKit.git", from: "3.0.0") to Package.swift, or pod 'PermissionsKit' to Podfile. Then import specific permission modules (e.g., import CameraPermission) in your app code.

🗺️Map of the codebase

  • Sources/PermissionsKit/Permission.swift — Core protocol defining the universal permission API that all specific permissions must implement—this is the architectural anchor.
  • Sources/CameraPermission/CameraPermission.swift — Reference implementation of Permission protocol showing the canonical pattern for wrapping iOS permission frameworks.
  • Sources/LocationPermission/LocationPermission.swift — Complex permission handler with dual modes (always/whenInUse) demonstrating how to manage permission variants and state.
  • Sources/NotificationPermission/NotificationPermission.swift — Shows how to bridge multiple frameworks (UserNotifications, PushKit) and handle authorization options conversion.
  • Sources/PermissionsKit/Data/Text.swift — Localization and messaging layer that powers permission request UI strings across 12+ languages.
  • Package.swift — Defines SPM targets and platform support—essential for understanding multi-target architecture.
  • PermissionsKit.podspec — CocoaPods configuration specifying public headers and resource bundles for localization distribution.

🧩Components & responsibilities

  • Permission (protocol) (Swift Protocol, associated types) — Defines contract: async request method + sync status property. Enforces consistent API shape.
    • Failure mode: If status property blocks (should never), UI freezes. If request completion never fires, app hangs.
  • Concrete Permission (e.g., CameraPermission) (AVFoundation, CoreLocation, HealthKit, etc.) — Wraps single iOS framework (AVFoundation). Translates framework auth status → PermissionStatus enum.
    • Failure mode: If framework import fails, module compilation fails. If request() crashes, app crashes on permission call.
  • Handler classes (e.g., LocationAlwaysHandler) (CoreLocation, delegation patterns) — Extract complex permission logic (multi-mode, conditional requests) into reusable helpers.
    • Failure mode: If handler retains permission object, circular reference leaks memory.
  • Text/Localization layer — Central source for user-facing strings; maps

🛠️How to make changes

Add a new permission type

  1. Create new directory Sources/NewPermission/ (Sources/NewPermission/NewPermission.swift)
  2. Implement struct conforming to Permission protocol with status and request(completion:) methods (Sources/NewPermission/NewPermission.swift)
  3. Import required framework (e.g., CoreLocation, AVFoundation) and call native permission APIs (Sources/NewPermission/NewPermission.swift)
  4. Add localization strings for this permission to all .lproj/Localizable.strings files (Sources/PermissionsKit/Resources/Localization/en.lproj/Localizable.strings)
  5. Update Package.swift to include new target as .target(name: 'NewPermission', ...) (Package.swift)
  6. Update PermissionsKit.podspec to register new subspec if using CocoaPods (PermissionsKit.podspec)

Add support for new language/locale

  1. Create new locale directory Sources/PermissionsKit/Resources/Localization/[locale].lproj/ (Sources/PermissionsKit/Resources/Localization/[locale].lproj/Localizable.strings)
  2. Copy English Localizable.strings as template and translate all keys (Sources/PermissionsKit/Resources/Localization/en.lproj/Localizable.strings)
  3. Verify all permission types have translated strings for new locale (Sources/PermissionsKit/Resources/Localization/[locale].lproj/Localizable.strings)

Customize permission status check logic for a permission

  1. Open target permission file (e.g., CameraPermission.swift) (Sources/CameraPermission/CameraPermission.swift)
  2. Override the status computed property to add custom logic for edge cases or multiple frameworks (Sources/CameraPermission/CameraPermission.swift)
  3. For complex handlers, extract logic into separate Handler class (see LocationAlwaysHandler pattern) (Sources/LocationPermission/Handlers/LocationAlwaysHandler.swift)

🔧Why these technologies

  • Swift (pure, no Objective-C) — Modern type-safe language; protocol-oriented design eliminates boilerplate and enables universal API
  • Multiple iOS frameworks (AVFoundation, CoreLocation, HealthKit, UserNotifications, etc.) — Each permission type requires its own native framework; abstraction layer provides unified interface
  • Swift Package Manager + CocoaPods dual support — Maximizes adoption by supporting both modern (SPM) and legacy (CocoaPods) dependency systems
  • Localization via .strings files (12 languages) — Standard iOS approach; enables community translation contributions and app-level localization

⚖️Trade-offs already made

  • Single unified Permission protocol vs. framework-specific types

    • Why: Simplifies API surface; developers don't learn 15 different permission patterns
    • Consequence: Some framework-specific capabilities (e.g., location accuracy) require permission-specific extensions
  • Synchronous status property + async request(completion:) methods

    • Why: Status queries are instant (cached); requests require async for dialog/system interaction
    • Consequence: Developers must handle two patterns; completion-based rather than async/await (iOS 13+ compatibility)
  • Modular targets per permission type vs. monolithic framework

    • Why: Reduces app bundle size; developers link only permissions they use
    • Consequence: Requires Package.swift/podspec coordination; more moving parts
  • No automatic re-checking on app foreground

    • Why: Avoids continuous permission state polling; reduces battery/performance impact
    • Consequence: Apps must manually call status queries when needed; can miss permission changes while backgrounded

🚫Non-goals (don't propose these)

  • Real-time permission change notifications (use AppDelegate/Scene callbacks instead)
  • Custom permission UI (framework is system dialog only)
  • Permission scheduling or batching
  • Handling of restricted/unavailable permissions (returns .denied; no distinction)

🪤Traps & gotchas

Info.plist configuration is mandatory—each permission type requires specific keys (NSCameraUsageDescription, NSLocationWhenInUseUsageDescription, etc.) or the app will crash on permission request; the README table lists these but they are easy to forget. Bluetooth and Location permissions require special handling for iOS 13+ background modes (must set NSBluetoothPeripheralUsageDescription and location background mode in Xcode). Health permission requires explicit entitlements setup in Xcode, not just Info.plist. No obvious CI/CD config (.github/ has templates but no .yml workflows shown) suggests manual testing burden falls on maintainers.

🏗️Architecture

💡Concepts to learn

  • iOS Permission Model (Authorization Status Lifecycle) — PermissionsKit's core abstraction (.authorized, .denied, .notDetermined) maps directly to iOS's AVAuthorizationStatus, CLAuthorizationStatus, etc.; understanding this lifecycle prevents race conditions and improper state handling.
  • Handler Pattern — PermissionsKit uses handlers (LocationAlwaysHandler, LocationWhenInUseHandler) to encapsulate framework-specific logic; this pattern keeps the Permission protocol clean and lets complex permissions like Location have multiple request flows.
  • Protocol-Oriented Programming (Swift Protocols) — The entire framework is built on Swift protocols (Permission, PermissionStatus); mastering protocol conformance and generic constraints is essential to extending or modifying PermissionsKit.
  • iOS Background Modes & Entitlements — Certain permissions (Location, Bluetooth) require entitlements and background mode configuration in Xcode; misconfiguration silently breaks permission requests at runtime.
  • Localization (Strings Files & NSLocalizedString) — PermissionsKit ships with 6 language localizations using .strings files; understanding the localization workflow is critical when adding new permission messages or supporting additional languages.
  • Info.plist Permission Declarations — iOS requires explicit NSUsageDescription keys in Info.plist for every permission; missing entries cause crashes. PermissionsKit abstracts the request, but the plist setup is the developer's responsibility.
  • ashleymills/Reachability.swift — Complementary iOS utility for checking network reachability status; often used alongside PermissionsKit in apps needing both permission and connectivity checks.
  • devicekit/DeviceKit — Abstracts device detection and iOS version checks; useful in PermissionsKit-based apps to gate features by device capability.
  • apple/swift-nio — Foundational Swift async/concurrency patterns; relevant as PermissionsKit could benefit from Swift Concurrency (async/await) for modern request flows.
  • pointfreeco/swift-composable-architecture — State management framework that pairs well with PermissionsKit in SwiftUI apps needing to manage permission state alongside app state.

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for Permission status handlers

The repo has 11 permission modules (Camera, Location, Bluetooth, etc.) but no visible test directory. Each permission handler should have unit tests covering the three status states (.authorized, .denied, .notDetermined). This is critical for a permission library where correctness directly impacts app security.

  • [ ] Create Tests/ directory structure mirroring Sources/ (e.g., Tests/CameraPermission/, Tests/LocationPermission/)
  • [ ] Add unit tests for each permission's status checking logic in handlers like Sources/LocationPermission/Handlers/LocationAlwaysHandler.swift and Sources/BluetoothPermission/BluetoothHandler.swift
  • [ ] Test the Permission.swift protocol implementation across all concrete permission types
  • [ ] Add tests for the NotificationAccess+userNotifcationAuthorizationOptions.swift conversion logic with various authorization option combinations

Create GitHub Actions workflow for iOS permission testing across multiple iOS versions

The repo has .github/ISSUE_TEMPLATE and .github/PULL_REQUEST_TEMPLATE.md but no visible CI workflow. Permission APIs differ significantly across iOS versions (e.g., location accuracy, health permissions). Adding a matrix test across iOS 13-17 ensures compatibility and prevents regressions.

  • [ ] Create .github/workflows/test.yml to run on push and PR events
  • [ ] Configure matrix strategy to test against multiple iOS SDK versions (minimum deployment target through latest)
  • [ ] Add build and test steps for both SPM (Package.swift) and CocoaPods (PermissionsKit.podspec) configurations
  • [ ] Include linting checks for the localization files in Sources/PermissionsKit/Resources/Localization/

Add missing localization for incomplete string translations and document localization contributor guidelines

The repo supports 12 languages (ar, de, en, es, fa, fr, it, nl, pl, pt, ru, uk, zh variants) in Sources/PermissionsKit/Resources/Localization/, but there's no documented process for translators or validation that all .strings files have equivalent keys. The README is truncated mid-sentence and doesn't mention localization.

  • [ ] Add a script in Sources/PermissionsKit/Resources/Localization/ to validate all language files have matching keys (catch missing translations early)
  • [ ] Create LOCALIZATION.md documenting how to contribute translations and the required keys in Localizable.strings
  • [ ] Add a GitHub Action workflow that runs the validation script on PRs modifying localization files
  • [ ] Complete and document the truncated README.md with the full list of supported permissions and localization information

🌿Good first issues

  • Add unit tests for each permission handler—create Tests/CameraPermissionTests.swift mirroring Sources/CameraPermission/CameraPermission.swift to validate .request() and .status paths.
  • Expand localization: add Russian (ru.lproj) and Japanese (ja.lproj) folders under Sources/PermissionsKit/Resources/Localization/ following the pattern of existing .strings files.
  • Document the handler pattern in CONTRIBUTING.md with a step-by-step example of adding a new permission type (e.g., a hypothetical VideoRecording permission), including required Info.plist keys.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • bc20d72 — Merge pull request #354 from zshannon/main (ivanvorobei)
  • 8832904 — expose SpeechPermission for macOS (zshannon)
  • e449e39 — Add macOS support to MicrophonePermission.swift (zshannon)
  • 5e59359 — Updated doc for permissions accesses. (ivanvorobei)
  • 80a04a4 — Merge pull request #353 from jonasrichardrichter/main (ivanvorobei)
  • 430dba4 — Merge branch 'sparrowcode:main' into main (jonasrichardrichter)
  • 7fd4d6c — Merge pull request #352 from EchoLunar/EchoLunar-patch-1 (ivanvorobei)
  • e6a501b — Adapt ContactsPermission to iOS 18, changing the limited status to return as authorized. (EchoLunar)
  • 982bb42 — Merge pull request #348 from cs4alhaider/patch-1 (ivanvorobei)
  • c0f8a1c — Fix typo in README.md (cs4alhaider)

🔒Security observations

PermissionsKit appears to be a well-structured iOS permissions abstraction library with no critical vulnerabilities evident from the file structure analysis. However, a complete security assessment requires examination of the actual Swift source code, especially the permission request implementations and status handling. The primary security dependencies are on Apple's native permission APIs, which are inherently secure when used correctly. The main recommendation is to ensure comprehensive security documentation for library users to prevent misuse. The score reflects good practices observed (modular structure, no obvious hardcoded credentials) balanced against incomplete code visibility.

  • Medium · Missing dependency information in static analysis — Package.swift. The Package.swift file content is not provided for analysis. Dependency vulnerabilities cannot be assessed without examining the actual package dependencies and their versions. Fix: Provide the Package.swift file content for dependency version analysis. Regularly audit dependencies using tools like swift package show-dependencies and check for known vulnerabilities using security advisories.
  • Low · Localization files may contain sensitive information — Sources/PermissionsKit/Resources/Localization/*/Localizable.strings. Multiple localization files (.strings) are present across different languages. While typically harmless, these files could potentially contain hardcoded user messages that reveal system behavior or error details. Fix: Review localization strings to ensure they do not expose sensitive information, implementation details, or error messages that could aid attackers. Avoid including system paths, API endpoints, or debugging information.
  • Low · Permission framework handling without explicit security review — Sources/*/[Permission].swift (all permission modules). The codebase handles multiple sensitive iOS permissions (Camera, Location, Contacts, Health, Photos, Microphone, etc.). While the framework itself manages permission requests through official APIs, improper implementation by developers using this library could lead to unauthorized access. Fix: Include comprehensive security documentation in README and code comments. Emphasize the importance of proper info.plist entries, user consent flows, and principle of least privilege. Consider adding warnings for sensitive permissions like Location Always or Health data.
  • Low · No visible input validation mechanisms — Sources/PermissionsKit/. The file structure suggests this is primarily a permission request framework, but without examining actual code, potential input validation issues in permission callbacks or status checks cannot be assessed. Fix: Ensure all permission status callbacks and responses are validated. Implement defensive programming to handle unexpected permission states returned by the OS.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · sparrowcode/PermissionsKit — RepoPilot