agentsclimarketplace

Xcodegen

Skill dbmrq/agent-skills/skills/xcodegen

Author and debug XcodeGen project.yml specs — merge semantics, settings pitfalls, source filtering, dependency integration, multiplatform targets, schemes, and cache/CLI behavior. Use when editing an existing project.yml / project.yaml, fixing generated .xcodeproj issues, or when the user mentions XcodeGen, xcodegen generate, or spec-driven Xcode projects. For scaffolding a new iOS app (folders + ai-rules quality gates + warnings-as-errors), use ios-bootstrap instead.From its SKILL.md

Install
npx -y skills add dbmrq/agent-skills --skill xcodegen

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

12.5 KB, ~2.9k tokens by cl100k_base, as published. Nobody here has run it

XcodeGen

Spec reference: ProjectSpec · Usage

New apps: use ios-bootstrap first (starter project.yml, ai-rules-ios, SwiftLint/SwiftFormat/Periphery, SWIFT_TREAT_WARNINGS_AS_ERRORS). This skill is the deep XcodeGen reference.

Assume the agent knows YAML and that XcodeGen generates .xcodeproj from a spec. This skill covers behavior that is easy to get wrong.

Agent workflow

  1. Read existing project.yml and any include: files before editing.
  2. After changes, run xcodegen generate (add --use-cache only when the repo already uses caching hooks).
  3. On unexpected output, run xcodegen dump --type json to inspect the resolved spec after includes/templates merge.
  4. Build in Xcode or xcodebuild to confirm targets, schemes, and dependencies — generation succeeding does not prove linking is correct.

Required quality settings (Leio / ai-rules apps)

When the repo uses ai-rules-ios, every Swift target must include:

settings:
  base:
    SWIFT_TREAT_WARNINGS_AS_ERRORS: "YES"

The application target that runs the Quality Check script also needs:

settings:
  base:
    ENABLE_USER_SCRIPT_SANDBOXING: NO
preBuildScripts:
  - name: Quality Check
    basedOnDependencyAnalysis: false
    script: |
      set -euo pipefail
      cd "${SRCROOT}"
      ./scripts/check.sh

Snippets live under .ai-rules/quality/xcodegen/ after install. Do not invent a second lint stack inside project.yml.

Include merge semantics

Includes merge additively by default:

Existing + newResult
Both dictsDeep merge
Both arraysConcatenate (new appended)
OtherwiseNew replaces old

:REPLACE suffix — force wholesale replacement instead of merge:

include:
  - base.yml
targets:
  MyTarget:          # defined in base.yml
    sources:REPLACE:
      - only/these/sources

Other include gotchas:

  • relativePaths: false on an include makes paths in that file relative to the root spec, not the included file.
  • enable: ${ENV_VAR} can conditionally skip an include.
  • Target names can be overridden by adding name: on a target entry.
  • Comma-separated --spec a.yml,b.yml merges multiple root specs (same flags apply to all).

Settings traps

Silent ignore of simple maps

If settings uses groups, base, or configs, a flat key-value map at the same level is silently ignored:

# MARKETING_VERSION is IGNORED; only CURRENT_PROJECT_VERSION applies
settings:
  MARKETING_VERSION: 100.0.0
  base:
    CURRENT_PROJECT_VERSION: 100.0

Merge order within a Settings object: groupsbaseconfigs.

Config name matching

configs: keys match case-insensitively and by substring — except exact matches, which apply only to that config:

settings:
  configs:
    staging:          # applies to "Staging Debug" AND "Staging Release"
      SWIFT_ACTIVE_COMPILATION_CONDITIONS: STAGING
    Release:          # applies ONLY to "Release", not "Staging Release"
      SWIFT_OPTIMIZATION_LEVEL: -O

Presets vs xcconfig hierarchy

XcodeGen layers settings: setting presets → groups/base/configs → xcconfig (highest). xcconfig values also overwrite preset defaults. Build setting keys must be the raw names (IPHONEOS_DEPLOYMENT_TARGET), not Xcode display titles.

options.settingPresets: none disables Xcode-like defaults — useful when xcconfig owns everything, but then you must set all required settings explicitly.

Custom configs drop preset build settings

Config types other than debug or release (e.g. none) receive no default Debug/Release build settings from XcodeGen:

configs:
  Debug: debug
  Beta: release      # gets release-type defaults
  Custom: none       # gets NO debug/release defaults

options.defaultConfig sets the CLI default; if unset, the first config alphabetically wins.

Sources — filtering and representation

excludes / includes paths

excludes and includes are relative to the source entry's path, not project.yml. Globstar ** is enabled (Bash 4 glob). When both are set, excludes win over includes.

Source type changes Xcode behavior

typeEffect
group (default for extensionless dirs)Files tracked individually; new files on disk are not auto-picked up
folderFolder reference; contents change on disk without editing spec
syncedFolderXcode 16+ buildable folder; needs options.projectFormat: xcode16_0 or newer
fileSingle file reference

options.defaultSourceDirectoryType sets the default when a directory omits type.

