Skills swiftlint

Swift linting and style enforcement via CLI

install
source · Clone the upstream repo
git clone https://github.com/openclaw/skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/openclaw/skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/alexissan/swiftlint" ~/.claude/skills/clawdbot-skills-swiftlint && rm -rf "$T"
manifest: skills/alexissan/swiftlint/SKILL.md
source content

SwiftLint

Enforce Swift style and conventions with static analysis. Lint entire projects, autocorrect fixable violations, manage rules, and integrate with Xcode and CI — all from the CLI.


Verify Installation

swiftlint version

If not installed:

brew install swiftlint

Or via Mint:

mint install realm/SwiftLint

Or as a Swift Package Manager plugin (add to

Package.swift
):

.package(url: "https://github.com/realm/SwiftLint.git", from: "0.57.0")

Then run:

swift package plugin swiftlint

Basic Usage

Lint Current Directory

swiftlint

This recursively lints all

.swift
files from the current directory.

Lint a Specific Path

swiftlint lint --path Sources/

Lint Specific Files

swiftlint lint --path Sources/App/ViewModel.swift

Lint from Standard Input

cat MyFile.swift | swiftlint lint --use-stdin --quiet

Agent guidance: When a user says "check my code style" or "lint my Swift code," run

swiftlint
from the project root. If they point to a specific file or folder, use
--path
.


Autocorrect

SwiftLint can automatically fix certain violations.

Fix All Autocorrectable Violations

swiftlint --fix

Fix a Specific Path

swiftlint --fix --path Sources/

Fix a Specific File

swiftlint --fix --path Sources/App/ViewModel.swift

Preview What Would Be Fixed (Dry Run)

Lint first to see violations, then fix:

swiftlint lint --path Sources/ && swiftlint --fix --path Sources/

Agent guidance: Always lint before autocorrecting so the user sees what will change. Some violations are not autocorrectable — report those separately after fixing.


Output Formats

Default (Human-Readable)

swiftlint

Output:

Sources/App.swift:12:1: warning: Line Length Violation: ...

JSON

swiftlint lint --reporter json

CSV

swiftlint lint --reporter csv

Checkstyle (XML)

swiftlint lint --reporter checkstyle

GitHub Actions

swiftlint lint --reporter github-actions-logging

Xcode Summary (plist)

swiftlint lint --reporter xcode-summary

SonarQube

swiftlint lint --reporter sonarqube

Markdown

swiftlint lint --reporter markdown

Save to File

swiftlint lint --reporter json > swiftlint-results.json

All Available Reporters

ReporterFormatBest For
xcode
Xcode-compatible (default)Local development
json
JSON arrayProgrammatic processing
csv
CSVSpreadsheet analysis
checkstyle
XMLJenkins, CI tools
codeclimate
Code Climate JSONCode Climate integration
github-actions-logging
GitHub annotationsGitHub Actions CI
sonarqube
SonarQube JSONSonarQube integration
markdown
Markdown tablePR comments
emoji
Emoji-decoratedFun terminal output
html
HTML reportBrowser viewing
junit
JUnit XMLTest reporting tools
xcode-summary
PlistXcode build summaries

Agent guidance: Use

--reporter json
when you need to parse results programmatically. Use
--reporter github-actions-logging
on GitHub Actions to get inline annotations on PRs.


Rules

List All Rules

swiftlint rules

Search for a Specific Rule

swiftlint rules | grep "force_cast"

Show Rule Details

swiftlint rules force_cast

Rule Identifiers Quick Reference

Rules fall into categories:

Enabled by Default (Common)

