CLI Reference

The koolbase release and koolbase patch commands build, sign, and ship VM-level code-push for Android and iOS — from the store build to the over-the-air patches you push on top of it. This page covers every command and flag.

Commands

CommandWhat it does
release androidBuild the multi-ABI store AAB and register a release per ABI.
patch androidBuild, diff against a released AAB, and publish an OTA patch per ABI.
patch pushBuild → sign → upload (→ publish) a patch for a built app binary.
patch stage-localBuild a patch and stage it locally on a device (dev/engine testing).
patch listList patches for a release.
patch publishPublish a draft patch.
patch recallRecall a published patch (devices revert).
patch ios buildAuthor an iOS patch from changed Dart source (compile → KBPI).
patch push-iosSign, upload and publish an iOS patch — one command from KBPI to live.
whoamiShow which account the CLI is logged in as (verified live).

release vs patch

Two commands, two jobs. release android builds the base app — the multi-ABI AAB you upload to the Play Store, done once per store version. patch android builds an over-the-air update to a release that's already out — a tiny Dart diff the engine applies on the next launch, no store trip, done as often as you ship fixes.

The mental model

release = the binary on the store (the base snapshot the engine boots). patch = the OTA Dart diff, bound to that release's build_id, applied at the next launch. You release once per store version and patch many times on top of it.

release android

Builds your app for each target ABI with the Koolbase engine, stamps a build_id per ABI, bundles them into a single multi-ABI .aab, and registers a release for each on the server. The resulting bundle is what you upload to Google Play.

koolbase release android \
  --engine 3.44.0-koolbase.2 \
  --flutter-sdk /path/to/flutter \
  --target-archs arm64,arm \
  --project <project_id> \
  --channel stable
FlagDescription
--engineKoolbase engine version to build with (e.g. 3.44.0-koolbase.2). Must be installed.
--flutter-sdkPath to the matching Flutter SDK for that engine version.
--target-archsComma-separated ABIs to build. Default: arm64,arm
--flavorBuild flavor (e.g. prod). Selects the gradle product flavor and shapes the output path. Required if your app declares product flavors.
--dart-defineCompile-time Dart value as KEY=VALUE (repeatable). Values may contain commas, URLs, or JSON.
--dart-define-from-fileLoad --dart-define values from a JSON or .env file (repeatable).
--projectApp (project) ID the releases register under. Defaults to your saved config.
--channelRelease channel. Default: stable
--no-tree-shake-iconsDisable icon tree-shaking during the build.

x86_64 and the Play Store

Koolbase code-push currently supports arm64-v8a and armeabi-v7a — effectively all physical Android phones. The generated AAB may still carry an x86_64 split from plugin native libraries, which has no Koolbase engine behind it. Before uploading to Play, restrict ABIs so x86_64 devices aren't served a split without code-push — see Store Compliance. x86_64 (emulator) support is on the way.

Other flutter flags go after --

Anything not first-class — --build-name, --build-number, --target, --obfuscate, --split-debug-info — goes after a -- separator and is forwarded straight to the per-ABI builds:
koolbase release android --flavor prod -- --build-name=1.2.3 --obfuscate

patch android

Builds your app for each ABI, diffs it against the base libapp extracted from a released .aab, and publishes a patch for each ABI's release. This is the high-level, multi-ABI equivalent of patch push — it handles the per-ABI build, base extraction, diff, and upload for you.

koolbase patch android \
  --base-aab build/app/outputs/koolbase/app-release.aab \
  --engine 3.44.0-koolbase.2 \
  --flutter-sdk /path/to/flutter \
  --target-archs arm64,arm \
  --app <project_id> \
  --channel stable \
  --key ./private.key \
  --publish
FlagDescription
--base-aabPath to the released AAB to diff against (extracts the base per ABI). Required.
--engineKoolbase engine version to build the new binary with.
--flutter-sdkPath to the matching Flutter SDK.
--target-archsComma-separated ABIs to patch. Default: arm64,arm
--appApp (project) ID. Defaults to your saved config.
--channelRelease channel. Default: stable
--keyPath to the Ed25519 signing key. Default: private.key
--diffBuild a kind=4 diff patch. Default: true
--publishPublish immediately. Default: false (drafts only).
--rolloutRollout percentage 0-100. Default: 100
--mandatoryMark the patch mandatory (force-update signal).
--notesRelease notes.
--no-tree-shake-iconsDisable icon tree-shaking during the build.

Base AAB survives the per-ABI clean

patch android runs a flutter clean between ABIs, so it copies your --base-aab aside before the loop. You can safely point it at the AAB under build/ from your last release.

patch push

Builds a signed patch from a base binary and a recompiled binary, uploads it, and optionally publishes it live. This is the main command for shipping a fix.

koolbase patch push \
  --app <project_id> \
  --binary ./base/libapp.so \
  --new ./fixed/libapp.so \
  --diff \
  --key ./private.key \
  --platform android \
  --channel stable \
  --rollout 25 \
  --publish
