Repository navigation
lethen 3.10.0
Lethen 3.10.0 tells you how sure it is about each result and why it reports it, explains any declaration on request, and removes classes of false positives measured on a corpus of real projects. It requires Swift 6.3 (Xcode 26.4) or later, like 3.9.0.
Breaking changes
- Managed SwiftPM scans reuse the previous build when Lethen can verify its index, and clean and rebuild when they cannot.
--clean-buildrestores a clean build on every scan. - Lethen runs
xcodebuild,swift, andbazeldirectly instead of throughbash -c. Quotes and$VARIABLESinbuild_arguments,--build-arguments, andxcode_list_argumentsare no longer interpreted by a shell: write each argument separately, such as--scratch-pathand/tmp/Build Space. Lethen warns about build arguments still wrapped in quotes. - Bazel scans need the
peripherymodule override inMODULE.bazelto be the same Lethen version as the binary, on Bazel 7.1 or later. Update the override'stagto3.10.0together with the binary. lethen scan --bazelrejects--skip-buildand--index-store-path, which it used to ignore. Scan an existing index store with--generic-project-configand--index-store-path.
Highlights
- Confidence and reasons. Every result is
certainorlikely, with a one-sentence reason.--min-confidence certainreports onlycertainresults, so--strictcan fail CI only on findings Lethen is sure about. JSON and CSV output carry both fields. lethen explain <name|usr>shows why a declaration is reported, the shortest chain of references that keeps it used, or the rule or comment that retains it.- Objective-C uses. Swift declarations used from
.mfiles or headers are no longer reported as unused without--retain-objc-accessible. - Build configurations.
--configurations debug release(SwiftPM) or--configurations Debug Release(Xcode) builds and scans each configuration together, so code used only behind#if DEBUGis kept.--skip-build --configurations Debug Releaserescans an Xcode project from the indexes of Lethen's last completed build of each configuration, and stops with an error naming a configuration that has none; Xcode's own DerivedData index is never used in its place. Xcode scans name the configuration they compile and warn when the scheme runs with another. - Faster rescans. A SwiftPM rescan of Lethen with nothing changed takes 5.3 s instead of 33.8 s.
--statsprints phase timings and throughput, and long builds print progress. - Integrations. The repository is a GitHub Action (
uses: albovsky/lethen@3.10.0) that installs a verified release binary and annotates pull requests. The package ships aLethenPlugincommand plugin for SwiftPM and Xcode, andmint install albovsky/lethenworks. - Fewer false positives. Parameters of retained public API, of functions passed as values, and of witnesses of hidden standard library requirements; metatype parameters that select a generic type; result builder methods; property wrapper initializers;
NSDocumentclasses named in Info.plist; and stored properties of encodedEncodablestructs are no longer reported. On the precision corpus, sampled precision rose from 73 % to 84.0 %. - New findings. Enum cases that are matched but never constructed, unused subscript parameters, unused parameters of stored closures, and types used only by their own macro expansion are reported.
--retain-public-targetskeeps the public API of selected modules only.
Fixes
- A project path, scheme name, Bazel filter, or build argument can no longer run shell commands during a scan.
lethen scan --bazelwrites its generated package to a private directory in the workspace's Bazel output base instead of the shared/var/tmp/periphery_bazel.- The
github-actionsformat escapes annotation fields, so a file name or message cannot inject workflow commands. - Linux tarballs link libxml2 statically and run on Ubuntu 26.04, including the
swift:6.4image. - Scans of an index with several versions of a file give the same results every run, and redundant conformance locations are listed in a fixed order.
- Xcode scans lock the DerivedData directories they use, so concurrent scans wait for each other, and they rebuild a directory from clean unless its last build completed with the same project, schemes, configuration, and build arguments. Every directory is rebuilt once after upgrading.
- Xcode builds with different build arguments no longer share one DerivedData directory, and
swift package describeno longer waits forever on another SwiftPM process's lock.
The full list is in CHANGELOG.md.
Verification and limits
The release commit must pass the Required checks gate: the Swift 6.4 / Xcode 27 baseline (.github/scripts/verify-swift-6.4.sh), the macOS 6.3 / Xcode 26.4 job, Linux 6.3 and 6.4, Bazel on macOS and Linux, and the Linux release tarballs smoke-tested on Ubuntu 22.04, 24.04, and 26.04 images.
The verified combinations table still lists the 3.9.0 binaries and release run; it has no 3.10.0 row, so nothing in it is evidence for this release. The precision scorecard records how precision is sampled; its target is 95 %. Intel source builds are not tested in CI.
Platforms and installation
Platforms: macOS release binaries and Homebrew are Apple silicon only (macOS 15 or later). Intel Macs build from source with a supported Xcode 26.x; see the platform policy. Linux x86_64 and aarch64 can use the release tarballs, which need glibc 2.35 or later and a Swift 6.3 or newer toolchain, or build from source.
Install with brew install albovsky/tap/lethen, or download the arm64 zip and checksums. Xcode or the Command Line Tools must be installed. On Linux, download lethen-3.10.0-linux-x86_64.tar.gz or lethen-3.10.0-linux-aarch64.tar.gz. The installation guide includes checksum verification; the README shows how to install a Linux tarball.
Source installation
Select a full Xcode installation on macOS, for example sudo xcode-select -s /Applications/Xcode.app/Contents/Developer, then:
git clone --branch 3.10.0 --depth 1 https://github.com/albovsky/lethen.git
cd lethen
swift build -c release --product lethen
lethen_bin_dir="$(swift build -c release --show-bin-path)"
"$lethen_bin_dir/lethen" version
mkdir -p "$HOME/.local/bin"
install -m 755 "$lethen_bin_dir/lethen" "$HOME/.local/bin/lethen"
export PATH="$HOME/.local/bin:$PATH"
lethen scan --project-root /path/to/your/project --disable-update-checkKeep the PATH export in your shell profile. Stable builds are offered stable releases by the optional update checker.