RuleWhat It Catches
line_length
Lines exceeding max length (default 120 warning, 200 error)
trailing_whitespace
Whitespace at end of lines
trailing_newline
Missing or extra trailing newlines
opening_brace
Opening brace placement
closing_brace
Closing brace placement
colon
Colon spacing (e.g.,
let x : Int
let x: Int
)
comma
Comma spacing
force_cast
Use of
as!
force_try
Use of
try!
force_unwrapping
Use of
!
on optionals (opt-in)
type_body_length
Type bodies exceeding max lines
function_body_length
Function bodies exceeding max lines
file_length
Files exceeding max lines
cyclomatic_complexity
High cyclomatic complexity
nesting
Deep nesting levels
identifier_name
Naming convention violations
type_name
Type naming convention violations
unused_import
Unused import statements (opt-in)
unused_declaration
Unused declarations (opt-in)
vertical_whitespace
Excessive blank lines
todo
TODO/FIXME comments as warnings
mark
Improper MARK comment format
void_return
Explicit
-> Void
instead of
-> ()
syntactic_sugar
Prefer
[Int]
over
Array<Int>
redundant_optional_initialization
var x: Int? = nil
(nil is default)
redundant_string_enum_value
Enum case name matches raw value

Opt-In (Must Be Explicitly Enabled)

RuleWhat It Catches
explicit_type_interface
Missing explicit type annotations
missing_docs
Missing documentation comments
multiline_arguments
Multiline function call formatting
multiline_parameters
Multiline function param formatting
vertical_parameter_alignment
Parameter alignment in declarations
sorted_imports
Unsorted import statements
file_header
Missing or incorrect file headers
accessibility_label_for_image
Images without accessibility labels
accessibility_trait_for_button
Buttons without accessibility traits
strict_fileprivate
Prefer
private
over
fileprivate
prohibited_interface_builder
Storyboard/XIB usage
no_magic_numbers
Magic numbers in code
prefer_self_in_static_references
Self
over explicit type name in static context
balanced_xctest_lifecycle
setUp without tearDown
test_case_accessibility
Test methods not marked correctly

Agent guidance: When setting up SwiftLint for a new project, start with defaults and only add opt-in rules the user specifically requests. Don't overwhelm with every possible rule.


Configuration (.swiftlint.yml)

SwiftLint reads

.swiftlint.yml
from the current directory (or parent directories).

Generate a Default Config

There's no built-in generator, but here's a minimal config:

# .swiftlint.yml

# Paths to include (default: all Swift files)
included:
  - Sources
  - Tests

# Paths to exclude
excluded:
  - Pods
  - DerivedData
  - .build
  - Packages

# Disable specific rules
disabled_rules:
  - todo
  - trailing_whitespace

# Enable opt-in rules
opt_in_rules:
  - sorted_imports
  - unused_import
  - missing_docs

# Configure specific rules
line_length:
  warning: 120
  error: 200
  ignores_comments: true
  ignores_urls: true

type_body_length:
  warning: 300
  error: 500

file_length:
  warning: 500
  error: 1000

function_body_length:
  warning: 50
  error: 100

identifier_name:
  min_length:
    warning: 2
    error: 1
  max_length:
    warning: 50
    error: 60
  excluded:
    - id
    - x
    - y
    - i
    - j
    - ok

type_name:
  min_length:
    warning: 3
    error: 0
  max_length:
    warning: 50
    error: 60

cyclomatic_complexity:
  warning: 10
  error: 20

nesting:
  type_level:
    warning: 2
  function_level:
    warning: 3

Using a Config from a Custom Path

swiftlint lint --config path/to/.swiftlint.yml

Multiple Configs (Child Config)

# Feature/.swiftlint.yml — inherits parent config and overrides
child_config: ../.swiftlint.yml

disabled_rules:
  - force_cast

Parent Config (Extend from Another)

# .swiftlint.yml
parent_config: shared/.swiftlint-base.yml

Remote Config

parent_config: https://raw.githubusercontent.com/org/repo/main/.swiftlint.yml

Agent guidance: When a project already has

.swiftlint.yml
, always read it before suggesting changes. Modify the existing config rather than creating a new one.


Inline Rule Management

Disable a Rule for a Line

let value = dict["key"] as! String // swiftlint:disable:this force_cast

Disable a Rule for a Block

// swiftlint:disable force_cast
let a = x as! String
let b = y as! Int
// swiftlint:enable force_cast

Disable All Rules for a Block

// swiftlint:disable all
// Legacy code that can't be refactored yet
// swiftlint:disable:enable all

Disable for Next Line Only

