swift-verify

star 32

Run the right local verification gate for a Swift project - detect XcodeGen vs plain .xcodeproj vs SwiftPM vs Tuist, then regenerate (if applicable), swiftformat --lint, swiftlint --strict, and xcodebuild test on the cheapest valid destination (macOS for pure-Swift) or swift build/test for SwiftPM. Reports each stage; --fix lets SwiftFormat rewrite.

charlesjones-dev By charlesjones-dev schedule Updated 6/3/2026

name: swift-verify description: "Run the right local verification gate for a Swift project - detect XcodeGen vs plain .xcodeproj vs SwiftPM vs Tuist, then regenerate (if applicable), swiftformat --lint, swiftlint --strict, and xcodebuild test on the cheapest valid destination (macOS for pure-Swift) or swift build/test for SwiftPM. Reports each stage; --fix lets SwiftFormat rewrite." argument-hint: "[path] [--fix] [--no-test] [--destination=]" allowed-tools: [Bash, Read, Glob, Grep] disable-model-invocation: true

Swift Verify

You run a Swift project's local quality gate, adapting the pipeline to how the project is built. This is the portable analog of a hand-written scripts/verify.sh: it discovers the build system and tools, runs them in the order that does not waste work, and reports each stage honestly.

This is the Swift-native specialization of a generic preflight; it does not duplicate ai-workflow's /workflow-preflight (Node/Python/.NET/Go/Rust). For release-blocker auditing (entitlements, Xcode Cloud, build numbers) use /swift-preflight; for general bug-finding use /code-review.

Arguments

$ARGUMENTS:

  • path - repo root (default cwd).
  • --fix - allow swiftformat to rewrite in place (default is lint-only / non-destructive).
  • --no-test - skip the build/test stage (format + lint only; good for doc-only changes).
  • --destination=<dest> - override the xcodebuild destination (e.g. platform=iOS Simulator,name=iPhone 16).

Phase 0: Detect build system + tools

  • XcodeGen: project.yml + command -v xcodegen.
  • Tuist: Project.swift + command -v tuist.
  • Plain Xcode: *.xcodeproj / *.xcworkspace, no generator.
  • SwiftPM: Package.swift (library or executable).

Tool availability: command -v swiftformat swiftlint xcodegen xcodebuild swift. If a required tool is missing, report it and the install hint (brew install swiftformat swiftlint xcodegen) and continue with the stages you can run - do not abort the whole gate for one missing optional tool.

Config presence: .swiftformat, .swiftlint.yml. If absent, run the tool with defaults but note that the project has no pinned config (so local and CI can diverge).

Phase 1: Regenerate (generator projects only)

If XcodeGen: xcodegen generate (quiet). If Tuist: tuist generate.

Why first: newly added .swift files are not in the .xcodeproj until regen, and SourceKit diagnostics for them are stale. Regenerating makes xcodebuild authoritative. On a plain .xcodeproj or SwiftPM, skip this stage.

Caution: regeneration rewrites the pbxproj from project.yml. If the working tree has uncommitted pbxproj hand-edits, warn the user that regen will revert them (this is exactly the drift trap - see /swift-preflight Check 1). Do not regen over a dirty pbxproj without noting it.

Phase 2: Format

  • Default / lint mode: swiftformat --lint . (reports, exits non-zero on diffs, writes nothing).
  • --fix mode: swiftformat . (rewrites in place).

Run format before lint so SwiftLint does not flag issues the formatter would have fixed. Note the known SwiftFormat↔SwiftLint modifier_order standoff (nonisolated(unsafe) private static): if both fire on the same line, that is the documented conflict, not a real defect - prefer moving the helper to file scope, or a scoped per-line disable pair.

Phase 3: Lint (strict)

swiftlint lint --strict --quiet. Strict = warnings fail the run, matching CI. Report each violation with file:line. Do not suggest // swiftlint:disable as a fix unless the rule genuinely cannot be satisfied (e.g. an override class func that cannot be static); even then require a one-line justification comment. Never suggest --no-verify or blanket disables.

Phase 4: Build / test

Pick the cheapest valid destination:

  • SwiftPM: swift build then swift test (no simulator needed).
  • App / framework with macOS support: xcodebuild -scheme <scheme> -destination "platform=macOS,arch=arm64" test. macOS is cheapest (no simulator boot) and is the right default for pure-Swift logic (models, services, persistence, networking).
  • iOS-only target: requires a simulator runtime. Use --destination if given, else pick an available iOS simulator from xcrun simctl list devices available. If no iOS runtime is installed, report it and the non-interactive install path xcodebuild -downloadPlatform iOS rather than failing silently; fall back to building (not testing) if no destination is bootable.

For multiplatform unit-test targets generated by XcodeGen, remember the macOS TEST_HOST override is required ($(BUILT_PRODUCTS_DIR)/App.app/Contents/MacOS/App); if xcodebuild test fails to launch the host on macOS, surface that as the likely cause.

Skip this phase entirely if --no-test.

Phase 5: Report

Swift Verify — <repo>  (XcodeGen · macOS destination)

xcodegen generate   ok
swiftformat --lint   3 files would change   (run with --fix to rewrite)
swiftlint --strict   2 violations
   App/Services/AuthService.swift:42  force_unwrapping
   App/Views/ReaderView.swift:88      modifier_order
xcodebuild test      52 passed, 0 failed

Result: FAIL (format + lint)
Next: /swift-verify --fix to auto-format, then fix the 2 lint violations.

Report the true outcome of every stage, including the exact failing command output (trim to the relevant lines). If a stage was skipped (missing tool, --no-test, no bootable destination), say so explicitly - never imply a skipped stage passed. Exit-code semantics: clean = all stages green; any failing stage = overall FAIL.

Install via CLI
npx skills add https://github.com/charlesjones-dev/claude-code-plugins-dev --skill swift-verify
Repository Details
star Stars 32
call_split Forks 3
navigation Branch main
article Path SKILL.md
More from Creator
charlesjones-dev
charlesjones-dev Explore all skills →