xcode-cloud
Skill0 starsChanged 3 months agoMITView on GitHub
Set up, debug and maintain Xcode Cloud CI for a React Native iOS app — the ci_post_clone.sh / ci_pre_xcodebuild.sh scripts that install node, pods and the RN prebuilt tarballs, the workflow settings, and the App Store Connect prerequisites for TestFlight. Use when the user asks to set up Xcode Cloud, add CI to an iOS app, get builds into TestFlight, or fix a failing cloud build; when an archive fails with "Unable to load contents of file list", "node: command not found", a curl error inside pod install, a bigdecimal or bundler failure, or a bare exit 65; when a green archive never reaches TestFlight; or before touching anything under ios/ci_scripts/, .xcode.env, Podfile, or Gemfile. Also use to record a newly diagnosed cloud build failure so it is not re-derived next time.
- Reads credentials
2 other projects use a version of this.
Adopted by
Most recently taken up by
- fiveonecode/agent-skillstheir own version, first seen Sep 6, 2026
- ingpoc/SKILLStheir own version, first seen Aug 10, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- fiveonecode/agent-skills★ 20same name
- ingpoc/SKILLS★ 9same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository19 other files it gives its agents.
- add-featureSkill
- bootsplashSkill
- build-uiSkill
- commit-changesSkill
- domain-modelSkill
- gitmojiSkill
- grill-planSkill
- implement-ticketSkill
- ios-widgetSkill
- iphone-duoSkill
- maintain-skillsSkill
- side-insetsSkill
- ticket-shapingSkill
- truesheet-usageSkill
- unistylesSkill
- upgrade-react-nativeSkill
- validate-changeSkill
- verifySkill
- write-testsSkill
The file
We split this skill into the rules it gives an agent
11 rules. About 0 are common, 6 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈6
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 39
Never write these scripts from the template alone.
- Very specific: line 69
Read references/build-machine-facts.md before designing anything around the runner's environment — and check the observation dates in it.
- Very specific: line 74
Write references/ci_post_clone.sh and references/ci_pre_xcodebuild.sh into ios/ci_scripts/, adapted from Phase 0's findings — read both in …
- Distinctive: line 87
Verify what git actually recorded, not what the filesystem says:
- Distinctive: line 93
Keep the explanatory comments.
- Very specific: line 115
Export compliance: Add ITSAppUsesNonExemptEncryption to the app's Info.plist or every build parks in "Missing Compliance".
- Very specific: line 117
OTHER_LDFLAGShygiene: If -ld64 or -ld_classic is in there, it is template residue from RN 0.72 — remove it. - Distinctive: line 146
Start condition: usually branch changes on the release branch.
- Very specific: line 167
Do this in the same session, not "later".
- Distinctive: line 185
If the log reads entirely green and it still failed, download the result bundle:
- Distinctive: line 196
This is the part that makes the skill worth keeping: Every Xcode Cloud failure is expensive to diagnose and trivial to re-encounter.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Xcode Cloud for a React Native app
Xcode Cloud clones the repo and nothing else. node_modules/ and Pods/
are both gitignored, so a fresh clone has no JavaScript and no pods — the
archive has to install them itself before xcodebuild ever runs. That is the
whole job of ci_post_clone.sh, and nearly every "Xcode Cloud is broken"
report is really that job failing in one of a dozen documented ways.
This skill carries those ways. references/failure-catalogue.md is the
highest-value file here — grep it for the literal error text before theorising
about any failure.
| File | What it is |
references/ci_post_clone.sh | The install script. Template; three lines to check per project. |
references/ci_pre_xcodebuild.sh | Build-number stamping. Generic as written. |
references/failure-catalogue.md | Symptom → real cause → fix. Append-only. |
references/build-machine-facts.md | What the runner actually provides, with observation dates. |
references/project-memory.md | The per-project doc skeleton + the hook that keeps it current. |
Phase 0 — ground yourself in the repo
Never write these scripts from the template alone. Five minutes here saves a build, and each failed build costs 10–20 minutes of round trip.
ls -d ios/*.xcworkspace ios/*.xcodeproj ios/ci_scripts 2>/dev/null
ls ios/*.xcodeproj/xcshareddata/xcschemes/ # scheme shared? empty = not shared
node -p "require('./package.json').dependencies['react-native']"
cat .nvmrc 2>/dev/null; node -p "require('./package.json').engines?.node ?? 'no engines'"
ls yarn.lock package-lock.json pnpm-lock.yaml 2>/dev/null
git check-ignore -v ios/Pods node_modules ios/.xcode.env.local
grep -c "CURRENT_PROJECT_VERSION" ios/*.xcodeproj/project.pbxproj
grep -rn "IPHONEOS_DEPLOYMENT_TARGET" ios/*.xcodeproj/project.pbxproj | sort -u
grep -rln "PRODUCT_BUNDLE_IDENTIFIER" ios/*.xcodeproj/project.pbxproj >/dev/null \
&& grep -o 'PRODUCT_BUNDLE_IDENTIFIER = [^;]*' ios/*.xcodeproj/project.pbxproj | sort -u
ls ios/*/*.entitlements ios/*.entitlements 2>/dev/null # capabilities to provisionWhat each answer changes:
| Finding | Consequence |
No .xcworkspace | Pods have never been installed here; pod install locally first. |
| Scheme not shared | Xcode Cloud cannot see it. Share it in Xcode and commit xcshareddata/. |
| Package manager | Swap the install block in post-clone (yarn / npm ci / pnpm). |
.nvmrc / engines.node | Sets NODE_FORMULA. Mismatching CI and local node is a real source of "works on my machine". |
| RN < 0.86 | No prebuilt tarballs — the prefetch loop is a harmless no-op; leave it. |
Pods/ not gitignored | Rare, but then post-clone needs no pod install. Check before assuming. |
| Extra targets (widget, share extension) | Each needs its own build number and its own App ID assignments. |
IPHONEOS_DEPLOYMENT_TARGET absent or low | See the exit-65 entry in the catalogue. Fix it now, not after it bites. |
Read references/build-machine-facts.md before designing anything around the
runner's environment — and check the observation dates in it.
Phase 1 — the scripts
Write references/ci_post_clone.sh and references/ci_pre_xcodebuild.sh into
ios/ci_scripts/, adapted from Phase 0's findings — read both in full first;
each carries a TEMPLATE header naming exactly what to check.
mkdir -p ios/ci_scripts # before writing them
chmod +x ios/ci_scripts/*.sh # after
git add ios/ci_scripts && git update-index --chmod=+x ios/ci_scripts/*.shThe location and the executable bit are both load-bearing. ci_scripts/
must sit next to the workspace, and a non-executable script is skipped in
silence — indistinguishable in the log from a script that does not exist.
Verify what git actually recorded, not what the filesystem says:
git ls-files -s ios/ci_scripts # want mode 100755, not 100644Keep the explanatory comments. They are the local record of why each line exists, and they are what stops the next person "simplifying" the yarn flag or the tarball prefetch back out again.
Dry-run locally before pushing. Both scripts are written to work off a checkout
with no CI variables set — post-clone is idempotent, and pre-xcodebuild exits
early with CI_BUILD_NUMBER unset:
bash -n ios/ci_scripts/*.sh # syntax
CI_PRIMARY_REPOSITORY_PATH="$PWD" ios/ci_scripts/ci_pre_xcodebuild.sh # no-op locallyPhase 2 — project settings
Three edits that are cheap now and expensive after a failed archive:
- Deployment target. Set
IPHONEOS_DEPLOYMENT_TARGETon every app configuration to the same value the Podfile pins pods to (min_ios_version_supported, resolved innode_modules/react-native/scripts/cocoapods/helpers.rb). Drift here fails archives on some Xcodes and not others. - Export compliance. Add
ITSAppUsesNonExemptEncryptionto the app'sInfo.plistor every build parks in "Missing Compliance". OTHER_LDFLAGShygiene. If-ld64or-ld_classicis in there, it is template residue from RN 0.72 — remove it. See the catalogue.
Phase 3 — the account side (the user's job, not yours)
None of this can be done from the repo, and all of it fails the first distribution archive rather than the ones before it. Hand the user an explicit list built from Phase 0's entitlements and bundle ids:
- An app record in App Store Connect for the app's bundle id. Xcode Cloud will not create it.
- For each capability each target claims: the identifier must exist, and each App ID must be assigned to it. Enabling a capability is not the same as assigning the App ID — a profile built from a capability with nothing assigned still fails.
- Extensions need their own App IDs, with the same assignments as the host.
Quick repair when profiles are wrong: open the workspace in Xcode once with automatic signing. Xcode creates capabilities; Xcode Cloud only ever consumes profiles.
Phase 4 — the workflow
Created in Xcode (Product → Xcode Cloud) or App Store Connect. UI work — walk the user through it rather than pretending to do it.
- Build the
.xcworkspace, never the.xcodeproj. The single most common misconfiguration, and it produces an error that looks like missing pods. - Scheme: the shared one from Phase 0.
- Start condition: usually branch changes on the release branch. Note that Xcode Cloud only builds pushed commits.
- Files and Folders, under the branch-changes condition, keeps prose commits
from burning an archive: set the dropdown to Don't Start a Build and add
docs/or equivalent. It excludes, so a commit touching both docs and source still builds — it cannot silently swallow a real change, unlike an include list. The complement isci skipanywhere in a commit message, which makes Xcode Cloud ignore that push entirely and covers the stray files no folder condition can. - Action Archive, and Deployment Preparation = App Store Connect and
TestFlight if the build is meant to reach testers.
DevelopmentorTestingproduces a downloadable artifact and uploads nothing. - Post-Action → TestFlight Internal Testing, with a tester group. Without it, a perfect archive still never appears.
Warn the user that the first archive after switching to TestFlight distribution often fails where the previous ones passed — it is the first one that checks entitlements at all. That is expected, and Phase 3 is the fix.
Phase 5 — install the project's memory
Do this in the same session, not "later". Follow
references/project-memory.md: write docs/xcode-cloud.md in the project's own
voice, and add the PostToolUse hook to the project's .claude/settings.json.
The doc is not a copy of this skill. This skill holds what is true of Xcode Cloud; the doc holds what is true of this app — its bundle ids, its capabilities, its extensions, the workarounds its dependencies forced. Overlap between the two is drift waiting to happen.
Phase 6 — first build, then triage
Push, watch the log, and expect the first one to fail. When it does:
- Grep the log for the literal error text in
references/failure-catalogue.mdbefore forming any theory. Most of these failures name something other than their cause: the file-list error means the wrong build target, the Rosetta advice is a red herring for a network reset, and a bare exit 65 with noerror:line is not a signing problem. - If the log reads entirely green and it still failed, download the result
bundle:
This is also the fastest way to read any archive failure —xcrun xcresulttool get build-results --path <build>.xcresulterrorCountand every issue as JSON, instead of grepping eight megabytes. - Fix, push, repeat. Then go to "Recording what you learn".
Recording what you learn
This is the part that makes the skill worth keeping. Every Xcode Cloud failure is expensive to diagnose and trivial to re-encounter. Whenever you diagnose one — during setup or years later — write it down before moving on.
Route it by who else it is true for:
| The finding is true of… | Goes in | Shape |
| this repo only — its bundle ids, capabilities, a dependency's quirk | the project's docs/xcode-cloud.md | prose, in that doc's voice |
| Xcode Cloud, the build image, CocoaPods, or RN at some version | references/failure-catalogue.md | a new ## section, same shape as its neighbours |
| what the runner provides | references/build-machine-facts.md | update the row and its History line; never overwrite silently |
| the install steps themselves | references/ci_post_clone.sh (+ this file) | the fix, plus a comment saying what it prevents |
Unclear which? Write it in the project doc and add a one-line pointer in the catalogue. A duplicated fact is recoverable; a lost one is not.
A catalogue entry is only useful if the next reader can find it by the symptom they have. So: the heading is the error text they will grep for, the first paragraph is what it actually means, and the fix comes last. Include the misleading part explicitly — "the Rosetta advice underneath is a red herring" is often the single most valuable sentence in an entry.
Where to edit. ${CLAUDE_PLUGIN_ROOT} is the installed copy of this
plugin and is read-only in practice — edits there are silently discarded on the
next /plugin marketplace update. Edit the source checkout instead, then push
and update. If you cannot find the source checkout, ask the user for its path
once; if the project has no access to it at all, put the learning in the
project's docs/xcode-cloud.md and tell the user it needs promoting later.
Say what you changed. End any session that touched CI with an explicit line: which file recorded which learning. A silent update to a memory file is indistinguishable from no update at all.
Danger zone — never do
- Never build the
.xcodeproj. It fails as though the pods are missing and sends you debugging the wrong half of the system. - Never commit a CI script non-executable. Silent skip, no diagnostic.
- Never
exportsomething and expectxcodebuildto see it. Separate process. Write it to a file. - Never install CocoaPods as a gem on the runner to "match local" — use the same bottle on both sides instead. The native extensions do not build there, and no amount of version pinning fixes it.
- Never trust a green local archive to clear a cloud failure. Different Xcode, different arch, different linker behaviour.
- Never conclude "network flake, just retry" without checking whether the fetch had retries at all. RN's tarball downloads did not.
- Never delete the explanatory comments from the CI scripts. They are the only thing standing between the next reader and repeating the failure.
- Never edit the installed plugin copy of this skill. Edit the source repo.
- Never bump a fact in
build-machine-facts.mdfrom memory — it is only worth anything because every row was read off a real build log.
Definition of done
- Both scripts committed under
ios/ci_scripts/, mode 100755 in git. - Scripts adapted to this repo's package manager, node version and ios path — not left as the template.
- Both run clean locally with no CI variables set.
- Workflow builds the workspace with a shared scheme.
- Deployment Preparation and the TestFlight post-action set, if testers are the goal.
- Account-side prerequisites listed for the user, one line per identifier.
docs/xcode-cloud.mdwritten in the project's voice, and the hook installed and observed firing.- One archive has gone green and reached TestFlight.
- Every failure diagnosed on the way there is recorded in the tier its lesson belongs to, and the user has been told where.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