// swiftlint:disable:next force_cast
let value = dict["key"] as! String

Disable for Previous Line

let value = dict["key"] as! String
// swiftlint:disable:previous force_cast

Agent guidance: Prefer targeted disables (

disable:this
,
disable:next
) over broad block disables. Never suggest
disable all
unless the user is dealing with generated code or legacy code they explicitly don't want to lint.


Xcode Integration

Build Phase Script

Add a Run Script Phase in Xcode (Build Phases):

if command -v swiftlint >/dev/null 2>&1; then
  swiftlint
else
  echo "warning: SwiftLint not installed, download from https://github.com/realm/SwiftLint"
fi

Build Phase with Autocorrect

if command -v swiftlint >/dev/null 2>&1; then
  swiftlint --fix && swiftlint
fi

Swift Package Plugin (Xcode 15+)

If SwiftLint is added as a package dependency:

swift package plugin swiftlint

Or in Xcode: right-click the project → "SwiftLintBuildToolPlugin".

Agent guidance: For modern projects (Xcode 15+), prefer the SPM plugin over a build phase script — it pins the SwiftLint version to the project and doesn't require a local install.


CI Integration

GitHub Actions

- name: SwiftLint
  run: |
    brew install swiftlint
    swiftlint lint --reporter github-actions-logging --strict

With only changed files:

- name: SwiftLint Changed Files
  run: |
    git diff --name-only --diff-filter=d origin/main...HEAD -- '*.swift' | \
    xargs -I{} swiftlint lint --path {} --reporter github-actions-logging --strict

Bitrise

- script:
    inputs:
    - content: |
        brew install swiftlint
        swiftlint lint --strict

Jenkins (Checkstyle)

swiftlint lint --reporter checkstyle > swiftlint-checkstyle.xml

Then use the Checkstyle plugin to parse

swiftlint-checkstyle.xml
.


Analyzing Results

Count Violations by Rule

swiftlint lint --reporter json | python3 -c "
import json, sys, collections
data = json.load(sys.stdin)
counts = collections.Counter(v['rule_id'] for v in data)
for rule, count in counts.most_common():
    print(f'{count:>5}  {rule}')
"

Show Only Errors (Not Warnings)

swiftlint lint --strict 2>&1 | grep "error:"

Strict Mode (Warnings Become Errors)

swiftlint lint --strict

This makes SwiftLint return a non-zero exit code for any violation (not just errors).

Quiet Mode (Errors Only in Output)

swiftlint lint --quiet

Suppresses warnings from output, only shows errors.

Enable/Disable Specific Rules via CLI

swiftlint lint --enable-rules sorted_imports,unused_import
swiftlint lint --disable-rules todo,trailing_whitespace

Custom Rules

Define custom regex-based rules in

.swiftlint.yml
:

custom_rules:
  no_print_statements:
    name: "No Print Statements"
    regex: "\\bprint\\s*\\("
    message: "Use os_log or Logger instead of print()"
    severity: warning
    match_kinds:
      - identifier

  no_hardcoded_strings:
    name: "No Hardcoded Strings in Views"
    regex: "Text\\(\"[^\"]+\"\\)"
    message: "Use LocalizedStringKey or String(localized:) for user-facing text"
    severity: warning
    included: ".*View\\.swift"

  no_force_unwrap_iboutlet:
    name: "No Force Unwrap IBOutlet"
    regex: "@IBOutlet\\s+(weak\\s+)?var\\s+\\w+:\\s+\\w+!"
    message: "Use optional IBOutlets to avoid crashes"
    severity: error

  accessibility_identifier_required:
    name: "Accessibility Identifier"
    regex: "\\.accessibilityIdentifier\\("
    message: "Good — accessibilityIdentifier found"
    severity: warning
    match_kinds:
      - identifier

  prefer_logger_over_print:
    name: "Prefer Logger"
    regex: "\\bNSLog\\s*\\("
    message: "Use Logger (os.Logger) instead of NSLog"
    severity: warning

Match Kinds

