Configure and verify Apple Developer signing, bundle identifiers, capabilities, provisioning, entitlements, App Store Connect, TestFlight, Developer ID, notarization, and release readiness for any iOS, iPadOS, macOS, watchOS, tvOS, visionOS, or app-extension target. Use when creating a new Apple app or extension, repairing Xcode signing, selecting an Apple team, registering App IDs, adding widgets or App Groups, preparing archives/uploads, or auditing signed artifacts and Apple release eviden...
Scanned 9/6/2026
Install to Claude Code
npx -y skills add ingpoc/SKILLS --skill apple-developer --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Apple Developer?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/ingpoc-apple-developer)More formats (shields.io, HTML) on the badges page.
---
name: apple-developer
description: Configure and verify Apple Developer signing, bundle identifiers, capabilities, provisioning, entitlements, App Store Connect, TestFlight, Developer ID, notarization, and release readiness for any iOS, iPadOS, macOS, watchOS, tvOS, visionOS, or app-extension target. Use when creating a new Apple app or extension, repairing Xcode signing, selecting an Apple team, registering App IDs, adding widgets or App Groups, preparing archives/uploads, or auditing signed artifacts and Apple release evidence. For Xcode Cloud workflow design and operations, use the xcode-cloud skill with this skill as the signing owner.
---
# Apple Developer
Operate Apple signing and distribution without assuming a project layout, bundle ID, account email, capability set, or release lane.
## Route related Apple skills
Read [references/apple-skill-catalog.md](references/apple-skill-catalog.md) when
the task needs WidgetKit, SwiftUI, macOS widget recovery, or another focused
Apple-framework skill. Reuse an installed skill when it fits. Install only the
single missing skill required for the task; do not install an upstream bundle.
For Xcode Cloud workflow design, compute, clean-clone bootstrap, or operations,
load `xcode-cloud` first. This skill remains the owner for its signing,
capability, App ID, and App Store Connect authorization work.
## Local account binding
- Expected paid Apple Developer Team ID on this Mac: `9UPQL479Z5`.
- Treat the Team ID as the stable selector. Do not select an account from an email label, display name, certificate/Keychain display name, or remembered identity.
- Re-verify the paid team in Xcode Settings > Accounts or a signed artifact's `TeamIdentifier` before changing a new project. A Personal Team is not equivalent to the paid team. A certificate display label is not team authority.
- Never revoke or delete legacy certificates or Keychain identities without explicit user authorization.
- Never copy an existing app's provisioning profile, App ID, entitlements, App Store record, or signing certificate configuration into another app.
## Start with the project owner
1. Read the repository instructions and the narrowest build/release owner.
2. Identify whether the project is generated by XcodeGen, Tuist, Swift Package Manager, Flutter, React Native, Unity, Unreal, or another owner.
3. Edit the generator/configuration owner. Do not hand-edit a generated `.xcodeproj`.
4. **XcodeGen entitlements trap:** the target key `entitlements: path: …` can regenerate/overwrite the `.entitlements` plist to an empty `<dict/>` and wipe App Groups. Prefer source-owned `.entitlements` files plus `CODE_SIGN_ENTITLEMENTS` only; after every `xcodegen generate`, run `plutil -p <entitlements>` and confirm required keys still exist.
5. Inspect existing signing settings before changing them:
```bash
rg -n "DEVELOPMENT_TEAM|CODE_SIGN_STYLE|CODE_SIGN_ENTITLEMENTS|PRODUCT_BUNDLE_IDENTIFIER|PROVISIONING_PROFILE" .
xcodebuild -list -project <Project.xcodeproj>
xcodebuild -project <Project.xcodeproj> -scheme <Scheme> -configuration Release -showBuildSettings
```
1. Classify the requested work:
- read-only account/signing audit;
- local project configuration;
- Apple Developer portal mutation;
- App Store Connect mutation;
- signed build, archive, upload, notarization, or release proof.
Keep these scopes separate. Local configuration does not authorize external record creation or submission.
## Inventory every target
Build a compact target map before editing:
| Target | Platform | Product type | Bundle ID | Entitlements | Distribution lane |
| --- | --- | --- | --- | --- | --- |
| Main app | project-derived | app | explicit | target-specific | development/store/Developer ID |
| Widget or extension | project-derived | extension | distinct explicit ID | least privilege | embedded with host |
| Tests/helpers | project-derived | test/tool | project-derived | normally none | not distributed |
Do not configure only the host app when the product includes extensions. Each distributable target needs a unique bundle ID and compatible signing.
## Choose identifiers
- Preserve an existing verified identifier unless the user explicitly requests a migration.
- For a new app, use the user's approved reverse-DNS identifier, such as `com.example.Product`.
- Give each extension a distinct child identifier, such as `com.example.Product.widget`.
- Treat identifiers as exact and case-sensitive. Check availability before claiming registration.
- Use one Apple Developer team across a host app and its embedded extensions unless an existing architecture proves otherwise.
- Register only capabilities that the implementation requires.
For a widget that shares data with its host, define one explicit App Group such as `group.com.example.Product` and add the same `com.apple.security.application-groups` entitlement to both targets. Do not add an App Group when no cross-process storage is required.
Register the App Group once, then assign it to every participating explicit
App ID independently. Enabling the capability on the host App ID does not
authorize an extension App ID. After changing an App ID's capabilities,
regenerate or refresh that target's provisioning profile; an older profile does
not gain the new entitlement.
## Configure signing
Prefer automatic signing for ordinary development and App Store workflows:
```text
DEVELOPMENT_TEAM = 9UPQL479Z5
CODE_SIGN_STYLE = Automatic
PRODUCT_BUNDLE_IDENTIFIER = <target-specific-id>
CODE_SIGN_ENTITLEMENTS = <target-specific-entitlements-file>
```
- Apply the paid Team ID to every distributable target.
- Keep one entitlements file per materially different target.
- Keep Debug and Release differences explicit.
- Do not pin `PROVISIONING_PROFILE_SPECIFIER` under automatic signing unless a documented constraint requires it.
- Use manual signing only when an existing CI/export contract or enterprise process owns profile selection.
- Let Xcode manage signing identities and private keys. Never export or print private keys to diagnose signing.
## Map capabilities to implementation
Inspect source, Info.plist values, entitlements, and platform requirements. Enable only implemented requirements, for example:
- App Sandbox and outbound network for Mac App Store apps;
- App Groups for intentional host-extension shared storage;
- Sign in with Apple for native Apple authentication;
- Push Notifications and `aps-environment` only with a working push backend;
- iCloud containers only when the app uses CloudKit or iCloud documents;
- camera, microphone, location, contacts, calendars, or health capabilities only with matching code, usage descriptions, and privacy disclosures;
- Hardened Runtime for macOS distribution;
- Developer ID and notarization only for distribution outside the Mac App Store.
Treat portal capabilities, entitlements, usage descriptions, privacy manifests, App Store privacy answers, and backend configuration as separate owners that must agree.
## Portal and account workflow
1. Inspect membership, team, roles, agreements, identifiers, devices, certificates, and App Store records before mutating.
2. Use the paid team `9UPQL479Z5` only after the current account exposes it.
3. Leave passwords, passkeys, 2FA, recovery data, CAPTCHAs, legal agreements, payments, tax/banking data, and identity attestations to the user.
4. Obtain explicit authorization before creating or deleting identifiers, devices, profiles, certificates, apps, builds, tester groups, or submissions.
5. After every portal mutation, read the saved list/detail view. A successful click or form submission is not proof.
6. Never create a second record to work around an ambiguous or pending state.
Automatic provisioning with `-allowProvisioningUpdates` can mutate the developer account. Use it only when the requested build/provisioning scope authorizes that effect.
Automatic-signing controls and account roles can restrict which resources Xcode
may register or modify. When automatic provisioning fails, verify the signed-in
team, role, explicit App IDs, capability assignments, and profile freshness
before changing source entitlements or creating duplicate records.
## Prove signing
Run the project's canonical build command. When no owner exists, adapt these commands:
```bash
xcodebuild -project <Project.xcodeproj> -scheme <Scheme> -configuration Release -destination 'generic/platform=macOS' build
xcodebuild -project <Project.xcodeproj> -scheme <Scheme> -configuration Release -destination 'generic/platform=iOS' build
codesign -dvvv <Built.app>
codesign -d --entitlements :- <Built.app>
```
A sandboxed `xcodebuild` that reports `No Account for Team "…"` is a false
negative, not proof the paid team is missing. Re-verify unrestricted (Xcode
Settings > Accounts or a signed artifact) before mutating portal records.
For a host with extensions:
1. Inspect the host app's Team Identifier, bundle ID, hardened runtime, and entitlements.
2. Inspect every embedded `.appex` independently.
3. Confirm host and extensions use team `9UPQL479Z5`.
4. Confirm each bundle ID matches its target configuration.
5. Confirm shared App Groups match exactly across participating targets.
6. Confirm the extension is embedded in the signed host.
Use `plutil -p` for array-valued entitlements. Do not treat a simulator build or `CODE_SIGNING_ALLOWED=NO` build as signing proof.
**Simulator signing false negative:** iOS Simulator often adhoc-signs with
`codesign -d --entitlements :-` empty and `TeamIdentifier=not set`. That is not
proof App Groups are missing. Check
`Build/Intermediates…/*-Simulated.xcent` for
`application-identifier` (`TEAMID.bundle.id`) and
`com.apple.security.application-groups`, then prove runtime by reading the
shared App Group container after the host writes. Device/generic-iOS builds
still need real profiles; do not upgrade Simulated.xcent into development
signing proof.
Decode each embedded provisioning profile and compare its application
identifier, team, and restricted entitlements with the final signed
entitlements. On macOS, a successful build and a visible `codesign` entitlement
are not sufficient authorization proof for a restricted capability: require
the matching profile entitlement and a successful runtime operation such as
opening the shared App Group container. Fail closed on wildcard development
profiles such as `Mac Team Provisioning Profile: *`: they can sign with App
Group present in entitlements while the profile itself does not authorize that
App Group.
## Simulator XCUITest traps
- UI test bundles run on iOS: `Process` / host `simctl` are unavailable. Drive
deterministic location via `XCUIApplication.launchEnvironment` (preferred) or
launch arguments the app reads in `LocationModel` / equivalent — not
`Process()` inside the test target.
- Prefer `launchEnvironment` over relaunch `launchArguments` for forced
lat/lng; argument re-parse on terminate/relaunch has been flaky.
- After a form submit that shows the keyboard, tab switches are flaky. Prefer
terminate + cold relaunch for feed round-trips.
- `-allowProvisioningUpdates` mutates the Apple Developer account. Use only
with explicit authorization; Simulator UITest lanes usually do not need it.
## Host + extension shared-status feeds
When a host app and WidgetKit extension share an on-device status feed via App
Groups (not iCloud sync):
- Put the shared schema and load/save helpers in a source folder compiled into
**both** targets. One Codable contract; do not fork structs in the widget.
- Prefer a stable work-item `id` for upserts (for example
`source:projectSlug:threadId`). Upserting by display name alone lets concurrent
agents in one project clobber each other.
- Writers outside the signed host (CLI scripts, hooks) do **not** inherit the
app's App Group entitlement. Resolve the group container by the known path
under `~/Library/Group Containers/<group-id>/…`, use atomic writes, and merge
by `id`. Do not call
`FileManager.containerURL(forSecurityApplicationGroupIdentifier:)` from an
unentitled tool and treat `nil` as "no App Group."
- Version the on-disk document. On schema breaks, change the filename or
`version` field and stop returning demo/sample payloads from `load()` —
empty is safer than a hard-coded product sample that agents mistake for live
data.
- A host timer that calls `WidgetCenter.reloadTimelines` is a **reload pump**,
not delivery proof. Keep it for local freshness; still prove the desktop or
Home Screen widget separately.
- Install the host to a **canonical path** for day-to-day use (for example
`/Applications/<App>.app`). After install, check `pluginkit` for the widget
extension: one registration, `Path` under that canonical host. Duplicate
registrations or DerivedData-only paths explain stale UI after a "successful"
build.
- Bumping `MARKETING_VERSION` / `CURRENT_PROJECT_VERSION` alone is not proof the
system loaded the new extension.
For WidgetKit UI, timelines, and budgets, load `widgetkit`. For a stale macOS
desktop instance after a correct install, load `macos-widget-reinstall`.
## Host + WidgetKit + CloudKit (cross-device)
When a Mac/iOS host pair mirrors the same private CloudKit zone into a
device-local App Group for WidgetKit:
- **Owners:** schema/UI in shared sources; `CKSyncEngine` in **hosts only**;
widgets stay App Group read-only.
- **Primary writer:** one platform (usually Mac) enqueues saves. Secondary
hosts bootstrap receive-only — do not auto-`pushLocalToCloud()` on launch or
a stale App Group mirror will fight higher revisions.
- **Push-on-write (local):** watch the App Group **directory** (not a file
inode) with `DispatchSource`; atomic renames kill file-fd watchers. Demote
timers to fallback. Optionally enqueue CloudKit publish from that same event.
- **CKRecord updates:** fetch existing records (or keep change tags) before
save. Fresh `CKRecord(recordType:recordID:)` without a change tag fails with
`CKError 14` / “record to insert already exists” when the name already
exists. Sanitize unsafe record-name characters; store the canonical id in a
field if the record name is rewritten.
- **WidgetKit Info.plist:** for `com.apple.widgetkit-extension`, do **not** set
`NSExtensionPrincipalClass` or `NSExtensionMainStoryboard` — entry is
`@main` on `Widget`/`WidgetBundle`. Including those keys fails physical
install (`AppexBundleContainsClassOrStoryboard`) even when Simulator
installs succeed.
- **Device install path (deterministic):** prefer
`xcrun devicectl list devices` → `device install app` → `device process
launch`. Continuity iPhone Mirroring is **not** a CoreDevice tunnel and
cannot install. Use mirroring (or `idevicescreenshot` if present) only for
Home Screen widget add/capture — WidgetKit cannot be added by CLI.
- **Verification tiers (do not collapse):** (1) feed JSON, (2) host UI,
(3) rendered desktop/Home Screen widget, (4) cross-device marker after
CloudKit publish (`published N` / unique phase string). Uninstall/reinstall
the phone host if a stale App Group + sync-engine serialization blocks
fetches.
For CloudKit API detail, load `cloudkit`.
## Verify WidgetKit refresh
- Treat `WidgetCenter.reloadTimelines(ofKind:)` and `reloadAllTimelines()` as
requests; the system chooses when WidgetKit runs the extension.
- Supply a coherent timeline and reload policy even when the host requests
refreshes. Avoid minute-by-minute polling assumptions.
- Prefer scheduling the next timeline entry at a **semantic boundary** (for
example when a row would become stale) instead of fixed sub-minute polls.
- Keep refresh requests meaningful because WidgetKit applies a daily execution
budget that varies with user behavior and configuration.
- Verify the rendered widget after the system accepts the update. A host view,
gallery preview, or timeline request is not visible-widget proof.
## Keep proof tiers distinct
- Compile proof: source builds; signing may be disabled.
- Development signing proof: a signed local/device build and matching entitlements.
- Archive proof: a valid archive exists; it may still be development-signed.
- App Store/TestFlight proof: an App Store distribution export/upload with `get-task-allow=false`, processed build, and correct App Store record.
- Developer ID proof: Developer ID Application signing, hardened runtime, notarization acceptance, and stapling.
- Release acceptance: installation through the intended external channel and completion of the required product journey.
Report each tier as complete, partial, or missing. Never upgrade one tier into another.
## Distribution routing
- iOS-family external beta: App Store Connect and TestFlight.
- Mac App Store: App Sandbox, App Store distribution, App Store Connect, and store review.
- Direct macOS distribution: Developer ID Application, Hardened Runtime, notarization, and stapling; do not assume App Store entitlements are valid outside the store.
- Internal local use: development signing may be sufficient, but state that it is not distribution proof.
Before upload, reconcile version/build numbers, bundle IDs, team, export method, App Store record, privacy metadata, encryption/export compliance, account deletion requirements, and capability-specific disclosures.
## Safety and closeout
- Never request credentials or secrets in chat.
- Never print signing private keys, API private keys, provisioning secrets, device identifiers, or unrelated account data.
- Do not infer the active Apple identity from an obsolete or current email address; verify the paid Team ID.
- Preserve user changes and existing project-generation boundaries.
- After edits, run the project's generator, build, signing inspection, and release verifier in that order.
- Report exact evidence paths and remaining external gates.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!