Other source gotchas

  • Info.plist is never added to any build phase, regardless of buildPhase.
  • optional: true skips missing-path validation.
  • inferDestinationFiltersByPath: true filters by **/ios/* and *_iOS.swift path patterns; ignored if destinationFilters is set.
  • Overriding options.fileTypes for a built-in extension requires providing all fields for that extension.

Multiplatform and destinations

platform: [iOS, tvOS] (array)

Generates separate targets per platform with default suffix _${platform} (override via platformPrefix / platformSuffix). ${platform} in the spec is substituted. Shared PRODUCT_NAME defaults to the logical name so imports stay consistent.

supportedDestinations (Xcode 14+)

Single target, multiple destinations. platform becomes auto. Use destinationFilters on sources and dependencies.

watchOS appssupportedDestinations does not support watchOS for app targets. Create a separate target with platform: watchOS.

inferDestinationFiltersByPath helps split shared source trees; explicit destinationFilters is more predictable.

Dependencies — integration specifics

Target / project reference

projectReferences:
  FooLib:
    path: path/to/FooLib.xcodeproj
targets:
  App:
    dependencies:
      - target: FooLib/SomeTarget   # ProjectName/TargetName

Carthage

  • carthage: helper is for .framework in Carthage/Build/PLATFORM/not XCFrameworks. For XCFrameworks use framework:.
  • findFrameworks: true (or global options.findCarthageFrameworks) reads Carthage .version files — Carthage must be built before xcodegen generate.
  • The name in the spec must match the .version filename, which can differ from repo or framework name.
  • Static Carthage frameworks live under PLATFORM/Static/; set linkType: static.
  • directlyEmbedCarthageDependencies defaults true except for iOS/tvOS/watchOS applications (those use the copy-frameworks script).
  • visionOS does not support Carthage.

Swift Packages

  • Declared at project packages:; linked per-target via dependencies: - package: Name (optional product: or products:).
  • Known limitation: SPM integration breaks when the project has configs beyond Debug/Release (SR-10927).
  • Pin versions via ProjectName.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved.
  • Local packages default to a Packages group; localPackagesGroup: "" puts them at project root. excludeFromProject: true omits from generated project.

Static library + bundle in another project

dependencies:
  - bundle: MyResourceBundle   # copies pre-built bundle into resources

Only for target types that can copy resources; pairs with static libs that vend bundles elsewhere.

Linking defaults worth overriding

PropertyDefault nuance
embedtrue for apps, false otherwise
linkDepends on dependency + target types (static libs link only to executables by default)
requiresObjCLinkingtrue for library.static; adds -ObjC to dependents — leave alone unless pure Swift with no ObjC categories
transitivelyLinkDependenciesfalse at project level; set true to pull transitive deps (and embed them for bundles/apps)

SDK dependency root

dependencies:
  - sdk: Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest
    root: DEVELOPER_DIR

Default root is BUILT_PRODUCTS_DIR.

Schemes

Auto-generated target schemes (target.scheme)

configVariants creates one scheme per variant, matching configs whose names contain the variant string (e.g. StagingStaging Debug / Staging Release).

Manual schemes

  • schemePathPrefix defaults to "../../" (standalone .xcodeproj). Use "../" inside .xcworkspace — affects relative paths like StoreKit configs and GPX files.
  • Custom GPX for simulateLocation must be listed in fileGroups to be found.
  • Test plans are not generated — create .xctestplan in Xcode, check in, reference by path. Renaming test targets may require updating plans in Xcode.
  • selectedTests overrides skippedTests when both are set.

Coverage / test target references

coverageTargets:
  - MyTarget
  - ExternalProj/OtherTarget
  - package: LocalPackage/TestTarget

Generated plists

info: and entitlements: rewrite files on every generation. Do not hand-edit generated plists without moving the source of truth into the spec. INFOPLIST_FILE in settings overrides auto-generated info: for that config.

Auto-generated Info.plist keys include bundle identifiers and version fields; CFBundleExecutable is not generated for bundle targets.

Cache and CLI behavior

xcodegen generate --spec path/to/project.yml --project output/dir
xcodegen generate --use-cache          # skip regen when spec unchanged
xcodegen cache                         # refresh cache without generating (for git hooks)
xcodegen dump --type json              # resolved spec after includes/templates
Command / optionBehavior
--use-cacheSkips project write when spec hash matches cache
preGenCommandRuns before cache check — executes even when generation is skipped
postGenCommandRuns only after actual regeneration — safe for pod install
--only-plistsRegenerates plists only, skips .xcodeproj

Recommended git hooks (from XcodeGen FAQ): post-checkout / post-merge / post-rewritexcodegen generate --use-cache; pre-commitxcodegen cache.

Environment variables in spec strings: ${VAR_NAME}.

Validation toggles

When sharing YAML across projects or generating in CI without all files present:

options:
  disabledValidations:
    - missingConfigs
    - missingConfigFiles
    - missingTestPlans

Common failure modes

SymptomLikely cause
Setting in YAML has no effectFlat settings mixed with base/configs/groups; or xcconfig overrides it
Files missing from targetWrong excludes path (relative to source path, not repo root); or type: group vs folder mismatch
Carthage framework not foundNot built yet; wrong .version name; XCFramework listed as carthage: instead of framework:
SPM resolution failsExtra configs beyond Debug/Release
Scheme can't find GPX / StoreKit fileMissing fileGroups entry or wrong schemePathPrefix
Duplicate symbols / wrong linkingtransitivelyLinkDependencies or requiresObjCLinking mismatch
pod install not needed but runspostGenCommand in spec without --use-cache, or cache invalidated

Templates

targetTemplates / schemeTemplates merge via templates: list. Placeholders:

  • ${target_name} / ${scheme_name} — resolved name
  • ${attributeName} — from templateAttributes on the referencing target/scheme

Templates compose: a scheme template can reference another scheme template via nested templates:.

Additional reference

For dependency option matrices, build script phase ordering, and breakpoint/scheme action fields, see reference.md.

What ships with it: 1 file

5.8 KB alongside SKILL.md

Keep looking

Skills are one crate of 326,861. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.