Skip to content

Open source

The PatchSDK (MIT) and the Patch engine (Apache-2.0) are both public, in the repository patch-release/patch-swift — the SDK as the SwiftPM package at the root, the engine as a second package nested at cli/. Patch edits your Xcode project and injects code into your @main App struct, so you shouldn’t have to take either on trust. The hosted control plane is a commercial service and is not open source.

Both live in patch-release/patch-swift. The SDK is the SwiftPM package at the repository root — which is why the package URL you add in Xcode is just the repository URL — and the engine is a second, independent SwiftPM package nested at cli/.

  • Directorypatch-swift/
    • Package.swift the SDK — MIT, the package SwiftPM resolves
    • DirectorySources/ the SDK’s targets
    • Directorycli/ the engine — Apache-2.0, its own SwiftPM package
      • Package.swift
      • DirectorySources/ the engine’s targets

The SDK executes a WebAssembly interpreter inside your users’ app, so it has to be maximally auditable and maximally permissive — MIT, no conditions worth arguing about.

The engine is Apache-2.0 rather than MIT for one reason: Apache-2.0 carries an express patent grant. Patch’s partitioning and lowering approach is novel enough that a licence which says nothing about patents is a worse answer for you, not just for us.

  • Directorycli/
    • DirectorySources/
      • DirectoryPartitioningEngine/ decides, per function, what can ship OTA
      • DirectoryCodeGenerator/ SwiftUI + UIKit lowering to the view IR
      • DirectoryCompiler/ Swift→WebAssembly pipeline, fingerprinting, upload
      • DirectoryViewNodeIR/ the wire format the SDK renders
      • DirectoryPatchCLI/ the patchcli command surface
    • DirectoryTests/ ~1,700 tests

The interesting part is PartitioningEngine + CodeGenerator. Everything else is plumbing. If you want to understand how a SwiftUI view body becomes WebAssembly, start at CodeGenerator/SwiftUIClassifier.swift and follow it into SwiftUIEmitter.swift.

  • Directory(repository root)
    • DirectorySources/
      • DirectoryPatchSDK/ runtime, loader, fallback chain, update checker, host bridges
      • DirectoryPatchSwiftUI/ the thunk entry point every generated view calls
      • DirectoryPatchRender/ reconstitutes the view IR into real SwiftUI
      • DirectoryPatchViewIR/ the SDK’s copy of the wire format
      • DirectoryPatchUIKit/ the UIKit equivalent
    • DirectoryTests/ ~1,000 tests
  1. Clone the repository and build the SDK. One clone gets you both packages. Nothing exotic — the SDK is a normal SwiftPM package at the root.

    Terminal window
    git clone https://github.com/patch-release/patch-swift
    cd patch-swift
    swift build && swift test
  2. Build the engine, the separate package in cli/.

    Terminal window
    cd cli
    swift build -c release
    .build/release/patchcli --help
  3. Add the WebAssembly toolchain — only needed to actually compile patches.

    Terminal window
    patchcli setup

    This installs the pinned swift.org toolchain and the WebAssembly SDK. The Apple/Xcode toolchain cannot target WebAssembly, which is why a second toolchain is required at all.

  4. Check the setup.

    Terminal window
    patchcli doctor

Every coverage figure on this site is generated from a committed measurement, not written by hand. You can re-run that measurement:

Terminal window
./corpus/fetch.sh # the corpus apps, at pinned commits
./tools/swiftui-corpus-coverage/run.sh # the census

corpus/fetch.sh clones each app at the exact commit recorded in corpus/manifest.yml, so the corpus is reproducible rather than a snapshot we happen to have on a laptop. See what Patch can and can’t update for the current results.

Issues and pull requests for both packages go to the same repository, patch-release/patch-swift. Two things that make a bug report actionable immediately:

Terminal window
patchcli doctor --json

That prints your setup as JSON — versions, toolchain, and whether the app’s fingerprint is registered. Attach it.

If you’re reporting that a view didn’t patch when you expected it to, the build output already names the blocking reads per view; paste that too.