nicklockwood/SwiftFormat
A command-line tool and Xcode Extension for formatting Swift code
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3d ago
- ✓13 active contributors
- ✓MIT licensed
Show 3 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Concentrated ownership — top contributor handles 71% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/nicklockwood/swiftformat)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/nicklockwood/swiftformat on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: nicklockwood/SwiftFormat
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/nicklockwood/SwiftFormat shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 3d ago
- 13 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Concentrated ownership — top contributor handles 71% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live nicklockwood/SwiftFormat
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/nicklockwood/SwiftFormat.
What it runs against: a local clone of nicklockwood/SwiftFormat — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in nicklockwood/SwiftFormat | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch main exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 33 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of nicklockwood/SwiftFormat. If you don't
# have one yet, run these first:
#
# git clone https://github.com/nicklockwood/SwiftFormat.git
# cd SwiftFormat
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of nicklockwood/SwiftFormat and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "nicklockwood/SwiftFormat(\\.git)?\\b" \\
&& ok "origin remote is nicklockwood/SwiftFormat" \\
|| miss "origin remote is not nicklockwood/SwiftFormat (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
&& ok "default branch main exists" \\
|| miss "default branch main no longer exists"
# 4. Critical files exist
test -f "CommandLineTool/main.swift" \\
&& ok "CommandLineTool/main.swift" \\
|| miss "missing critical file: CommandLineTool/main.swift"
test -f "Package.swift" \\
&& ok "Package.swift" \\
|| miss "missing critical file: Package.swift"
test -f "Rules.md" \\
&& ok "Rules.md" \\
|| miss "missing critical file: Rules.md"
test -f "EditorExtension/Extension/SourceEditorExtension.swift" \\
&& ok "EditorExtension/Extension/SourceEditorExtension.swift" \\
|| miss "missing critical file: EditorExtension/Extension/SourceEditorExtension.swift"
test -f "EditorExtension/Shared/OptionsStore.swift" \\
&& ok "EditorExtension/Shared/OptionsStore.swift" \\
|| miss "missing critical file: EditorExtension/Shared/OptionsStore.swift"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 33 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~3d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/nicklockwood/SwiftFormat"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
SwiftFormat is a command-line tool and Xcode editor extension that reformats Swift code beyond simple whitespace adjustment—it can insert/remove implicit self, eliminate redundant parentheses, correct operator spacing, and enforce idiomatic Swift patterns. It's deployed as a standalone binary, Xcode extension, Swift Package Manager plugin, and Docker image to standardize code style across teams and CI/CD pipelines. Dual-architecture project: CommandLineTool/main.swift wraps a core formatting engine; EditorExtension/ contains the Xcode UI in EditorExtension/Application/Source/ (AppDelegate, RulesViewController, UserSelection) and extension hooks in EditorExtension/Extension/ (FormatFileCommand, SourceEditorExtension). Config is .swiftformat file; CI is GitHub Actions workflows in .github/workflows/.
👥Who it's for
Swift developers and teams who need automated code style enforcement—specifically those using Xcode, command-line workflows, GitHub Actions, or pre-commit hooks who want consistent formatting beyond what swiftc provides, plus maintainers who want linting feedback without manual review.
🌱Maturity & risk
Production-ready. The project has CI/CD pipelines across build.yml, docker.yml, release.yml, and windows_release.yml; extensive GitHub Actions workflows for notarization and validation; and CHANGELOG.md documenting changes. The codebase is 6MB+ of Swift with supporting shell and Objective-C, indicating a mature, actively maintained formatter used at scale.
Low risk for production use but single-maintainer dependency: the repo is authored by nicklockwood with no visible co-maintainers in file structure. Breaking changes are documented in CHANGELOG.md. No direct dependency bloat visible—the project is self-contained. Windows support (windows_release.yml) and Docker packaging suggest broad platform coverage, but Swift toolchain version constraints could impact CI compatibility.
Active areas of work
Active maintenance with multi-platform releases: Windows release automation (windows_release.yml), macOS notarization (notarize.yml), Docker builds (docker.yml), and PR validation (validate_pr.yml) are all wired up. The project has pre-commit hook support (.pre-commit-hooks.yaml), dependabot.yml for dependency tracking, and label-based issue automation (label_fixed_issues.yml).
🚀Get running
git clone https://github.com/nicklockwood/SwiftFormat.git && cd SwiftFormat && swift build -c release. The CommandLineTool/main.swift is the entry point; binary output goes to .build/release/swiftformat. For Xcode extension development, open the project in Xcode and run EditorExtension targets directly.
Daily commands: swift build -c release && .build/release/swiftformat --help (for CLI). For editor extension: open EditorExtension/Application.xcodeproj in Xcode, select SwiftFormatter target, press Run. For Docker: docker build -t swiftformat . && docker run swiftformat --help.
🗺️Map of the codebase
CommandLineTool/main.swift— Entry point for the CLI tool; demonstrates how the formatting engine is invoked and integrated with command-line argument parsing.Package.swift— Swift Package Manager manifest defining all targets, dependencies, and build configuration; required reading to understand project structure.Rules.md— Comprehensive documentation of all formatting rules; essential reference for understanding the rule system and rule behavior.EditorExtension/Extension/SourceEditorExtension.swift— Xcode extension entry point showing how SwiftFormat integrates with Xcode's source editor; critical for understanding the extension architecture.EditorExtension/Shared/OptionsStore.swift— Configuration management for storing and retrieving user-selected formatting options; core to the settings system used across CLI and extensions..swiftformat— Root configuration file example showing the format and default rules; every contributor must understand the config file syntax.CONTRIBUTING.md— Contribution guidelines and development workflow; required reading for anyone submitting changes.
🛠️How to make changes
Add a New Formatting Rule
- Create a new rule struct conforming to the Rule protocol in the main SwiftFormat target (
Sources/SwiftFormat/Rules/*.swift (new file following naming convention)) - Implement the rule's description, configuration options, and formatting logic (
Sources/SwiftFormat/Rules/*.swift) - Register the rule in the Rules collection that drives rule discovery (
Sources/SwiftFormat/RulesStore.swift or equivalent rule registry) - Add snapshot test cases in the appropriate Snapshots subdirectory (
Snapshots/[FeatureName]/Input.swift and Expected.swift) - Document the rule in Rules.md with examples and configuration (
Rules.md)
Extend the CLI with a New Command
- Add the command option handling in the argument parser section (
CommandLineTool/main.swift) - Create a new command type or handler in the CLI module (
Sources/SwiftFormat/CLI/*.swift (new or existing)) - Wire the command to the formatter engine and output results (
CommandLineTool/main.swift) - Add integration test in RegressionTests covering the new command (
RegressionTests/RegressionTests.swift)
Add a New UI Control to the Settings App
- Define a new preference key in OptionsStore or RulesStore (
EditorExtension/Shared/OptionsStore.swift or RulesStore.swift) - Add a UI element (button, toggle, text field) in the view controller (
EditorExtension/Application/Source/RulesViewController.swift) - Create a custom table cell view if needed for the control type (
EditorExtension/Application/Source/ListSelectionTableCellView.swift (or new file)) - Connect the UI element to read/write from OptionsStore via UserDefaults (
EditorExtension/Application/Source/RulesViewController.swift)
Improve Xcode Extension Integration
- Understand how the extension receives text buffer and selection from Xcode (
EditorExtension/Extension/XCSourceTextBuffer+SwiftFormat.swift) - Implement or modify the command handler (FormatFileCommand, FormatSelectionCommand, etc.) (
EditorExtension/Extension/FormatFileCommand.swift) - Load configuration and apply formatting rules via SwiftFormat engine (
EditorExtension/Extension/SourceEditorExtension.swift) - Update the extension's Info.plist if new capabilities or permissions are needed (
EditorExtension/Extension/Info.plist)
🔧Why these technologies
- Swift & Swift Package Manager — Targets Swift developers natively; SPM enables distribution, plugin support, and cross-platform building (macOS, Linux, Windows).
- Xcode Source Editor Extension API — Integrates SwiftFormat directly into Xcode's editor, providing real-time or on-demand formatting without leaving the IDE.
- macOS Application (Cocoa/AppKit) — Provides a native settings UI for configuring rules and options specific to the Xcode extension.
- GitHub Actions CI/CD — Enables automated testing, building, and release workflows across multiple platforms (macOS, Linux, Windows).
- Configuration files (.swiftformat) — Allows per-project and per-user customization without requiring CLI flags; supports hierarchical inheritance (child/.swiftformat overrides parent).
⚖️Trade-offs already made
-
Single binary CLI tool with integrated Xcode extension
- Why: Reduces maintenance overhead and ensures feature parity between CLI and IDE.
- Consequence: Extension and CLI must stay synchronized; changes require testing on both paths.
-
Snapshot-based regression testing instead of exhaustive unit tests
- Why: Easier to validate complex formatting rules against real Swift code patterns; golden files are human-readable.
- Consequence: Snapshot updates can mask unintended changes; reviewers must carefully inspect snapshot diffs.
-
Configuration files inherit hierarchically (child/.swiftformat overrides parent)
- Why: Allows teams to set project-wide rules while developers can override locally.
- Consequence: Adds complexity to config resolution; cascading rules can be surprising if not well-documented.
-
Extension communicates with
- Why: undefined
- Consequence: undefined
🪤Traps & gotchas
- macOS notarization (notarize.yml) requires valid signing credentials and AppleID secrets—local builds skip this but distributed binaries must be notarized. 2. Windows builds (windows_release.yml) use a separate GitHub Actions runner; Swift on Windows may have different behavior than macOS/Linux. 3. The .swiftformat config file format is custom INI-like syntax; typos silently use defaults. 4. EditorExtension requires Xcode 11+ and Swift Playgrounds may not support the extension. 5. No visible Swift Package.swift in file list suggests this may not be a standard SPM package despite mentioning 'Swift Package Manager plugin' in README—check if it's provided separately.
🏗️Architecture
💡Concepts to learn
- Lexical Analysis / Tokenization — SwiftFormat tokenizes Swift source into logical units (keywords, operators, identifiers, whitespace) before applying formatting rules; understanding token streams is essential to modify formatting logic
- AST (Abstract Syntax Tree) manipulation — Formatter rules must understand Swift syntax structure (declarations, expressions, control flow) to make intelligent formatting decisions like removing redundant parentheses or inserting implicit self
- Code Generation / Pretty Printing — After tokenizing and analyzing code, SwiftFormat regenerates formatted source; understanding idempotency (repeated runs produce same output) is critical for formatter correctness
- Xcode Source Editor Extension APIs (NSE) — EditorExtension uses the SourceKitService and NSE plugin model to integrate with Xcode's editor; knowing NSE protocol requirements is essential for extending the editor integration
- macOS Code Signing & Notarization — Release pipeline (notarize.yml) signs and notarizes binaries for macOS Gatekeeper; understanding codesign and xcrun notarytool is needed to troubleshoot distribution issues
- CLI Argument Parsing & Configuration Precedence — SwiftFormat resolves config from CLI flags, .swiftformat files, and defaults; understanding the precedence chain is critical when debugging why a rule isn't applied
- GitHub Actions Workflow Automation — The project uses conditional workflows (validate_pr.yml, release.yml, windows_release.yml) with secrets and matrix builds; learning the GitHub Actions DSL is needed to modify CI/CD
🔗Related repos
realm/SwiftLint— Complementary linter for Swift code that detects style violations SwiftFormat can auto-fix; both are used together in CI workflowsapple/swift-format— Official Swift formatter from Apple Foundation; SwiftFormat is the community-driven alternative with more aggressive style correctionHomebrew/homebrew-core— SwiftFormat is distributed via Homebrew (brew install swiftformat); the formula lives in this repo's core packagespre-commit/pre-commit— SwiftFormat integrates with pre-commit hooks (.pre-commit-hooks.yaml in this repo); users install it as a pre-commit framework pluginactions/checkout— GitHub Actions step used in all the CI workflows (.github/workflows/) to check out code before running swiftformat
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for EditorExtension/Extension command handlers
The Xcode Extension has three command handlers (FormatFileCommand.swift, FormatSelectionCommand.swift, LintFileCommand.swift) that interact with XCSourceTextBuffer. Currently, there's no dedicated test suite for these Extension handlers. Adding tests would catch regressions in the Xcode integration layer and improve maintainability.
- [ ] Create Tests/EditorExtensionTests/ directory structure
- [ ] Add unit tests for FormatFileCommand.swift covering various buffer states and edge cases
- [ ] Add unit tests for FormatSelectionCommand.swift testing selection range handling
- [ ] Add unit tests for LintFileCommand.swift and CommandErrors.swift error reporting
- [ ] Mock XCSourceTextBuffer interactions using protocol-based design if needed
- [ ] Integrate new tests into build.yml workflow to run on every PR
Implement platform-specific integration tests for Windows release binary
The repo has Platforms/Windows/SwiftFormat.wixproj and windows_release.yml workflow, but there's no visible test coverage validating that the Windows-built binary works correctly. A new workflow or test suite could verify Windows MSI installation, CLI functionality, and basic formatting on Windows runners.
- [ ] Create a new workflow file .github/workflows/windows_integration_tests.yml that runs on windows-latest
- [ ] Add test script to verify the generated MSI installer installs correctly
- [ ] Add CLI smoke tests (e.g., test
swiftformat --version,swiftformat --help, basic file formatting) - [ ] Verify the Windows binary can parse and format sample Swift files correctly
- [ ] Report results back to PR checks for visibility
Add integration tests for PluginTests/Sources/PackageUsingPlugin Swift Package Plugin
The repo includes a Swift Package Plugin architecture (visible in PluginTests/Package.swift and PluginTests/Sources), but there's no automated test validating that the plugin integrates correctly with swift build workflows. This is a growing Swift feature and needs test coverage to prevent breakage.
- [ ] Examine PluginTests/Package.swift to understand the plugin's expected interface
- [ ] Create PluginTests/Tests/ with integration tests that invoke
swift buildon a test package using the SwiftFormat plugin - [ ] Add tests verifying plugin formats files correctly when used as a build tool plugin
- [ ] Test plugin with different Swift versions matching Package.swift's supported platforms
- [ ] Add PluginTests integration to build.yml workflow under a conditional step
🌿Good first issues
- Add tests for EditorExtension/Extension/CommandErrors.swift—error handling for Xcode commands is present but likely lacks unit test coverage; create tests in a Tests/ directory mirroring the structure.
- Document the .swiftformat configuration grammar more formally—the README mentions 'Config file' but the file list shows .swiftformat without a schema; write a formal spec or validation in a docs/ folder.
- Implement missing rule UI in RulesViewController.swift—some rules are supported by the CLI but not exposed in the Xcode UI settings; add ListSelectionTableCellView entries for unexposed rules.
⭐Top contributors
Click to expand
Top contributors
- @Copilot — 71 commits
- @calda — 9 commits
- @dependabot[bot] — 6 commits
- @kimdv — 3 commits
- @ghugues — 2 commits
📝Recent commits
Click to expand
Recent commits
a5fa7a6— Update for 0.61.1 release (calda)814ae64— Update VSCode integration instructions to use Run on Save (#2520) (anuragg-saxenaa)3e5bdf2— fix race condition when parsing config files (#2521) (ghugues)8b998f0— Fix redundantStaticSelf false positive inside closures and nested functions (#2518) (Copilot)b48ffbc— Fix docs typo (nicklockwood)a279d73— Bump the github-actions group with 5 updates (#2453) (dependabot[bot])249801f— Bump the github-actions group with 5 updates (#2453) (dependabot[bot])3c174b1— Update dependabot PRs to target develop branch (#2516) (calda)0af344d— Improve "Label Fixed Issues" CI workflow (#2515) (Copilot)1e0aaaa— Fix unsafe keyword dot-spacing edge case (#2513) (AlexeyRadomskiy)
🔒Security observations
SwiftFormat has a reasonable security posture overall. The codebase is a command-line tool and Xcode extension written in Swift with minimal external dependencies visible. Key strengths include use of Docker scratch images for minimal attack surface and checksum verification for SDK downloads. Main concerns are: (1) lack of binary verification in Docker pipeline, (2) potential GitHub Actions workflow security issues that need review, (3) Xcode extension entitlements that should be audited for excessive permissions, and (4) pre-commit hooks configuration that should be validated. No critical vulnerabilities detected from static analysis of file structure, but runtime security depends on the content of workflows and configuration files not fully visible in this analysis.
- Medium · Dockerfile uses 'scratch' base image without verification —
Dockerfile (runner stage). The final Docker image uses 'scratch' as the base, which is extremely minimal. While this reduces attack surface, there's no verification that the copied binary (/usr/bin/swiftformat) hasn't been tampered with. The builder stage downloads a Swift SDK with a checksum, but the final binary isn't verified before being copied to the scratch image. Fix: Consider implementing binary verification in the builder stage before copying to scratch. Add a checksum verification step for the compiled swiftformat binary, or use a minimal base image with package verification capabilities. - Low · Swift SDK download over HTTPS without additional verification —
Dockerfile (builder stage, RUN swift sdk install). While the Dockerfile includes a checksum for the Swift SDK (SHA256), the download is from download.swift.org. There's no signature verification beyond the checksum, and the URL uses HTTPS but lacks additional verification mechanisms like GPG signatures. Fix: Implement additional verification such as GPG signature verification if available from Swift.org. Consider pinning the SDK version in a secure artifact registry under organizational control. - Low · GitHub Actions workflows may lack security hardening —
.github/workflows/. Multiple GitHub Actions workflows are present (.github/workflows/) including build.yml, release.yml, notarize.yml, and windows_release.yml. Without reviewing the content, typical risks include: using latest action versions instead of pinned commits, missing branch protection rules, and potential privilege escalation in release workflows. Fix: Review all GitHub Actions workflows for: (1) Pin actions to specific commit SHAs rather than tags/latest, (2) Use minimal permissions (principle of least privilege) with 'permissions' declarations, (3) Implement required status checks and branch protection, (4) Use OIDC tokens for authentication where possible instead of personal access tokens. - Low · Pre-commit hooks configuration present —
.pre-commit-hooks.yaml. The presence of .pre-commit-hooks.yaml suggests the project uses pre-commit framework. Without seeing the configuration, potential risks include: executing arbitrary code during commits, pulling hooks from untrusted sources, and bypassing security checks. Fix: Ensure all hooks in .pre-commit-hooks.yaml: (1) Use pinned versions/commits, (2) Only execute trusted, internal scripts, (3) Include security-focused hooks like secret scanning, (4) Document the purpose and safety of each hook. - Low · Xcode Extension lacks visible security configuration —
EditorExtension/Application/SwiftFormatter.entitlements, EditorExtension/Extension/SwiftFormatter.entitlements. The EditorExtension components (Application and Extension) handle source code and integrate with Xcode. The entitlements files (SwiftFormatter.entitlements) are present but their contents aren't shown. Xcode extensions have elevated privileges and could pose security risks if not properly configured. Fix: Review entitlements files to ensure: (1) Only necessary capabilities are requested, (2) Code signing is properly configured, (3) Sandboxing is enabled where possible, (4) No excessive file system or network access is granted. - Low · Docker cache configuration may expose build artifacts —
Dockerfile (RUN instruction with cache mount). The Dockerfile uses build cache mounts (--mount=type=cache) for .build directory. While this improves performance, build artifacts could potentially be leaked if the cache is not properly isolated or if temporary build files contain sensitive information. Fix: Ensure Docker BuildKit cache isolation is properly configured. Regularly clean build caches in CI/CD pipelines and verify that intermediate build artifacts don't contain sensitive data.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.