SwiftButler uses SwiftSyntax to parse Swift code into syntax trees and turn large, noisy Swift codebases into smaller, more useful working surfaces for humans and coding agents.
It is built around four practical jobs:
analyze: produce a bare-bones "header" representation so an LLM can know the API without reading full implementationscheck: run lightning-fast syntax checking with precise locations and fix-itsreindent: normalize Swift indentation with spaces or tabs so generated or patched code becomes consistent againdistribute: split large generated files into one file per declaration, including separate protocol conformance extensions, so agents have less code to scan
Detailed CLI usage lives in CLI.md.
Agentic workflows break down when the working set is too large, too noisy, or too slow to validate.
SwiftButler is useful because it cuts directly into those failure modes:
- Better context density: agents can read compact API surfaces instead of thousands of lines of implementation detail
- Lower token cost: interface-style output is often dramatically smaller than full source
- Faster iteration loops: syntax checking is fast enough to sit directly in generation and repair loops
- Easier file targeting: distributed output makes it more obvious where a change belongs
- Better generated-code hygiene: large synthesized Swift files can be split into maintainable units before an agent starts editing them
In practice, that means less time spent re-reading irrelevant code, fewer blind edits, and faster recoveries when generated output is malformed.
The problem with feeding raw source trees to an LLM is not just token count. It is signal quality.
Most of the time, an agent does not need every private helper, every implementation branch, or every generated conformance body. It needs to know:
- what types exist
- what the visible API looks like
- where syntax is broken
- how code should be split into smaller working units
SwiftButler is designed around exactly that.
analyzegives agents a compact representation of the public or internal API surfacecheckgives agents fast, machine-usable feedback after every generation stepdistributereduces oversized files into manageable slices so the next edit is more local and less error-prone
This combination is especially effective in workflows where an agent is:
- learning an unfamiliar codebase
- repairing generated Swift
- refactoring monolithic generated files
- iterating on framework APIs
- validating code before handing off to
swift buildor CI
# Clone the repository
git clone https://github.com/Cocoanetics/SwiftButler.git
cd SwiftButler
# Analyze a file
swift run butler path/to/File.swift
# Analyze a directory recursively
swift run butler Sources/ --recursive --format interface --visibility public
# Syntax-check a project
swift run butler check Sources/ --recursive
# Emit JSON for tooling or automation
swift run butler check Sources/ --recursive --jsonIf you want to hand a framework surface to an agent without drowning it in implementation details:
swift run butler Sources -v public -r | pbcopyThat gives you a compact, interface-style view you can paste directly into a prompt.
SwiftButler transforms implementation-heavy Swift into a cleaner declaration-oriented view.
Example:
import Foundation
/// A utility class for mathematical operations
@MainActor
public final class MathUtils {
/// The mathematical constant pi
public static var pi: Double { get }
/**
Calculates the area of a circle
- Parameter radius: The radius of the circle
- Returns: The area of the circle
*/
public static func circleArea(radius: Double) -> Double
}For an agent, that is usually the useful part. The internal implementation can stay out of context until it is actually needed.
Use analyze when an agent needs to understand the API shape of a file or module.
Typical uses:
- preparing prompt context for an unfamiliar framework
- extracting public interfaces for review
- generating compact architectural summaries
Examples:
swift run butler MyFile.swift --format interface
swift run butler Sources/MyFramework/ --format markdown --visibility public
swift run butler Sources/ --recursive --format jsonUse check inside generation, repair, and validation loops.
Typical uses:
- validating generated Swift before committing it to a larger flow
- returning structured JSON diagnostics to an agent
- rendering markdown reports with fix-its for humans
Examples:
swift run butler check MyFile.swift
swift run butler check Sources/ --recursive --json
swift run butler check Sources/ --recursive --format markdown --show-fixitsWhy it helps:
- fast feedback without waiting for a full semantic build
- precise line and column locations
- fix-it suggestions that are useful in automated repair loops
Use reindent when generated, patched, or hand-edited Swift has inconsistent indentation.
Typical uses:
- normalizing indentation after LLM-generated edits
- switching a file or project between spaces and tabs
- cleaning up mixed indentation before committing or reviewing
Examples:
swift run butler reindent MyFile.swift
swift run butler reindent Sources/ --recursive --spaces 2
swift run butler reindent Sources/ --recursive --tabs
swift run butler reindent Sources/ --recursive --dry-runWhy it helps:
- keeps formatting consistent without a full formatter pass
- makes generated diffs easier to review
- supports explicit spaces-vs-tabs preferences
Use distribute when large generated files become too heavy for reliable agent editing.
Typical uses:
- splitting generated model files into one declaration per file
- separating protocol conformances into extension files
- reducing context size before a refactor or targeted edit
Examples:
swift run butler distribute Generated.swift
swift run butler distribute Sources/Generated --recursive --dry-run
swift run butler distribute Sources/Generated --recursive --output SplitSourcesWhy it helps:
- smaller files are easier for agents to inspect correctly
- conformance extensions become easier to target and reason about
- code ownership becomes more obvious after generation
SwiftButler can also be used directly as a Swift package dependency.
import SwiftButler
let tree = try SyntaxTree(url: URL(fileURLWithPath: "MyFile.swift"))
let overview = CodeOverview(tree: tree, minVisibility: .public)
let interface = overview.interface()
let json = try overview.json()
let markdown = overview.markdown()You can also parse directly from strings:
import SwiftButler
let tree = try SyntaxTree(string: swiftCode)
let overview = CodeOverview(tree: tree, minVisibility: .internal)
let interface = overview.interface()check is designed for the part of the loop that comes before compilation.
It catches malformed Swift syntax such as:
- broken type annotations
- invalid declarations
- malformed parameter lists
- operator and expression errors
- missing braces, delimiters, or required tokens
It is especially useful when an agent is repeatedly generating or rewriting Swift and needs immediate feedback before moving on.
func invalidFunc: <T>(value: T) -> T {
return value
}
var property: Int String = 5
let incomplete = 1 + + 2SwiftButler reports precise source locations and can include fix-its, making it suitable for both human review and automated repair.
Add SwiftButler to your Package.swift:
dependencies: [
.package(url: "https://github.com/Cocoanetics/SwiftButler.git", branch: "main")
]SwiftButler is a practical tool for agentic Swift workflows because it does three things well:
- compresses code into the API surface an agent actually needs
- validates generated Swift quickly with actionable diagnostics
- restructures oversized generated files into units an agent can edit more safely
That combination makes SwiftButler useful as both a developer tool and a force multiplier for coding agents.