FlagDescription
--appApp (project) ID. Required.
--binaryPath to the released/base app binary. Required.
--newPath to the recompiled app binary to ship. Required.
--diffBuild a kind=4 diff patch (small delta) instead of a full replacement.
--keyPath to the Ed25519 signing key. Default: private.key
--platformios, android, or macos. Default: macos
--channelRelease channel. Default: stable
--rolloutRollout percentage 0–100. Default: 100
--publishPublish immediately after upload (otherwise stays a draft).
--mandatoryMark the patch mandatory (force-update signal).
--match-modeRelease match mode: build_id (default) or release_version.
--app-versionApp version, used when auto-creating the release.
--flutter-versionFlutter version, used when auto-creating the release.
--releaseExplicit release ID (skips build_id match/create).
--notesRelease notes.

Diff vs full

Pass --diff to ship a small binary delta (kind=4). Without it, the patch carries the full new blob (kind=3) — larger, but occasionally useful when you don't have the exact base binary to diff against. Diff is the recommended default.

Flag parity check

When patch push matches your release, it prints the flags that release was built with — flavor, dart-define keys, passthrough. Build your --new binary with the same flags; a mismatch is the usual cause of an oversized diff that won't apply cleanly. (dart-define values are never shown, only the keys.)

patch stage-local

Builds a patch and stages it directly where the engine reads it — no server, no upload. Use this for local development and engine testing, to confirm a patch applies before pushing it to real devices.

koolbase patch stage-local \
  --binary ./base/libapp.so \
  --new ./fixed/libapp.so \
  --diff \
  --key ./private.key
FlagDescription
--binaryPath to the running/base app binary. Required.
--newPath to a recompiled binary. Present ⇒ a replacement patch is built.
--diffWith --new: build a diff patch instead of a full replacement.
--keyPath to the Ed25519 signing key. Default: private.key

patch list

Lists the patches on a release, with their numbers and status.

koolbase patch list --release <release_id>

patch publish

Publishes a draft patch, making it live to devices. Use this when you pushed without --publish and want to review before going live.

koolbase patch publish --patch <patch_id>

patch recall

Recalls a published patch. Devices on it revert to the prior state on their next check. See Rollout & Rollback.

koolbase patch recall --app <project_id> --patch <patch_id>

patch ios build

Authors an iOS patch from your changed Dart source: compiles it against your installed Koolbase engine and packs a KBPI container — the iOS patch artifact. This is the iOS sibling of building a --new binary on Android.

koolbase patch ios build \
  --source lib/main.dart \
  --app-package myapp \
  --engine 3.44.4-koolbase.4
FlagDescription
--sourcePath to the changed Dart file. Required.
--app-packageHost app package name (e.g. myapp) — drives patch identity. Required.
--engineInstalled Koolbase engine version the app was built with. Required.
--outputOutput KBPI path. Default: <app-package>_patch.kbpi

Patch what you declared

An iOS patch can override the functions your app declares as patchable in its koolbase_dynamic_interface.yaml. Declare the surface you may want to fix before you ship the release build — the declaration travels with the binary, the patch targets it later.

patch push-ios

Ships an iOS patch: signs the KBPI into a verified envelope, derives the release build_id from your app binary, creates or matches the release, uploads, and publishes — one command from artifact to live.

koolbase patch push-ios \
  --app <project_id> \
  --kbpi myapp_patch.kbpi \
  --binary ./Runner.app/Frameworks/App.framework/App \
  --key ./private.key \
  --channel stable
FlagDescription
--appApp (project) ID. Required.
--kbpiKBPI from patch ios build. Signs + publishes in one command.
--binaryBase App binary (required with --kbpi; the build_id is derived from it).
--keyEd25519 private key (required with --kbpi).
--containerAlternative to --kbpi: a pre-built signed container to upload as-is.
--channelRelease channel. Default: stable
--rolloutRollout percentage 0–100. Default: 100
--mandatoryMark the patch mandatory (force-update signal).
--no-publishLeave the patch as a draft for review.
--releaseExplicit release ID (skips release creation).
--match-modebuild_id (default) or release_version.
--app-versionRelease version to match, e.g. 1.0.0+1 (release_version mode).
--notesRelease notes.

No hand-typed build_id

With --kbpi the release build_id is derived from the binary you pass — the same value the device reports at check-in. There is nothing to copy from a screen, and a mismatching explicit --build-id is rejected rather than silently shipped.

whoami

Shows which account the CLI is authenticated as — verified live against the API, so a stale or revoked session reports as such instead of failing later mid-command. Publish and release commands act as this account; if a project isn't visible to it, errors will say so by name.

koolbase whoami

How patch signing works

Every patch is signed, and the Koolbase engine verifies that signature before applying anything — an unsigned or tampered patch is rejected on-device and the app stays on its current version. Signing today uses a single Koolbase signing key, whose public half is built into the Koolbase engine your app ships with. Treat any signing key you're given like a production secret: keep it out of version control and store it securely.

Per-project signing keys are on the roadmap

Support for per-project keys — where you generate, hold, and rotate your own signing key scoped to your app — is planned and not yet available. Until then, code-push signing is managed with the Koolbase signing key. If your security review requires customer-held keys, reach us at [email protected].