Install

curl -fsSL https://swx.quadratic.xyz/install.sh | sh

The script downloads the release for your OS and CPU, checks it against the release's SHA256SUMS, and installs swx and swift-x into ~/.local/bin. With swift-x on your PATH, swift x build works too. SWX_VERSION=v0.1.0 pins a release and SWX_INSTALL_DIR changes the location.

From source, with Swift 6.1 or later:

git clone https://github.com/jeslyvarghese/swx && cd swx
swift build -c release
cp .build/release/swx ~/.local/bin/
ln -s swx ~/.local/bin/swift-x   # optional: enables `swift x …`

swx runs SwiftPM for builds, so a Swift toolchain must be installed (or let swx toolchain install fetch one).

Dependencies

A drop-in for swift package resolve and update, with the same flags. Any other package subcommand is forwarded to SwiftPM.

swx package resolve
swx package update
swx package show-dependencies   # forwarded to `swift package`

The result is what SwiftPM would have written: the same Package.resolved, the same .build/checkouts and .build/workspace-state.json. A later swift build finds everything resolved and does no network work.

Build, test, run

swx resolves first, then hands over to SwiftPM with resolution disabled.

swx build -c release
swx test
swx run MyTool --flag

SWX_BUILD_CACHE=1 shares compiled dependencies between projects through the compiler's content-addressed cache (with SwiftPM's native build system): a second project that uses swift-collections built in 1.7 s instead of 6.4 s.

Apple platforms

Packages that declare apps with AppleProductTypes (.iOSApplication(…), as Xcode and Swift Playgrounds read them) build, run and test on simulators and devices. swx uses xcodebuild, simctl and devicectl underneath, so this needs macOS with Xcode.

swx devices                                       # simulators and paired devices
swx build --platform ios                          # generic build when no simulator exists
swx run   --platform ios HelloApp                 # build, install, launch, stream console
swx run   --platform ios --destination device --team ABCDE12345 HelloApp
swx test  --platform watchos                      # package tests on a watchOS simulator

Platforms: ios, watchos, tvos, visionos.

Xcode projects

Xcode's own resolution can't be replaced, but it can be fed. swx xcode resolve prepares SourcePackages exactly as Xcode would (same pins, originHash and state), including projects with registries, mirrors and local package folders.

swx xcode resolve --source-packages SourcePackages
xcodebuild -clonedSourcePackagesDirPath SourcePackages \
           -disableAutomaticPackageResolution -onlyUsePackageVersionsFromResolvedFile …

When an app outgrows a package, swx xcode generate writes an .xcodeproj for its .iOSApplication products (through XcodeGen, fetched like any swx tool).

Toolchains

swift.org releases and snapshots, installed per user. Every command honours .swift-version and installs the pinned toolchain on demand.

swx toolchain list --available
swx toolchain install 6.4
swx toolchain install main-snapshot   # also 6.5-snapshot, or a snapshot tag
swx toolchain use 6.4                 # writes .swift-version
swx toolchain which

Tools

Run executables from packages without installing them, like uvx or Mint. Builds are cached per revision and toolchain, so a pinned tool starts in about 20 ms.

swx tool run swiftformat@0.54.0 --version
swx tool run realm/SwiftLint lint
swx tool install swiftlint     # links into ~/.local/bin

Scripts

Single-file scripts declare their dependencies in a comment; products are inferred from the imports. A warm start takes about 10 ms.

#!/usr/bin/env -S swx run
// swx-dependencies:
// .package(url: "https://github.com/apple/swift-argument-parser", from: "1.3.0")

import ArgumentParser
swx run greet.swift Ada

Environment

VariableEffect
SWX_CACHE_DIRThe shared store. Default ~/.cache/swx, or $XDG_CACHE_HOME/swx.
SWX_HOMEToolchains. Default ~/.local/share/swx.
SWX_TRACE=1A timestamped timeline of every subprocess.
SWX_STATIC_MANIFESTS=0Always evaluate manifests with the compiler.
SWX_GIT_HTTP=0List tags with git ls-remote instead of HTTP.
SWX_BUILD_CACHE0 disables the shared compilation cache; 1 opts into it with SwiftPM's native build system.

Compatibility

Each of these is checked byte for byte against SwiftPM or Xcode:

  • Package.resolved: v2 and v3 written, v1 read; originHash matches SwiftPM's and Xcode's.
  • Workspace state: workspace-state.json v7, including path dependencies and binary artifacts. Entries swx doesn't manage (edited packages, prebuilts) are kept untouched.
  • Dependencies: branch, revision, path and local git dependencies; SwiftPM's pruning, traits, tag-to-version rules and pre-release ranges.
  • Mirrors: mirrors.json from the package and ~/.swiftpm; the original URL is what the lockfile records.
  • Submodules and Git LFS: checked out as SwiftPM checks them out (LFS needs git-lfs, as SwiftPM does).
  • Registries: registries.json, SwiftPM's credential lookup (environment, Keychain, .netrc), checksums and trust-on-first-use fingerprints, SE-0391 signatures, and --replace-scm-with-registry.
  • Tag fingerprints: the commit behind each tag is recorded in SwiftPM's store, and a tag that moves is refused.
  • Binary targets: XCFrameworks, artifact bundles and .artifactbundleindex, downloaded and unzipped once per machine.
  • Manifests: 0 disagreements with dump-package over a 364-manifest corpus.
  • Xcode: projects, workspaces and root package folders, with the registries and mirrors Xcode keeps in xcshareddata.
  • Mixed use: swift package update works on top of swx checkouts, and swift-syntax prebuilts still apply.

Multi-root workspaces are not supported.

Verification

Compatibility is checked differentially: each script runs SwiftPM or Xcode and swx on the same input and compares what they write. The full list is in the contributing guide; for example:

Scripts/compare-with-swiftpm.sh <package-dir>   # Package.resolved, workspace-state.json, checkouts
Scripts/compare-registry-signing.sh             # signed registry releases: trusted, untrusted, tampered
Scripts/compare-xcode-apps.sh                   # an app + widget + watch app project vs xcodebuild
swx debug manifest-parity --cache-path <dir>    # the static parser vs dump-package over a corpus

Found a difference from SwiftPM? That's a bug — please report it.