Our review
Automates Xcode TestFlight release preparation by bumping the build number, generating a changelog, committing, and pushing to trigger CI.
Strengths
- Fully automated without asking for confirmation
- Includes pre-flight checks (branch, clean tree, remote up-to-date)
- Multi-agent review via debate step to catch issues before changes
- Changelog reflects only net changes since last build
Limitations
- Only works on the master branch
- Requires a clean working tree with no modified files
- Relies on specific commit messages to find the last bump commit
When you need to quickly prepare a TestFlight build with a changelog and proper version bumping.
When you have uncommitted changes, are not on master, or need manual release decision-making.
Security analysis
SafeThe skill uses only standard Xcode/git/make commands for building, testing, and version bumping. There are no destructive operations, network calls to external services, or access to sensitive data beyond the workspace. No obfuscation or exfiltration risk.
No concerns found
Examples
Create a new TestFlight release buildBump the build number and generate changelog for TestFlight/xcode-releasename: xcode-release description: > Automate Xcode TestFlight releases: bump build number, generate changelog, run pre-release checks with multi-agent review, commit, and push to trigger CI. Use when the user says "release build", "new build", "push to TestFlight", "bump build", or invokes /xcode-release. allowed-tools:
- Bash
- Read
- Edit
- Grep
- Glob
- Skill
Release Build
Automate the full TestFlight release preparation: bump build number, generate changelog, commit, and push.
Procedure
Follow these steps in order. Do NOT ask for confirmation — proceed through all steps automatically. Only stop if a check fails and cannot be auto-fixed.
Step 1: Pre-flight
Before any work, verify the workspace is ready:
- Clean working tree: Run
git status --porcelain. If there are modified or untracked files, stop and ask the user how to proceed. Do not stash or discard silently. - Correct branch: Check
git branch --show-currentismaster. If not, stop. - Remote is up to date: Run
git fetchthen compare local and remote HEAD. If behind, stop and suggestgit pull --rebase.
Step 2: Read current state
Run these commands to gather context:
agvtool what-version
Extract MARKETING_VERSION from the Xcode project:
grep -m1 'MARKETING_VERSION' *.xcodeproj/project.pbxproj
Read the top of CHANGELOG.md to find the last build entry (version, build
number, and date).
Step 3: Identify NET changes since last build
Find the commit that last bumped the build number:
git log --oneline --all --grep="bump build" -1
Then review commits AND the actual diff between that commit and HEAD:
git log --oneline <last-bump-commit>..HEAD
git diff --stat <last-bump-commit>..HEAD
If no bump commit is found, use the last 20 commits as context.
Critical: only include NET changes. Read the full commit history carefully. If a feature was added in one commit but reverted or removed in a later commit, do NOT include it in the changelog. If a bug was introduced and then fixed, do NOT mention either. The changelog must reflect only the difference between the previous build and this one — what a user upgrading from the last build will actually experience. Compare the actual code diff, not just commit messages.
Step 4: Release readiness debate
Review whether the release contains potential issues BEFORE making any changes to the working tree. This ensures a no-go leaves the tree clean.
Scale the debate depth to the complexity of the release. Assess complexity by
reading the diff (git diff --stat <last-bump-commit>..HEAD) and evaluating:
- Does it touch data models, schema, storage configuration, or migrations?
- Does it change business logic, scheduling, sync, or payment flows?
- Does it affect multiple platforms or introduce new user-facing behavior?
- Could it affect existing users upgrading from the current App Store version?
Use depth:quick for low-complexity releases (cosmetic changes, copy updates,
minor bug fixes with no behavioral risk). Use default depth for moderate
complexity. Use depth:deep for high-complexity releases (data layer changes,
new features with edge cases, multi-system changes).
Invoke with:
/debate <depth based on complexity> — Review the changes going into this
release build for potential issues. The diff since last build is: `git diff
<last-bump-commit>..HEAD`. Reference the project's CLAUDE.md for
project-specific release requirements. Focus on: (1) data migration safety —
do any changes affect persisted models, schema, store configuration, or
migration logic? Could upgrading users lose data? (2) bugs or regressions —
do the changes introduce edge cases, missing error handling, or behavioral
changes that could break existing functionality? (3) release blockers — are
there any incomplete features, missing localizations, broken platform parity,
or other issues that should prevent this build from shipping? Produce a
go/no-go recommendation with specific concerns if any.
If the debate produces a no-go recommendation, stop and present the concerns to the user. Do NOT proceed — the working tree is still clean.
If the debate produces a go recommendation (possibly with warnings), note any warnings and proceed to Step 5.
The debate skill is a required dependency. If it is not installed, stop and inform the user to install it before proceeding.
Step 5: Pre-release gate
These checks validate the ENTIRE app state, not just recent changes.
Run every check target defined in the project's Makefile or CI configuration:
make format
make lint
make build
make test
If any check fails, fix the issue (or ask the user for guidance) and re-run before continuing. Do NOT proceed with failing checks.
After checks pass, check whether make format modified any files:
git diff --name-only
If source files were modified by formatting, they must be staged in Step 8.
Step 6: Bump the build number
Calculate the new build number (current + 1), then run:
agvtool new-version -all <NEW_BUILD_NUMBER>
Verify the new build number is strictly greater than the number in the last
CHANGELOG.md entry. If not, stop — this indicates a duplicate or regression.
Step 7: Generate the changelog entry
Write a changelog entry following this exact format:
Version <MARKETING_VERSION> (Build <NEW_BUILD_NUMBER>) - <YYYY-MM-DD>
- <Platform>: <What changed — technical detail and user benefit>
- <Platform>: <What changed — technical detail and user benefit>
Rules for changelog entries:
- Each bullet starts with the platform scope (iOS, macOS, watchOS, or omit if cross-platform)
- Describe both the technical change AND the user-facing benefit in one line
- Use present tense, imperative mood
- Keep each bullet to one line
- Order: user-facing changes first, then internal/infra changes
- Cross-check: each bullet should correspond to actual changes visible in
git diff --stat
Prepend the new entry to CHANGELOG.md directly after the # Changelog heading,
followed by a --- separator before the previous entry.
Verify that MARKETING_VERSION in the changelog matches the value in
project.pbxproj.
Step 8: Commit
Stage ALL modified files — this includes changelog, project files, plists changed by agvtool, AND any source files modified by formatting in Step 5:
git add CHANGELOG.md *.xcodeproj/project.pbxproj
git add $(git diff --name-only -- '*.plist')
git add $(git diff --name-only -- '*.swift')
git add $(git diff --name-only -- '*.xcstrings')
Verify nothing unexpected is staged with git diff --cached --stat. If
unexpected files appear, stop and ask the user.
Commit message format:
chore: bump build to <N>, update changelog
Include the Co-Authored-By trailer.
Step 9: Push and monitor
Push immediately after committing:
git push origin master
After pushing, wait up to 30 seconds for the CI run to appear, then print the run URL:
gh run list --workflow=build.yml --limit 1
Inform the user they can monitor with gh run watch <RUN_ID>.
Error handling
- If
agvtoolfails, check that the working directory contains an.xcodeproj - If there are uncommitted changes before starting, warn the user and ask how to proceed
- If the push fails, show the error and suggest
git pull --rebasefirst - Never force-push
Recovery after CI failure
If CI fails after push:
Lint or test failure
The local checks diverged from CI. Fix the issue, then:
- Do NOT bump the build number again — the failed build was never uploaded
- Commit the fix with:
fix: resolve CI failure for build <N> - Push. CI will re-run and archive the same build number
Archive or upload failure
This is an infrastructure issue (signing, provisioning, App Store Connect):
- Do NOT revert or re-bump — the code is correct
- Fix the CI configuration and re-run:
gh run rerun <RUN_ID> --failed
Never revert a build bump commit
Reverting creates confusion: the build number goes backwards, but agvtool and App Store Connect have already seen the number. Always fix forward.
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.