Apple Bundle ID Guardrails
Use this skill whenever an Apple bundle identifier meets a signing configuration: new Xcode or mobile project setup, side-by-side Release/Debug identity, entering a bundle ID or signing team, repo audits for identifier leaks, and App ID registration errors. This skill owns Apple registration safety and works independently of Flutter. Before writing an Apple bundle ID, allow only letters, digits, hyphens, and dots; preserve existing casing and target suffixes. Validate derived IDs before use; preserve existing personal IDs unless migration is requested.
Why This Exists
App IDs (explicit bundle IDs) are globally unique across the entire Apple Developer Program, across all teams. Merely running an iOS app on a device lets Xcode automatic signing register the App ID to the currently selected team — including a free personal team, which cannot access the portal Identifiers list, so a wrongly registered ID is hard to reclaim. macOS builds usually skip registration unless a restricted entitlement requires a provisioning profile (TN3125), but apply the same rules to macOS conservatively.
macOS carries a second, independent hazard that does not depend on registration at all. TCC permission grants (Accessibility, Input Monitoring, Screen Recording) are keyed to bundle ID plus code signature, and UserDefaults domains are keyed to bundle ID alone. One ID shared between a development build and an installed release means one grant and one preferences domain between them, each overwriting the other — and since macOS never revokes a grant when an app is deleted, a build silently inherits whatever that ID was granted before. Suffixed personal and .dev IDs isolate both. Details and the tccutil workflow: references/xcconfig-guardrail.md.
Rules
- Never enter the canonical ID (
com.<org>.<product>) into any signing configuration until the organization team exists and has registered it. This is the only fatal mistake.
- New personal development identities use
<canonical>.<github-handle>; development builds append .dev (example shape: com.acme.myapp.alice.dev). App ID uniqueness is exact-string, so registering a suffixed ID never blocks the canonical one — a mistake's blast radius is one personal suffix.
- The first action after the organization team opens is to register every canonical App ID to it. After registration, canonical IDs may enter the organization's release configuration; keep personal overrides and side-by-side identity isolation where needed.
- Before organization registration, repos — public ones especially — carry the canonical ID in no active build or signing configuration: an outside contributor's automatic signing could try to register it. Documentation and non-executable comments are exempt; audit effective setting values, not text mentions. Rule 5 is the mechanism.
- Before organization registration, check in only a sacrificial ID with no organization namespace (convention:
forked.<product>.local) and no DEVELOPMENT_TEAM; personal bundle IDs and the signing team live in a git-ignored xcconfig override. Setup procedure: references/xcconfig-guardrail.md.
Resolve real org, product, and github-handle values from the user or project docs before writing anything; never apply the example IDs above literally.
Workflow
- Identify the branch: new-project or retrofit setup, side-by-side Release/Debug identity, audit, personal-ID choice, org-team handover, or registration-error recovery.
- Setup before organization registration (new project or retrofit): follow
references/xcconfig-guardrail.md. Done when each app, extension, and widget resolves to its own sacrificial ID without the local override, and tracked active build/signing values contain neither the organization namespace nor a personal team ID. Verify the available unsigned or simulator build separately; report unavailable signing checks.
- Side-by-side identity: use the
.dev ID from Rule 2 and follow Optional Development Build Name in references/xcconfig-guardrail.md. Done when Release and Debug resolve to different bundle IDs and display names.
- Audit: search every tracked file —
project.pbxproj, *.xcconfig, *.plist, *.entitlements, export options, CI configs — for the org namespace and for DEVELOPMENT_TEAM literals. Classify hits as active settings or documentation/comments. Report active organization IDs as registration hazards only before organization registration, and personal team literals as hygiene issues; include file and line evidence and confirm the override is git-ignored.
- Org-team handover checklist:
- Enumerate every canonical explicit bundle ID: each app, plus each extension and widget, is its own App ID.
- Register each in the org team's portal (Certificates, Identifiers & Profiles → Identifiers).
- Only then move canonical IDs into signing configs and release lanes; personal suffixed IDs stay for local development.
- Recovery from "An App ID with Identifier … is not available" / "Failed to register bundle identifier": the ID is already registered to some team. If a team you control owns it, delete it from that team's Identifiers list to release it. A free personal team cannot see Identifiers — treat that ID as burned and switch to a suffixed personal ID.
Output
Report which branch ran, the exact IDs written or audited (sacrificial, personal, canonical), every file changed or flagged, and any decision still needing a human — signing team selection and portal registration always do.
1---2name: apple-bundle-id-guardrails3description: Use when creating a new Xcode or mobile app project, choosing or entering an Apple bundle ID / App ID, configuring a signing team (especially a free personal team), setting up side-by-side Release and Debug installs, setting up a macOS app that requests TCC permissions (Accessibility, Input Monitoring, Screen Recording), auditing a repo for identifier leaks, or hitting 'An App ID with Identifier is not available' / 'Failed to register bundle identifier' errors.4---56# Apple Bundle ID Guardrails78Use this skill whenever an Apple bundle identifier meets a signing configuration: new Xcode or mobile project setup, side-by-side Release/Debug identity, entering a bundle ID or signing team, repo audits for identifier leaks, and App ID registration errors. This skill owns Apple registration safety and works independently of Flutter. Before writing an Apple bundle ID, allow only letters, digits, hyphens, and dots; preserve existing casing and target suffixes. Validate derived IDs before use; preserve existing personal IDs unless migration is requested.910## Why This Exists1112App IDs (explicit bundle IDs) are globally unique across the entire Apple Developer Program, across all teams. Merely running an iOS app on a device lets Xcode automatic signing register the App ID to the currently selected team — including a free personal team, which cannot access the portal Identifiers list, so a wrongly registered ID is hard to reclaim. macOS builds usually skip registration unless a restricted entitlement requires a provisioning profile (TN3125), but apply the same rules to macOS conservatively.1314macOS carries a second, independent hazard that does not depend on registration at all. TCC permission grants (Accessibility, Input Monitoring, Screen Recording) are keyed to bundle ID plus code signature, and `UserDefaults` domains are keyed to bundle ID alone. One ID shared between a development build and an installed release means one grant and one preferences domain between them, each overwriting the other — and since macOS never revokes a grant when an app is deleted, a build silently inherits whatever that ID was granted before. Suffixed personal and `.dev` IDs isolate both. Details and the `tccutil` workflow: `references/xcconfig-guardrail.md`.1516## Rules17181. Never enter the canonical ID (`com.<org>.<product>`) into any signing configuration until the organization team exists and has registered it. This is the only fatal mistake.192. New personal development identities use `<canonical>.<github-handle>`; development builds append `.dev` (example shape: `com.acme.myapp.alice.dev`). App ID uniqueness is exact-string, so registering a suffixed ID never blocks the canonical one — a mistake's blast radius is one personal suffix.203. The first action after the organization team opens is to register every canonical App ID to it. After registration, canonical IDs may enter the organization's release configuration; keep personal overrides and side-by-side identity isolation where needed.214. Before organization registration, repos — public ones especially — carry the canonical ID in no active build or signing configuration: an outside contributor's automatic signing could try to register it. Documentation and non-executable comments are exempt; audit effective setting values, not text mentions. Rule 5 is the mechanism.225. Before organization registration, check in only a sacrificial ID with no organization namespace (convention: `forked.<product>.local`) and no `DEVELOPMENT_TEAM`; personal bundle IDs and the signing team live in a git-ignored xcconfig override. Setup procedure: `references/xcconfig-guardrail.md`.2324Resolve real org, product, and github-handle values from the user or project docs before writing anything; never apply the example IDs above literally.2526## Workflow27281. Identify the branch: new-project or retrofit setup, side-by-side Release/Debug identity, audit, personal-ID choice, org-team handover, or registration-error recovery.292. Setup before organization registration (new project or retrofit): follow `references/xcconfig-guardrail.md`. Done when each app, extension, and widget resolves to its own sacrificial ID without the local override, and tracked active build/signing values contain neither the organization namespace nor a personal team ID. Verify the available unsigned or simulator build separately; report unavailable signing checks.303. Side-by-side identity: use the `.dev` ID from Rule 2 and follow **Optional Development Build Name** in `references/xcconfig-guardrail.md`. Done when Release and Debug resolve to different bundle IDs and display names.314. Audit: search every tracked file — `project.pbxproj`, `*.xcconfig`, `*.plist`, `*.entitlements`, export options, CI configs — for the org namespace and for `DEVELOPMENT_TEAM` literals. Classify hits as active settings or documentation/comments. Report active organization IDs as registration hazards only before organization registration, and personal team literals as hygiene issues; include file and line evidence and confirm the override is git-ignored.325. Org-team handover checklist:33 - Enumerate every canonical explicit bundle ID: each app, plus each extension and widget, is its own App ID.34 - Register each in the org team's portal (Certificates, Identifiers & Profiles → Identifiers).35 - Only then move canonical IDs into signing configs and release lanes; personal suffixed IDs stay for local development.366. Recovery from "An App ID with Identifier … is not available" / "Failed to register bundle identifier": the ID is already registered to some team. If a team you control owns it, delete it from that team's Identifiers list to release it. A free personal team cannot see Identifiers — treat that ID as burned and switch to a suffixed personal ID.3738## Output3940Report which branch ran, the exact IDs written or audited (sacrificial, personal, canonical), every file changed or flagged, and any decision still needing a human — signing team selection and portal registration always do.