Claude Agent Skill · by Dpearson2699

Permissionkit

Install Permissionkit skill for Claude Code from dpearson2699/swift-ios-skills.

Install
Terminal · npx
$npx skills add https://github.com/microsoft/github-copilot-for-azure --skill azure-rbac
Works with Paperclip

How Permissionkit fits into a Paperclip company.

Permissionkit drops into any Paperclip agent that handles this kind of work. Assign it to a specialist inside a pre-configured PaperclipOrg company and the skill becomes available on every heartbeat — no prompt engineering, no tool wiring.

S
SaaS FactoryPaired

Pre-configured AI company — 18 agents, 18 skills, one-time purchase.

$27$59
Explore pack
Source file
SKILL.md446 lines
Expand
---name: permissionkitdescription: "Create child communication safety experiences using PermissionKit to request parental permission for children. Use when building apps that involve child-to-contact communication, need to check communication limits, request parent/guardian approval, or handle permission responses for minors."--- # PermissionKit > **Note:** PermissionKit is new in iOS 26. Method signatures should be verified against the latest Xcode 26 beta SDK. Request permission from a parent or guardian to modify a child's communicationrules. PermissionKit creates communication safety experiences that let childrenask for exceptions to communication limits set by their parents. TargetsSwift 6.3 / iOS 26+. ## Contents - [Setup](#setup)- [Core Concepts](#core-concepts)- [Checking Communication Limits](#checking-communication-limits)- [Creating Permission Questions](#creating-permission-questions)- [Requesting Permission with AskCenter](#requesting-permission-with-askcenter)- [SwiftUI Integration with PermissionButton](#swiftui-integration-with-permissionbutton)- [Handling Responses](#handling-responses)- [Significant App Update Topic](#significant-app-update-topic)- [Common Mistakes](#common-mistakes)- [Review Checklist](#review-checklist)- [References](#references) ## Setup Import `PermissionKit`. No special entitlements are required. ```swiftimport PermissionKit``` **Platform availability:** iOS 26+, iPadOS 26+, macOS 26+. ## Core Concepts PermissionKit manages a flow where: 1. A child encounters a communication limit in your app2. Your app creates a `PermissionQuestion` describing the request3. The system presents the question to the child for them to send to their parent4. The parent reviews and approves or denies the request5. Your app receives a `PermissionResponse` with the parent's decision ### Key Types | Type | Role ||---|---|| `AskCenter` | Singleton that manages permission requests and responses || `PermissionQuestion` | Describes the permission being requested || `PermissionResponse` | The parent's decision (approval or denial) || `PermissionChoice` | The specific answer (approve/decline) || `PermissionButton` | SwiftUI button that triggers the permission flow || `CommunicationTopic` | Topic for communication-related permission requests || `CommunicationHandle` | A phone number, email, or custom identifier || `CommunicationLimits` | Checks whether communication limits apply || `SignificantAppUpdateTopic` | Topic for significant app update permission requests | ## Checking Communication Limits Before presenting a permission request, check if communication limits areenabled and whether the handle is known. ```swiftimport PermissionKit func checkCommunicationStatus(for handle: CommunicationHandle) async -> Bool {    let limits = CommunicationLimits.current    let isKnown = await limits.isKnownHandle(handle)    return isKnown} // Check multiple handles at oncefunc filterKnownHandles(_ handles: Set<CommunicationHandle>) async -> Set<CommunicationHandle> {    let limits = CommunicationLimits.current    return await limits.knownHandles(in: handles)}``` ### Creating Communication Handles ```swiftlet phoneHandle = CommunicationHandle(    value: "+1234567890",    kind: .phoneNumber) let emailHandle = CommunicationHandle(    value: "friend@example.com",    kind: .emailAddress) let customHandle = CommunicationHandle(    value: "user123",    kind: .custom)``` ## Creating Permission Questions Build a `PermissionQuestion` with the contact information and communicationaction type. ```swift// Question for a single contactlet handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)let question = PermissionQuestion<CommunicationTopic>(handle: handle) // Question for multiple contactslet handles = [    CommunicationHandle(value: "+1234567890", kind: .phoneNumber),    CommunicationHandle(value: "friend@example.com", kind: .emailAddress)]let multiQuestion = PermissionQuestion<CommunicationTopic>(handles: handles)``` ### Using CommunicationTopic with Person Information Provide display names and avatars for a richer permission prompt. ```swiftlet personInfo = CommunicationTopic.PersonInformation(    handle: CommunicationHandle(value: "+1234567890", kind: .phoneNumber),    nameComponents: {        var name = PersonNameComponents()        name.givenName = "Alex"        name.familyName = "Smith"        return name    }(),    avatarImage: nil) let topic = CommunicationTopic(    personInformation: [personInfo],    actions: [.message, .audioCall]) let question = PermissionQuestion<CommunicationTopic>(communicationTopic: topic)``` ### Communication Actions | Action | Description ||---|---|| `.message` | Text messaging || `.audioCall` | Voice call || `.videoCall` | Video call || `.call` | Generic call || `.chat` | Chat communication || `.follow` | Follow a user || `.beFollowed` | Allow being followed || `.friend` | Friend request || `.connect` | Connection request || `.communicate` | Generic communication | ## Requesting Permission with AskCenter Use `AskCenter.shared` to present the permission request to the child. ```swiftimport PermissionKit func requestPermission(    for question: PermissionQuestion<CommunicationTopic>,    in viewController: UIViewController) async {    do {        try await AskCenter.shared.ask(question, in: viewController)        // Question was presented to the child    } catch let error as AskError {        switch error {        case .communicationLimitsNotEnabled:            // Communication limits not active -- no permission needed            break        case .contactSyncNotSetup:            // Contact sync not configured            break        case .invalidQuestion:            // Question is malformed            break        case .notAvailable:            // PermissionKit not available on this device            break        case .systemError(let underlying):            print("System error: \(underlying)")        case .unknown:            break        @unknown default:            break        }    }}``` ## SwiftUI Integration with PermissionButton `PermissionButton` is a SwiftUI view that triggers the permission flowwhen tapped. ```swiftimport SwiftUIimport PermissionKit struct ContactPermissionView: View {    let handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)     var body: some View {        let question = PermissionQuestion<CommunicationTopic>(handle: handle)         PermissionButton(question: question) {            Label("Ask to Message", systemImage: "message")        }    }}``` ### PermissionButton with Custom Topic ```swiftstruct CustomPermissionView: View {    var body: some View {        let personInfo = CommunicationTopic.PersonInformation(            handle: CommunicationHandle(value: "user456", kind: .custom),            nameComponents: nil,            avatarImage: nil        )        let topic = CommunicationTopic(            personInformation: [personInfo],            actions: [.follow]        )        let question = PermissionQuestion<CommunicationTopic>(            communicationTopic: topic        )         PermissionButton(question: question) {            Text("Ask to Follow")        }    }}``` ## Handling Responses Listen for permission responses asynchronously. ```swiftfunc observeResponses() async {    let responses = AskCenter.shared.responses(for: CommunicationTopic.self)     for await response in responses {        let choice = response.choice        let question = response.question         switch choice.answer {        case .approval:            // Parent approved -- enable communication            print("Approved for topic: \(question.topic)")        case .denial:            // Parent denied -- keep restriction            print("Denied")        @unknown default:            break        }    }}``` ### PermissionChoice Properties ```swiftlet choice: PermissionChoice = response.choiceprint("Answer: \(choice.answer)")  // .approval or .denialprint("Choice ID: \(choice.id)")print("Title: \(choice.title)") // Convenience staticslet approved = PermissionChoice.approvelet declined = PermissionChoice.decline``` ## Significant App Update Topic Request permission for significant app updates that require parental approval. ```swiftlet updateTopic = SignificantAppUpdateTopic(    description: "This update adds multiplayer chat features") let question = PermissionQuestion<SignificantAppUpdateTopic>(    significantAppUpdateTopic: updateTopic) // Present the questiontry await AskCenter.shared.ask(question, in: viewController) // Listen for responsesfor await response in AskCenter.shared.responses(for: SignificantAppUpdateTopic.self) {    switch response.choice.answer {    case .approval:        // Proceed with update        break    case .denial:        // Skip update        break    @unknown default:        break    }}``` ## Common Mistakes ### DON'T: Skip checking if communication limits are enabled If communication limits are not enabled, calling `ask` throws`.communicationLimitsNotEnabled`. Check first or handle the error. ```swift// WRONG: Assuming limits are always activetry await AskCenter.shared.ask(question, in: viewController) // CORRECT: Handle the case where limits are not enableddo {    try await AskCenter.shared.ask(question, in: viewController)} catch AskError.communicationLimitsNotEnabled {    // Communication limits not active -- allow communication directly    allowCommunication()} catch {    handleError(error)}``` ### DON'T: Ignore AskError cases Each error case requires different handling. ```swift// WRONG: Catch-all with no user feedbackdo {    try await AskCenter.shared.ask(question, in: viewController)} catch {    print(error)} // CORRECT: Handle each casedo {    try await AskCenter.shared.ask(question, in: viewController)} catch let error as AskError {    switch error {    case .communicationLimitsNotEnabled:        allowCommunication()    case .contactSyncNotSetup:        showContactSyncPrompt()    case .invalidQuestion:        showInvalidQuestionAlert()    case .notAvailable:        showUnavailableMessage()    case .systemError(let underlying):        showSystemError(underlying)    case .unknown:        showGenericError()    @unknown default:        break    }}``` ### DON'T: Create questions with empty handles A question with no handles or person information is invalid. ```swift// WRONG: Empty handles arraylet question = PermissionQuestion<CommunicationTopic>(handles: [])  // Invalid // CORRECT: Provide at least one handlelet handle = CommunicationHandle(value: "+1234567890", kind: .phoneNumber)let question = PermissionQuestion<CommunicationTopic>(handle: handle)``` ### DON'T: Forget to observe responses Presenting a question without listening for the response means you neverknow if the parent approved. ```swift// WRONG: Fire and forgettry await AskCenter.shared.ask(question, in: viewController) // CORRECT: Observe responsesTask {    for await response in AskCenter.shared.responses(for: CommunicationTopic.self) {        handleResponse(response)    }}try await AskCenter.shared.ask(question, in: viewController)``` ### DON'T: Use deprecated CommunicationLimitsButton Use `PermissionButton` instead of the deprecated `CommunicationLimitsButton`. ```swift// WRONG: DeprecatedCommunicationLimitsButton(question: question) {    Text("Ask Permission")} // CORRECT: Use PermissionButtonPermissionButton(question: question) {    Text("Ask Permission")}``` ## Review Checklist - [ ] `AskError.communicationLimitsNotEnabled` handled to allow fallback- [ ] `AskError` cases handled individually with appropriate user feedback- [ ] `CommunicationHandle` created with correct `Kind` (phone, email, custom)- [ ] `PermissionQuestion` includes at least one handle or person information- [ ] `AskCenter.shared.responses(for:)` observed to receive parent decisions- [ ] `PermissionButton` used instead of deprecated `CommunicationLimitsButton`- [ ] Person information includes name components for a clear permission prompt- [ ] Communication actions match the app's actual communication capabilities- [ ] Response handling updates UI on the main actor- [ ] Error states provide clear guidance to the user ## References - Extended patterns (response handling, multi-topic, UIKit): [references/permissionkit-patterns.md](references/permissionkit-patterns.md)- [PermissionKit framework](https://sosumi.ai/documentation/permissionkit)- [AskCenter](https://sosumi.ai/documentation/permissionkit/askcenter)- [PermissionQuestion](https://sosumi.ai/documentation/permissionkit/permissionquestion)- [PermissionButton](https://sosumi.ai/documentation/permissionkit/permissionbutton)- [PermissionResponse](https://sosumi.ai/documentation/permissionkit/permissionresponse)- [CommunicationTopic](https://sosumi.ai/documentation/permissionkit/communicationtopic)- [CommunicationHandle](https://sosumi.ai/documentation/permissionkit/communicationhandle)- [CommunicationLimits](https://sosumi.ai/documentation/permissionkit/communicationlimits)- [SignificantAppUpdateTopic](https://sosumi.ai/documentation/permissionkit/significantappupdatetopic)- [AskError](https://sosumi.ai/documentation/permissionkit/askerror)- [Creating a communication experience](https://sosumi.ai/documentation/permissionkit/creating-a-communication-experience)