Centralized Swift code quality tooling with smart configuration discovery. Three command-line binaries plus 12 custom SwiftSyntax-based lint rules that text-pattern linters cannot express.
swiftformat-smart: SwiftFormat with project-aware config discoveryswiftlint-smart: SwiftLint with project-aware config discoveryswiftlintcustom-smart: Custom SwiftSyntax-based linting rules with parallel processing
All three walk up the directory tree to find a project-specific config, falling back to the shared configs in Configs/ when none is present.
cd ~/Developer/swift-quality-tools
./Scripts/build-all.shThat builds all three binaries plus the custom rule engine. Manual build:
swift build -c releaseBinaries land in .build/release/:
~/Developer/swift-quality-tools/.build/release/
├── swiftformat-smart
├── swiftlint-smart
└── swiftlintcustom-smart
- SwiftFormat:
brew install swiftformat - SwiftLint:
brew install swiftlint - Swift 5.9+ for building the tools themselves
swiftformat-smart # current directory
swiftformat-smart Sources/MyFile.swift # single file
swiftformat-smart Sources/ # directory
swiftformat-smart --config path/to/.swiftformat.yml # explicit configswiftlint-smart # current directory
swiftlint-smart Sources/MyFile.swift # single file
swiftlint-smart Sources/ # directory
swiftlint-smart --config path/to/.swiftlint.yml # explicit configswiftlintcustom-smart # parallel by default
swiftlintcustom-smart Sources/MyFile.swift # single file
swiftlintcustom-smart Sources/ # directory
swiftlintcustom-smart --sequential Sources/ # debug modeParallel processing is on by default and uses every available CPU core. Pass --sequential for predictable output when debugging a rule. The custom rule engine auto-builds on first run.
For all three tools:
--configflag if provided- Project-local config in current directory
- Walk up parent directories until a config is found
- Fall back to
Configs/shared-*.ymlin this repo
The rules live in CustomRules/swiftlint-swiftsyntax-integration/rule-engine/test-custom-rule.swift.
skimmable_body: SwiftUI Viewbodyproperties capped at 15 linesno_group_body:bodymust not be a top-levelGroup(unless it has modifiers)one_top_level_view:bodymust have exactly one top-level viewexcessive_indentation: physical indentation capped at 16 spaces / 4 tabsstack_minimum_children:VStack/HStack/ZStackmust have at least 2 children (ForEachandif/elsewith 2+ branches allowed)view_structure_order: view property ordering (currently disabled, has bugs)no_wrapper_body: flags pointless wrapperbodypropertiesblank_line_import_separation: blank line required between regular and@testableimportspreview_required: every file declaring aView,ViewModifier, orShapemust have at least one#Previewno_exported_import: bans@_exported import(underscore prefix is unstable Swift API)prefer_swift_testing: flagsimport XCTestandXCTAssert*calls in favor of Swift Testingprefer_shorthand_optional_binding: flagsif let foo = barin favor of the shorthandif let bar
- Edit
CustomRules/swiftlint-swiftsyntax-integration/rule-engine/test-custom-rule.swift - Rebuild:
./Scripts/build-all.sh
Custom rules support line-specific suppression using the swiftlintcustom: prefix (separate from SwiftLint's swiftlint: so the standard linter's superfluous_disable_command safety check still works):
// swiftlintcustom:disable:next excessive_nesting
var computed: String {
// Deep nesting allowed here
}
func deep() { // swiftlintcustom:disable:this excessive_nesting
// ...
}See docs/swiftlint-directive-support.md for the full directive syntax.
The hook system at ~/.claude/hooks/ calls into the binaries automatically:
# ~/.claude/hooks/formatters/swift_formatter.py
SWIFT_TOOLS_PATH = Path.home() / "Developer" / "swift-quality-tools" / ".build" / "release"When you edit a Swift file in Claude Code, formatting runs immediately and lint warnings show up in the next response.
Add a "Run Script" build phase to surface lint warnings in the Issue Navigator:
"${HOME}/Developer/swift-quality-tools/Scripts/xcode-lint.sh"The script runs both linters and works around Xcode's subprocess output suppression by parsing and re-echoing warnings as standard Xcode warning lines.
swiftlintcustom-smart auto-detects when it's running inside Xcode (via XCODE_VERSION_ACTUAL) and formats violations as clickable warnings without any flags.
If you want explicit control instead of the wrapper script:
if [ -f "${HOME}/Developer/swift-quality-tools/.build/release/swiftlint-smart" ]; then
"${HOME}/Developer/swift-quality-tools/.build/release/swiftlint-smart" "${SRCROOT}" || true
fi
if [ -f "${HOME}/Developer/swift-quality-tools/.build/release/swiftlintcustom-smart" ]; then
"${HOME}/Developer/swift-quality-tools/.build/release/swiftlintcustom-smart" "${SRCROOT}"
fiSwiftFormat is intentionally not in the build phase. It runs on every edit through the Claude Code hook, and build phases stay linters-only.
Add the binaries to your PATH:
# In ~/.zshrc
export PATH="$HOME/Developer/swift-quality-tools/.build/release:$PATH"
swiftformat-smart .
swiftlint-smart .
swiftlintcustom-smart .shared-swiftformat.yml: SwiftFormat ruleset, Swift 6.0 targetshared-swiftlint.yml: SwiftLint ruleset, custom SwiftUI rules
Place either of these in a project root to override the shared config:
.swiftformat.ymlor.swiftformat.swiftlint.ymlor.swiftlint.yaml
The tools discover them automatically.
swift-quality-tools/
├── Package.swift # Swift Package definition
├── Scripts/
│ ├── build-all.sh # Build everything
│ └── test-tools.sh # Integration validation
├── Sources/
│ ├── SwiftFormatSmart/ # swiftformat-smart binary
│ ├── SwiftLintSmart/ # swiftlint-smart binary
│ ├── SwiftLintCustomSmart/ # swiftlintcustom-smart binary
│ └── SharedUtilities/
│ ├── ConfigDiscovery.swift # Walk-up config finder
│ ├── ColoredOutput.swift # Terminal colors
│ ├── ProcessRunner.swift # Subprocess execution
│ └── ErrorFormatter.swift # Self-healing error messages
├── Configs/ # Shared rulesets
│ ├── shared-swiftformat.yml
│ └── shared-swiftlint.yml
├── CustomRules/
│ └── swiftlint-swiftsyntax-integration/
│ └── rule-engine/
│ ├── Package.swift
│ └── test-custom-rule.swift
└── .build/release/ # Compiled binaries
cd ~/Developer/swift-quality-tools
./Scripts/build-all.sh./Scripts/run-tests.sh # full suite (unit + integration)
swift test # unit tests only (Swift Testing)
./Scripts/test-tools.sh # integration only (binary validation)Manual testing on this repo or any other Swift project:
./.build/release/swiftformat-smart Sources/
./.build/release/swiftlint-smart Sources/
./.build/release/swiftlintcustom-smart Sources/All three tools emit self-healing errors in a fixed shape so the Claude Code hook can act on them:
[Tool] Error: [ErrorType]
Problem: [What is wrong]
Context: [What was being attempted]
Fix: [Concrete next step]
The shape is consistent enough that an LLM can parse it and either fix the issue or surface a clear question.
Swift quality tooling by Synodic Studio. See LICENSE for the terms.