KindWhat It Matches
identifier
Variable/function names
string
String literals
comment
Comments
keyword
Swift keywords
typeidentifier
Type names
number
Numeric literals
parameter
Function parameters
argument
Function arguments

Agent guidance: Custom rules are powerful but regex-based — they can produce false positives. Always test custom rules on the codebase before suggesting them as permanent additions.


Common Flags Reference

FlagPurpose
--path <path>
Lint specific file or directory
--config <path>
Use custom config file
--reporter <name>
Output format (json, csv, etc.)
--strict
Treat warnings as errors
--quiet
Only show errors in output
--fix
Autocorrect fixable violations
--enable-rules <rules>
Enable specific rules (comma-separated)
--disable-rules <rules>
Disable specific rules (comma-separated)
--use-stdin
Read Swift from stdin
--force-exclude
Exclude files even if explicitly passed
--cache-path <path>
Custom cache directory
--no-cache
Disable caching
--use-alternative-excluding
Use alternative file-excluding method
--in-process-sourcekit
Use in-process SourceKit
--compiler-log-path
Path to xcodebuild log for analyzer rules
--progress
Show progress bar

Common Workflows

Set Up SwiftLint for a New Project

# 1. Install
brew install swiftlint

# 2. Run initial lint to see baseline
swiftlint lint --path Sources/ --reporter json > baseline.json

# 3. Create config based on results
cat > .swiftlint.yml << 'EOF'
included:
  - Sources
  - Tests
excluded:
  - Pods
  - DerivedData
  - .build
disabled_rules:
  - todo
opt_in_rules:
  - sorted_imports
  - unused_import
line_length:
  warning: 120
  error: 200
  ignores_urls: true
EOF

# 4. Fix autocorrectable issues
swiftlint --fix --path Sources/

# 5. Re-lint to see remaining issues
swiftlint

Fix All Issues Before a PR

# Autocorrect what we can
swiftlint --fix

# Check what remains
swiftlint lint --strict

Lint Only Changed Files (vs. main)

git diff --name-only --diff-filter=d origin/main...HEAD -- '*.swift' | \
  xargs -I{} swiftlint lint --path {} --strict

Compare Violation Counts Between Branches

# Current branch count
CURRENT=$(swiftlint lint --quiet 2>&1 | wc -l | tr -d ' ')

# Main branch count
git stash
git checkout main
MAIN=$(swiftlint lint --quiet 2>&1 | wc -l | tr -d ' ')
git checkout -
git stash pop

echo "main: $MAIN violations, current: $CURRENT violations"

Troubleshooting

Common Errors

ErrorSolution
No lintable files found
Check
included
paths in config or run from project root
Invalid configuration
Validate YAML syntax in
.swiftlint.yml
SourceKit not found
Run
sudo xcode-select -s /Applications/Xcode.app
Rule not found
Check rule name with
swiftlint rules
, may be opt-in
Slow linting
Add
excluded
paths for Pods/DerivedData, use
--cache-path

Performance Tips

  • Always exclude
    Pods/
    ,
    DerivedData/
    ,
    .build/
    , and
    Packages/
    in config
  • Use
    --cache-path
    to persist cache across CI runs
  • Lint only changed files on CI instead of the entire project
  • Use
    --no-cache
    only when debugging unexpected results

Notes

Agent Tips

When a user asks to "clean up" or "fix style" in Swift code, run

swiftlint --fix
first, then
swiftlint lint
to report remaining issues.

Before adding SwiftLint to an existing project, run

swiftlint lint --reporter json
to assess the violation count. If there are hundreds of violations, suggest a phased approach: fix autocorrectable ones first, then tackle the rest by category.

Always check for an existing

.swiftlint.yml
before creating one. Read it to understand the team's style preferences.

For projects targeting accessibility (which should be all of them), suggest enabling

accessibility_label_for_image
and
accessibility_trait_for_button
opt-in rules.

When the user's project uses SwiftUI, suggest a custom rule to catch hardcoded strings in

Text()
views — all user-facing strings should use
String(localized:)
for localization support.

The

--strict
flag is essential for CI — without it, SwiftLint exits 0 even with warnings, which means your CI pipeline won't catch style regressions.