CLI reference
Every command
Section titled “Every command”| Command | What it does |
|---|---|
patchcli setup | Install the Swift→WebAssembly toolchain `patchcli release` needs (one-time). |
patchcli init | Set up this app for Patch: detect the project, register the app, add the SDK, insert startup code. |
patchcli prepare | Make this app's SwiftUI views patchable out of the box (dynamic-replacement thunks). |
patchcli doctor | Preflight: check (read-only) that this project is set up for OTA patches, with a fix hint per gap. |
patchcli build | Parse → classify → split → compile to a real .wasm module. Track F1. |
patchcli push | Upload the built .wasm to the backend (gated on fingerprint compatibility). Track F2. |
patchcli release | Release a patch to your users: build the .wasm then upload it in one shot (fingerprint-gated). |
patchcli status | Show the current deployment: version, rollout %, adoption, failure rate. |
patchcli rollback | Roll back to the previous module (or --to <version>). |
patchcli fingerprint | Compute / diff / register the native-shell fingerprint. |
patchcli fingerprint diff | Show what changed in the native shell since the last registered fingerprint. |
patchcli fingerprint register | Register the current native-shell fingerprint with the backend. |
patchcli channels | List deployment channels for the configured app (+ active module per channel). |
patchcli whoami | Print the configured app_id / workspace_id / base URL / channel from .Patch.yml. |
patchcli analyze | Analysis only, for CI. Reports OTA coverage; exits 1 if the native shell changed. |
patchcli compile | Generate _wasm.swift for OTA-eligible code and compile it to a real .wasm module. |
patchcli overlay | Author + package an OTA resource overlay (colors / strings / images). |
patchcli overlay package | Bundle an overlay spec (JSON) into the built module artifact. |
patchcli overlay inspect | Print the resource overlay carried by a packaged module artifact. |
patchcli setup
Install the Swift→WebAssembly toolchain `patchcli release` needs (one-time).
OVERVIEW: Install the Swift→WebAssembly toolchain `patchcli release` needs
(one-time).
USAGE: patchcli setup [--force]
OPTIONS:
--force Reinstall even if a toolchain is already detected.
--version Show the version.
-h, --help Show help information.patchcli init
Set up this app for Patch: detect the project, register the app, add the SDK, insert startup code.
OVERVIEW: Set up this app for Patch: detect the project, register the app, add
the SDK, insert startup code.
USAGE: patchcli init [<path>] [--target <target>] [--base-url <base-url>] [--force] [--manual] [--no-open] [--yes] [--skip-package] [--skip-code]
ARGUMENTS:
<path> Project directory (default: current directory).
OPTIONS:
--target <target> Build target. Optional: inferred from Package.swift /
.xcodeproj / source layout when omitted.
--base-url <base-url> Backend base URL to record in .Patch.yml (root or
.../api/v1 — both work). Default: the live production
API.
--force Overwrite an existing .Patch.yml and start fresh.
--manual Skip all automation (browser registration, package
add, code insertion); just write .Patch.yml and print
the manual steps.
--no-open Don't auto-open the browser for registration (the URL
is printed instead).
--yes Apply proposed source-code changes without asking.
--skip-package Skip adding the PatchSDK Swift package to the Xcode
project.
--skip-code Skip inserting the Patch startup code into App.swift.
--version Show the version.
-h, --help Show help information.patchcli prepare
Make this app's SwiftUI views patchable out of the box (dynamic-replacement thunks).
OVERVIEW: Make this app's SwiftUI views patchable out of the box
(dynamic-replacement thunks).
USAGE: patchcli prepare [<path>] [--yes] [--thunks-only] [--check] [--quiet]
ARGUMENTS:
<path> Project directory (default: the directory of
.Patch.yml, else CWD).
OPTIONS:
--yes Apply source changes without asking.
--thunks-only Only regenerate the thunk file; never edit existing
sources. (For a build phase.)
--check Report views that aren't patch-ready (missing
`dynamic`) and exit non-zero if any. (For CI /
pre-push.)
--quiet Less output.
--version Show the version.
-h, --help Show help information.patchcli doctor
Preflight: check (read-only) that this project is set up for OTA patches, with a fix hint per gap.
OVERVIEW: Preflight: check (read-only) that this project is set up for OTA
patches, with a fix hint per gap.
USAGE: patchcli doctor [<path>] [--base-url <base-url>] [--offline] [--json]
ARGUMENTS:
<path> Project directory (default: the directory of
.Patch.yml, else CWD).
OPTIONS:
--base-url <base-url> Backend base URL override (for the fingerprint check).
--offline Skip every network call (the fingerprint-registration
check degrades to a warning).
--json Output JSON (machine-readable).
--version Show the version.
-h, --help Show help information.patchcli build
Parse → classify → split → compile to a real .wasm module. Track F1.
OVERVIEW: Parse → classify → split → compile to a real .wasm module. Track F1.
USAGE: patchcli build [<path>] [--verbose] [--dry-run] [--report <report>] [--optimization <optimization>] [--output <output>] [--no-prepare]
ARGUMENTS:
<path> Source directory to build (default: project root from
.Patch.yml, else CWD).
OPTIONS:
--verbose Verbose: print generated sources + per-function table.
--dry-run Generate sources + coverage report but skip the WASM
compile.
--report <report> Write the coverage report (JSON) to this path.
--optimization <optimization>
Optimization: size | speed.
--output <output> Output .wasm path (default: .Patch/build/module.wasm).
--no-prepare Skip the automatic `prepare` step (don't add
`dynamic`/thunks to new views before building).
--version Show the version.
-h, --help Show help information.patchcli push
Upload the built .wasm to the backend (gated on fingerprint compatibility). Track F2.
OVERVIEW: Upload the built .wasm to the backend (gated on fingerprint
compatibility). Track F2.
USAGE: patchcli push <options>
OPTIONS:
--channel <channel> Release channel (default: production). (default:
production)
--rollout <rollout> Rollout percentage 0-100 (default: 100). (default:
100)
--message <message> Release notes / changelog message.
--version <version> Module version (default: timestamp-derived).
--module <module> Path to the .wasm to push (default:
.Patch/build/module.wasm).
--base-url <base-url> Backend base URL override.
--mandatory Mark the update as mandatory.
--min-app-version <min-app-version>
Only deliver to app versions ≥ this (e.g. 2.1.0).
Absent = all versions.
--max-app-version <max-app-version>
Only deliver to app versions ≤ this (e.g. 3.0.0).
Absent = no upper bound.
--min-os-version <min-os-version>
Only deliver to OS versions ≥ this (e.g. 16.0).
Absent = all OS versions.
--target-cohort <target-cohort>
Restrict the rollout to a named cohort/segment.
Absent = all devices.
--dry-run Run all checks + show what would be sent, but do not
upload.
--force Upload even if the native-shell fingerprint gate
reports a MISMATCH (dangerous; skips the
compatibility refusal).
--allow-native-drift Ship the patch when the native shell drifted ONLY in
ways the OTA patch can't see (a package / Info.plist
/ entitlements / deployment-target change, with no
native-source change). Refused if any change is
patch-affecting. The non-interactive form of the
native-drift prompt.
--no-prepare Skip the automatic `prepare` step (don't add
`dynamic`/thunks to new views before pushing).
--version Show the version.
-h, --help Show help information.patchcli release
Release a patch to your users: build the .wasm then upload it in one shot (fingerprint-gated).
OVERVIEW: Release a patch to your users: build the .wasm then upload it in one
shot (fingerprint-gated).
USAGE: patchcli release <options>
OPTIONS:
--optimization <optimization>
Optimization: size | speed.
--output <output> Output .wasm path (default: .Patch/build/module.wasm).
--channel <channel> Release channel (default: production). (default:
production)
--rollout <rollout> Rollout percentage 0-100 (default: 100). (default:
100)
-m, --message <message> Release notes / changelog message.
--version <version> Module version (default: timestamp-derived).
--base-url <base-url> Backend base URL override.
--mandatory Mark the update as mandatory.
--min-app-version <min-app-version>
Only deliver to app versions ≥ this (e.g. 2.1.0).
Absent = all versions.
--max-app-version <max-app-version>
Only deliver to app versions ≤ this (e.g. 3.0.0).
Absent = no upper bound.
--min-os-version <min-os-version>
Only deliver to OS versions ≥ this (e.g. 16.0).
Absent = all OS versions.
--target-cohort <target-cohort>
Restrict the rollout to a named cohort/segment.
Absent = all devices.
--dry-run Build, then run all push checks + show what would be
sent, but do not upload.
--force Upload even if the native-shell fingerprint gate
reports a MISMATCH (dangerous; skips the
compatibility refusal).
--allow-native-drift Ship the patch when the native shell drifted ONLY in
ways the OTA patch can't see (a package / Info.plist
/ entitlements / deployment-target change, with no
native-source change). Refused if any change is
patch-affecting. The non-interactive form of the
native-drift prompt.
--allow-empty Release even if the module has no real OTA coverage
(only a version probe / a degenerate near-empty
module). Off by default.
--no-prepare Skip the automatic `prepare` step (don't add
`dynamic`/thunks to new views before building).
--version Show the version.
-h, --help Show help information.patchcli status
Show the current deployment: version, rollout %, adoption, failure rate.
OVERVIEW: Show the current deployment: version, rollout %, adoption, failure
rate.
USAGE: patchcli status [--channel <channel>] [--base-url <base-url>] [--json]
OPTIONS:
--channel <channel> Release channel (default: production). (default:
production)
--base-url <base-url> Backend base URL override.
--json Output JSON.
--version Show the version.
-h, --help Show help information.patchcli rollback
Roll back to the previous module (or --to <version>).
OVERVIEW: Roll back to the previous module (or --to <version>).
USAGE: patchcli rollback [--channel <channel>] [--to <to>] [--base-url <base-url>] [--dry-run] [--json]
OPTIONS:
--channel <channel> Release channel (default: production). (default:
production)
--to <to> Roll back to a specific version (rolls back
everything newer first).
--base-url <base-url> Backend base URL override.
--dry-run Show what would be rolled back without calling the
backend.
--json Output JSON.
--version Show the version.
-h, --help Show help information.patchcli fingerprint
Compute / diff / register the native-shell fingerprint.
OVERVIEW: Compute / diff / register the native-shell fingerprint.
USAGE: patchcli fingerprint <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
diff (default) Show what changed in the native shell since the last
registered fingerprint.
register Register the current native-shell fingerprint with
the backend.
See 'patchcli help fingerprint <subcommand>' for detailed help.patchcli fingerprint diff
Show what changed in the native shell since the last registered fingerprint.
OVERVIEW: Show what changed in the native shell since the last registered
fingerprint.
USAGE: patchcli fingerprint diff [--base-url <base-url>] [--json] [--explain] [--no-build]
OPTIONS:
--base-url <base-url> Backend base URL override.
--json Output JSON.
--explain Also list the native (not OTA-patchable) functions in
the shell and WHY each is native.
--no-build Skip the build-confirmation compile; compute the
STATIC estimate instead (faster, but the result is an
estimate — the authoritative check runs at
build/release).
--version Show the version.
-h, --help Show help information.patchcli fingerprint register
Register the current native-shell fingerprint with the backend.
OVERVIEW: Register the current native-shell fingerprint with the backend.
USAGE: patchcli fingerprint register [--base-url <base-url>] [--app-version <app-version>] [--dry-run] [--json] [--no-prepare]
OPTIONS:
--base-url <base-url> Backend base URL override.
--app-version <app-version>
App version string to record (e.g. 2.0.0).
--dry-run Compute + print the fingerprint but do not call the
backend.
--json Output JSON.
--no-prepare Skip the automatic prepare step before hashing
(advanced — risks a post-upgrade fingerprint mismatch
on the next release).
--version Show the version.
-h, --help Show help information.patchcli channels
List deployment channels for the configured app (+ active module per channel).
OVERVIEW: List deployment channels for the configured app (+ active module per
channel).
USAGE: patchcli channels [--base-url <base-url>] [--json]
OPTIONS:
--base-url <base-url> Backend base URL override.
--json Output JSON.
--version Show the version.
-h, --help Show help information.patchcli whoami
Print the configured app_id / workspace_id / base URL / channel from .Patch.yml.
OVERVIEW: Print the configured app_id / workspace_id / base URL / channel from
.Patch.yml.
USAGE: patchcli whoami [--base-url <base-url>] [--json]
OPTIONS:
--base-url <base-url> Backend base URL override (to preview what would be
used).
--json Output JSON.
--version Show the version.
-h, --help Show help information.patchcli analyze
Analysis only, for CI. Reports OTA coverage; exits 1 if the native shell changed.
OVERVIEW: Analysis only, for CI. Reports OTA coverage; exits 1 if the native
shell changed.
USAGE: patchcli analyze <path> [--format <format>] [--verbose] [--fast-no-split-check] [--split-diagnostics] [--check-fingerprint] [--fingerprint-baseline <fingerprint-baseline>] [--base-url <base-url>]
ARGUMENTS:
<path> Path to a directory (or a single .swift file) to
analyze.
OPTIONS:
--format <format> Output format: text (default) or json. (default: text)
--verbose Print the per-function classification table.
--fast-no-split-check Skip the realized-split pass (faster; reports only
the optimistic mixed-inclusive OTA%).
--split-diagnostics Print the per-strategy realized-split outcome
breakdown (A / sub-expr / guard / unrealized reasons).
--check-fingerprint CI gate: exit 1 if the native-shell fingerprint
differs from the baseline (.Patch.yml + backend, or
--fingerprint-baseline).
--fingerprint-baseline <fingerprint-baseline>
Expected native-shell fingerprint to compare against
(CI; avoids a backend call).
--base-url <base-url> Backend base URL override (for --check-fingerprint).
--version Show the version.
-h, --help Show help information.patchcli compile
Generate _wasm.swift for OTA-eligible code and compile it to a real .wasm module.
OVERVIEW: Generate _wasm.swift for OTA-eligible code and compile it to a real
.wasm module.
USAGE: patchcli compile <path> [--output <output>] [--swift-sdk <swift-sdk>] [--exports <exports>]
ARGUMENTS:
<path> Path to a directory of generated _wasm.swift files
(or a single .swift file) to compile.
OPTIONS:
--output <output> Output .wasm path. (default: patch.wasm)
--swift-sdk <swift-sdk> Swift SDK identifier for the WASM target. (default:
swift-6.3.2-RELEASE_wasm)
--exports <exports> Comma-separated symbols to export from the module.
--version Show the version.
-h, --help Show help information.patchcli overlay
Author + package an OTA resource overlay (colors / strings / images).
OVERVIEW: Author + package an OTA resource overlay (colors / strings / images).
USAGE: patchcli overlay <subcommand>
OPTIONS:
--version Show the version.
-h, --help Show help information.
SUBCOMMANDS:
package Bundle an overlay spec (JSON) into the built module
artifact.
inspect Print the resource overlay carried by a packaged
module artifact.
See 'patchcli help overlay <subcommand>' for detailed help.patchcli overlay package
Bundle an overlay spec (JSON) into the built module artifact.
OVERVIEW: Bundle an overlay spec (JSON) into the built module artifact.
USAGE: patchcli overlay package <spec> [--module <module>] [--output <output>]
ARGUMENTS:
<spec> Path to the overlay spec JSON (colors / strings /
images).
OPTIONS:
--module <module> Module to wrap (default: .Patch/build/module.wasm).
--output <output> Where to write the wrapped artifact (default:
overwrite the module in place).
--version Show the version.
-h, --help Show help information.patchcli overlay inspect
Print the resource overlay carried by a packaged module artifact.
OVERVIEW: Print the resource overlay carried by a packaged module artifact.
USAGE: patchcli overlay inspect <artifact>
ARGUMENTS:
<artifact> Path to the artifact (a POVR-wrapped module, or any
module).
OPTIONS:
--version Show the version.
-h, --help Show help information.The full command surface of the patchcli CLI. build and compile drive the real engine and the real WASM toolchain; push, release, status, rollback, and fingerprint talk to the backend over HTTP. Run patchcli <command> --help for full details on any command.
Which command compiles vs. uploads? patchcli build compiles your Swift to a real .wasm at .Patch/build/module.wasm but never talks to the backend. patchcli push does not build — it only uploads an already-built .wasm (the one build wrote, or the path you pass with --module), gated on the fingerprint check. patchcli release is the everyday command: it runs the same build pipeline as build, then the same fingerprint-gated upload as push — i.e. release = build + push.
| Command | What it does | Key flags |
|---|---|---|
patchcli init [path] |
One-command app setup: detect the Xcode project/target/bundle id, register the app via the browser (app.patchrelease.com/cli-connect — the CLI automatically receives the app key and a publish token, writing app_key/publish_token/app_id/workspace_id into .Patch.yml), add the PatchSDK package to the project (backup at project.pbxproj.patch-backup), and propose the startup-code diff, applied after you confirm. Skips anything already done — safe to re-run. Anything it can’t do safely falls back to printed manual steps. |
--manual · --no-open · --yes · --skip-package · --skip-code · --force · --target <name> · --base-url <url> |
patchcli login [path] (new) |
Get a publish token (ppt_…) for this project and save it to .Patch.yml. Opens your browser, you approve, the CLI receives the token — the same hand-off init uses, on its own so you can run it any time. Use it when you clone a repo that has .Patch.yml but no token, when a token is revoked, or to mint one for CI. The token is never printed. |
--base-url <url> |
patchcli doctor [path] (new) |
Read-only setup/health preflight — answers “is my app set up correctly for OTA patches?” Runs five checks (each ✓/⚠/✗ with a one-line fix hint), never mutates the project, and exits non-zero on any blocking ✗ so it’s CI-usable. Run it after init or whenever a patch isn’t behaving. See the doctor section. |
--json · --offline · --base-url <url> |
patchcli prepare [path] |
Make your SwiftUI views patchable: mark each var body: some View dynamic and generate the @_dynamicReplacement(for: body) thunks (the same mechanism Xcode Previews uses), so a future OTA patch re-renders your views with no PatchView wrapping. Idempotent. You normally never run this yourself — it runs automatically on every build / push / release. This standalone command stays for CI (--check) and debugging. |
--check |
patchcli build [path] |
Parse → classify → split → compile to a real .wasm module at .Patch/build/module.wasm. Does not upload. Auto-runs prepare first (insert dynamic + thunks for any new views) unless --no-prepare. |
--verbose · --dry-run · --report <path> · --optimization size|speed · --output <path> · --no-prepare |
patchcli push |
Upload an already-built .wasm to the backend, gated on a fingerprint-compatibility check. Does not build — run build first (or use release). |
--channel <name> · --rollout 0-100 · --message <text> · --version <ver> · --module <path> · --mandatory · --min-app-version <ver> · --max-app-version <ver> · --min-os-version <ver> · --target-cohort <name> · --allow-native-drift · --base-url <url> · --dry-run · --no-prepare |
patchcli release (new) |
Build then push in one command — the everyday deploy. Runs the same build pipeline as build, then the same fingerprint-gated upload as push; accepts both flag sets (no --module, since it builds the module itself). Auto-runs prepare first so views you add are always patchable (skip with --no-prepare). |
--channel <name> · --rollout 0-100 · --message <text> · --version <ver> · --mandatory · --min-app-version <ver> · --max-app-version <ver> · --min-os-version <ver> · --target-cohort <name> · --allow-native-drift · --optimization size|speed · --output <path> · --base-url <url> · --dry-run · --no-prepare |
patchcli status |
Show the current deployment: version, rollout %, adoption, failure rate. | --channel <name> · --base-url <url> · --json |
patchcli rollback |
Roll back to the previous module (or to a specific version). | --channel <name> · --to <version> · --base-url <url> · --dry-run · --json |
patchcli fingerprint <diff|register> |
Diff or register the native-shell fingerprint that gates OTA compatibility. diff is the default subcommand. |
--base-url <url> · --app-version <ver> (register) · --dry-run (register) · --json |
patchcli analyze <path> |
Analysis only, for CI/code review. Reports OTA coverage; with --check-fingerprint it exits 1 if the native shell changed. |
--format text|json · --verbose · --check-fingerprint · --fingerprint-baseline <hash> |
patchcli channels |
List the deployment channels seen for the configured app, with the active module per channel. Calls GET /apps/{app_id}/channels (falls back to deriving channels from the module list). |
--base-url <url> · --json |
patchcli whoami |
Print the configured app_id / workspace_id / base URL / channel resolved from .Patch.yml (and env overrides). Handy for confirming which backend a command will hit. |
--json |
patchcli compile <path> |
Lower-level: compile a directory of generated _wasm.swift to a real .wasm module. |
--output <path> · --swift-sdk <id> · --exports <symbols> |
Build coverage output
Section titled “Build coverage output”patchcli build parses, classifies, splits, and compiles, then prints a coverage report and writes the module to .Patch/build/module.wasm. Use --verbose for the per-function table and --dry-run to skip the WASM compile.
$ patchcli build ./SourcesCoverage report: WASM-eligible (pure) 7 (50.0%) WASM-eligible (bridged) 3 (21.4%) Mixed (auto-split) 0 (0.0%) Native (stays in shell) 4 (28.6%) OTA-updatable (realized): 71.4% Packaging tier (start): T0 Embedded + bridges (tens of KB)
Module: .Patch/build/module.wasm (38.2 KB) ✓ Build succeeded — push with: patchcli pushRelease in one command
Section titled “Release in one command”patchcli release runs the build pipeline, confirms the module, then runs the same fingerprint-gated push as patchcli push — so it accepts both sets of flags. This is the command you’ll use day to day.
# everyday: build + push to a 10% staged rollout on production$ patchcli release --rollout 10 --message "Tighten refund eligibility"
# release to a named channel, optimizing the module for size$ patchcli release --channel staging --optimization size
# mark a release mandatory (see Force updates)$ patchcli release --rollout 100 --mandatory --message "Critical tax fix"
# preflight only — build + run all push checks, but do not upload$ patchcli release --dry-runStatus & rollback
Section titled “Status & rollback”# current deployment + device telemetry on a channel$ patchcli status --channel productionActive version: 2026.06.03.142210Rollout: 10% Adoption: 96.4% (activations / downloads) Failure rate: 0.2% (errors / (activations+errors))
# one-click revert to the previous module (≈60s to propagate)$ patchcli rollback --channel production
# roll all the way back to a specific version$ patchcli rollback --to 2026.05.30.090112Check your setup: patchcli doctor
Section titled “Check your setup: patchcli doctor”patchcli doctor is the “is my setup correct?” command. It runs a read-only preflight — it never edits your project (unlike init / prepare), so it’s safe to run anytime, in CI, or on a teammate’s machine. Run it right after patchcli init, or whenever a patch isn’t behaving the way you expect. It reports five checks, each with a ✓ / ⚠ / ✗ and a one-line fix hint:
.Patch.ymlpresent + valid — has a publish token (ppt_…, orPATCH_API_KEYset);app_idrecommended for backend commands. Anapp_keyalone fails this check: it is a public identifier, not a publish credential.- PatchSDK package added + linked — referenced in your
.xcodeprojorPackage.swiftand linked into your app target. Patch.configure(...)+Patch.shared.start()in the@mainApp — plusimport PatchSDK(aconfigurewith nostart()never fetches updates).- Views are patch-ready — every SwiftUI view
bodyisdynamicand the dynamic-replacement thunks exist. If some aren’t yet, this is just a ⚠ (not a blocker):build/push/releaseauto-runprepare, so it self-heals on your next release. - Native-shell fingerprint registered + current — the registered fingerprint matches the current shell (needs network; degrades to a ⚠ with
--offline).
$ patchcli doctorPatch doctor============
✓ .Patch.yml present + valid publish token set; app_id 3f2b…-uuid.✓ PatchSDK package added to the project MyApp.xcodeproj references patch-swift and links the PatchSDK product.✓ Patch.configure(...) + start() in the @main App entry Patch.configure(...) + Patch.shared.start() + import PatchSDK found (MyAppApp.swift).✓ Views are patch-ready (bodies dynamic + thunks) 12 SwiftUI view(s) are `dynamic` + have generated thunks.✓ Native-shell fingerprint registered + current Registered fingerprint matches the current native shell (3f2b9c1e7a4d…).
5/5 checks passed.READY — this project is set up for OTA patches. ✓It exits non-zero on any blocking ✗ (the ⚠ items are non-fatal but worth fixing), so you can drop it into CI as a setup gate. Add --json for a machine-readable report:
# fail the job if the project isn't set up for OTA patches$ patchcli doctor --jsonNative-shell drift: --allow-native-drift
Section titled “Native-shell drift: --allow-native-drift”Sometimes your native shell changes but in ways the OTA patch can’t see — you added a Swift package, edited Info.plist, tweaked an entitlement, or bumped the deployment target, without touching the source the patch is built against. The plain fingerprint gate would block the push, even though the view patch is provably compatible. To handle this, patchcli fingerprint diff tags each changed component as either native-only (the patch can’t see it) or patch-affecting (it can change the surface the patch is built against), and --allow-native-drift lets you ship a view patch when every change is native-only.
| Changed component | Classified | Why |
|---|---|---|
| Info.plist | native-only | Pure native-shell metadata (display name, permission strings, URL schemes). The WASM module never reads or links it. |
| Entitlements | native-only | Native binary capabilities (keychain groups, App Groups, push) — an OS/codesign concern the WASM ABI is blind to. |
| Linked frameworks | native-only | Adding/removing a framework the shell links. (If a patched view had started using it, the view’s source would have changed too — that shows up as a patch-affecting native-source change and blocks the skip.) |
| Deployment target | native-only | A native build setting — it changes which OS versions the binary supports, not the OS-version-independent WASM ABI. |
| Native .swift files | patch-affecting | A native function, signature, or file add/remove can change the surface the patch is built against — never skipped. |
| Bridge definitions | patch-affecting | Host bridges are capabilities the module calls; changing them shifts the shell ABI. |
| SDK / WasmKit / compiler version | patch-affecting | These govern how the module is marshalled and executed on-device — a rebuild + re-register is required. |
# see the per-component breakdown (native-only vs patch-affecting)$ patchcli fingerprint diff
# the native shell drifted, but only natively — ship the view patch anyway$ patchcli release --allow-native-drift --message "Restyle the paywall"Configuration: .Patch.yml
Section titled “Configuration: .Patch.yml”patchcli init writes .Patch.yml at your project root — including the app_key/publish_token/app_id/workspace_id it receives during browser registration. It’s a small, fixed-shape YAML file. Environment variables override the API fields at call time; app_id/workspace_id are only needed for backend commands (push/release/status/rollback).
version: 1app_key: pak_live_… # PUBLIC app identifier (also baked into your binary)publish_token: ppt_… # SECRET publish credential — env PATCH_API_KEY overridesproject: MyApp.xcodeprojtarget: MyApp
app_id: 3f2b…-uuid # required for push/release/status/rollbackworkspace_id: 9a01…-uuidapi_base_url: https://api.patchrelease.com
exclude: # paths/globs to skip during analysis []
bridges: # host bridges available to OTA code networking: true userDefaults: true notifications: true navigation: true keychain: true dateLocale: true logging: true
build: optimization: size # size | speed stripDebugInfo: true swiftui: true # lower SwiftUI views to WASM (default on)| Field | Type | Description |
|---|---|---|
| version | int | Config schema version. Currently 1. |
| app_key | string | PUBLIC per-app identifier (pak_…). Ships inside your binary and rides the device check-in body. Authenticates nothing — it is not accepted as X-API-Key. |
| publish_token | string? | SECRET publish credential (ppt_…), sent as X-API-Key. Written by patchcli init/login. Overridden by env PATCH_API_KEY. |
| project | string | Detected project file (e.g. MyApp.xcodeproj or Package.swift). |
| target | string | The app target whose sources Patch analyzes. |
| app_id | uuid? | Backend app UUID. Required for push/release/status/rollback; optional for offline build/analyze. |
| workspace_id | uuid? | Backend workspace UUID the app belongs to. |
| api_base_url | url? | Backend base URL. Overridden by env PATCH_API_URL / the –base-url flag. |
| api_key | string? | Legacy alias for publish_token, still read as a fallback. Overridden by env PATCH_API_KEY. An app key here is ignored. |
| exclude | string[] | Paths/globs to skip during analysis. Empty list = analyze everything. |
| bridges.* | bool | Toggle each host bridge: networking, userDefaults, notifications, navigation, keychain, dateLocale, logging, analytics, fileStorage, connectivity, biometrics, appReview, pasteboard, haptics, deviceInfo, shareSheet, openURL, location, calendar, contacts, appBadge, mailCompose, inAppPurchase, speechSynthesis, documentPicker, systemSound, photoPicker, secureRandom, appGroupStorage, screenControl, audioPlayback, audioRecording, motion, mapsDirections, networkImage, spotlightIndex, backgroundTask, fileDownload, accessibility, appShortcuts, handoff, watchConnectivity, nfcRead, processInfo, videoPlayback, speechRecognition, mediaInfo, imageFilter, pdfGenerate, qrGenerate, camera (51 in total). A disabled bridge means functions using it stay native. |
| build.optimization | string | size (default) or speed. Overridden by –optimization. |
| build.stripDebugInfo | bool | Strip debug info from the emitted module to shrink it. Default true. |
| build.swiftui | bool | Lower SwiftUI View.body to WASM so views ship over the air. Default true (on if omitted); set false to keep views native. Env PATCH_SWIFTUI=0 overrides per-run. |