Skip to content

CLI reference

morphe-builder is a single entry point with eight subcommands. aastoken, auth, and download handle Google Play access; tools prepares external tooling; build, list-patches, and verify read TOML configuration or existing artifacts; clean maintains the cache.

Every example below uses the installed entry point. From a source checkout, prefix each command with uv run.

Command overview

CommandReads configNetworkPurpose
aastokennoGoogle AccountsGenerate a persistent AAS token through pinned goopdl
authnoGoogle PlayCreate a reusable Google Play session
downloadnoGoogle PlayDownload and verify one package's splits
toolsnoGitHub releasesResolve, download, and hash the Java toolchain
list-patchesyesGitHub releasesShow patch-compatible versions per app
buildyesall providersFull matrix: download, merge, patch, sign, package
verifynononeRe-verify an existing split set on disk
cleannononeRemove the disposable work cache

Global conventions

Architectures

--arch accepts arm64 (arm64-v8a) or armv7 (armeabi-v7a). auth and download additionally accept both, which runs two fully independent jobs and, for download, writes them into arm64/ and armv7/ subdirectories of the output. verify requires one concrete architecture.

Output formats

tools, build, verify, list-patches, and clean accept --json. Progress events always go to stderr; the final machine-readable result goes to stdout, so morphe-builder build ... --json > result.json keeps the JSON clean.

Human-readable progress looks like:

text
[tools] preparing toolchains
[resolve] resolving compatible version package=com.google.android.youtube arch=arm64
[complete] build completed jobs=2 output=build

With --json, each event becomes one JSON object per line on stderr.

Secrets and redaction

Passwords are never accepted as arguments. build reads the keystore password from MORPHE_KEYSTORE_PASSWORD only. Error messages and progress events are redacted: URL query strings and fragments are stripped, and authorization, cookie, token, password, and dispenser values are replaced with <redacted>.

Cache layout

--cache defaults to %LOCALAPPDATA%/morphe-builder on Windows, $XDG_CACHE_HOME/morphe-builder when that variable is set, otherwise ~/.cache/morphe-builder.

SubdirectoryContentsRemoved by clean
tools/Pinned Java tools and their provenanceno
trusted/Verified stock split sets, re-verified before reuseno
work/Disposable intermediate build stateyes

Environment variables

VariableUsed byPurpose
GOOPDL_ACCOUNT_EMAILauth, download, buildGoogle account email; requires GOOPDL_AAS_TOKEN.
GOOPDL_AAS_TOKENauth, download, buildPersistent account token starting with aas_et/; requires account email.
GOOPDL_BROWSERaastoken --browserBrowser executable when automatic detection fails.
MORPHE_KEYSTORE_PASSWORDbuildSigning keystore password. Required.
MORPHE_DISPENSER_URLauth, downloadDefault anonymous dispenser when --dispenser is absent.
MORPHE_MODULE_VERSION_CODEbuildMonotonic module versionCode; CI passes the run number.
GITHUB_TOKENtools, build, list-patchesAuthenticates GitHub API calls. Never sent to asset downloads.
HTTP_PROXY, HTTPS_PROXYbuildProxy for provider downloads.
LOCALAPPDATA, XDG_CACHE_HOMEall cached commandsResolve the default cache root.
MORPHE_LIVE_TEST_PACKAGEtest suiteOpt in to the live Google Play test.

aastoken

Generates a persistent Google account AAS token through pinned goopdl. Morphe Builder inherits interactive input and output without capturing the token.

bash
morphe-builder aastoken --browser
OptionMeaning
--browserOpen an isolated browser profile and capture the signed-in email plus one-time OAuth token.
--oauthPrompt for an OAuth token captured manually from Google EmbeddedSetup.

Exactly one mode is required. Browser mode is recommended. See Google Play authentication for setup and credential-handling rules.

auth

Creates the Google Play session that later downloads reuse, and stores it outside the repository.

bash
morphe-builder auth --arch arm64
OptionDefaultMeaning
--arch {arm64,armv7,both}arm64Device profile architecture to authenticate for.
--profile PROFILEgoopdl device profile name.
--region CCTwo-letter region, uppercased before use.
--dispenser URLMORPHE_DISPENSER_URLAnonymous token dispenser. Must be HTTPS with no credentials, query, or fragment.

With GOOPDL_ACCOUNT_EMAIL and GOOPDL_AAS_TOKEN set, goopdl authenticates directly against the account and no dispenser is contacted. See Google Play authentication for token generation, local setup, CI secrets, and handling rules.

download

Downloads one package's split set, verifies it independently, and publishes it atomically with provenance.

bash
morphe-builder download com.example.app --arch arm64 --output downloads
morphe-builder download com.example.app --arch both --version-name 21.04.223
Argument / optionDefaultMeaning
packagerequiredAndroid package name; rejected unless it matches the package-name grammar.
--output PATHdownloadsPublication directory. Must not already exist.
--arch {arm64,armv7,both}arm64both writes arm64/ and armv7/ subdirectories.
--version-name NAMElatestRequest an exact version name.
--version-code CODElatestRequest an exact version code. Mutually exclusive with --version-name.
--profile, --region, --dispenserSame as auth.

The download itself lands in a temporary sibling directory of --output. Before anything is published, the builder verifies the Google integrity manifest against the files on disk, then independently re-derives package name, version, split requirements, ABI, density, and signing certificate from the APKs themselves. Only then is the staged set moved into place with provenance.json. A failure removes the temporary set and leaves no partial output; an existing --output is refused rather than overwritten.

tools

Resolves the external Java toolchain to exact release tags, downloads the assets, hashes them, and records provenance.

bash
morphe-builder tools
morphe-builder tools \
  --morphe-version v1.12.0 \
  --patches-version v1.37.0 \
  --apkeditor-version V1.4.9 \
  --signer-version v1.3.0
OptionDefaultMeaning
--cache PATHplatform cache rootToolchain cache location.
--morphe-version TAGlatestMorphe CLI release tag.
--patches-version TAGlatestPatch bundle release tag.
--apkeditor-version TAGpinned defaultAPKEditor release tag.
--signer-version TAGpinned defaultuber-apk-signer release tag.
--jsonoffEmit the provenance path as JSON.

Prints the path to toolchain-provenance.json, which records each resolved tag, pinned asset URL, size, and SHA-256. Requires Java 21+. Cache, checksum, and update policy: toolchain.md.

list-patches

Resolves each configured app's patch bundle and reports which app versions the selected patches support. Use it before build to see what a configuration change will actually produce.

bash
morphe-builder list-patches morphe.toml
morphe-builder list-patches morphe.toml --json
Argument / optionDefaultMeaning
configrequiredPath to the TOML configuration.
--cache PATHplatform cache rootToolchain cache used to resolve patches.
--jsonoffFull compatibility result per app instead of the summary line.

Human output is one line per app:

text
com.google.android.youtube: 21.04.223 (147 patches)

Include, exclude, and exclusive patch selections from the configuration are applied, so the reported version is the one build would choose. Version resolution rules: configuration.md.

build

Runs the complete configured matrix. This is the command CI uses.

bash
MORPHE_KEYSTORE_PASSWORD=secret morphe-builder build morphe.toml \
  --keystore /path/outside/repository/builder.p12 \
  --output build
Argument / optionDefaultMeaning
configrequiredPath to the TOML configuration.
--keystore PATHrequiredSigning keystore. Must be a regular file, not a symlink.
--keystore-alias ALIASmorphe-builderKey alias inside the keystore.
--output PATHbuildPublication directory. Must not already exist.
--cache PATHplatform cache rootTool and trusted-stock cache.
--jsonoffMachine-readable build summary on stdout.

Per configured job, build:

  1. Prepares the app's pinned toolchain (one preparation per distinct source, reused across apps).
  2. Resolves a patch-compatible app version, intersecting selected patch versions.
  3. Downloads or reuses a verified stock split set, walking the provider fallback order.
  4. Selects the required splits and merges them with APKEditor.
  5. Signs the merged stock, then verifies package, version, architecture, ZIP structure, and certificate before patching.
  6. Patches the signed stock with the Morphe CLI, signs the result, and verifies it again.
  7. Optionally builds Magisk/KernelSU modules.

Everything is staged in a temporary directory next to --output and moved into place only after every job succeeds, so a partial matrix is never published. Successful output includes build-summary.json and CHANGELOG.md. Trusted original splits are never modified, and cached trusted sets are re-verified before reuse.

verify

Re-verifies a split set that already exists on disk, without any network access. Useful for auditing a cached or archived download.

bash
morphe-builder verify trusted/splits com.google.android.youtube \
  --arch arm64 --version-name 21.04.223
Argument / optionDefaultMeaning
directoryrequiredDirectory containing the split APKs.
packagerequiredExpected Android package name.
--arch {arm64,armv7}requiredExpected architecture.
--version-name NAMEExpected version name.
--version-code CODEExpected version code.
--jsonoffMachine-readable verification result.

Reports package, version name and code, architecture, and file count on success. Any identity, version, architecture, split-requirement, or signature mismatch fails with exit code 5.

clean

Removes only the disposable work cache.

bash
morphe-builder clean
morphe-builder clean --cache /custom/cache --json
OptionDefaultMeaning
--cache PATHplatform cache rootCache root to clean.
--jsonoffList removed and preserved paths as JSON.

Deletes <cache>/work and nothing else. <cache>/trusted, <cache>/tools, build outputs, keystores, and provenance files are preserved, and the resolved path is validated to be exactly <cache>/work before removal so a crafted --cache cannot delete an unrelated directory.

Exit codes

Exit codes are stable per failure category, so CI can branch on them.

CodeCategoryTypical cause
0success
2configurationInvalid or unreadable TOML, rejected field.
3compatibility / availabilityNo patch-compatible version, provider or requested version unavailable.
4external toolchainMissing Java, unresolvable release, checksum mismatch.
5integrity / identity / signatureManifest, hash, package, version, ABI, or signer mismatch.
6mergeSplit selection or APKEditor merge failure.
7APK build / signingPatching or signing failure, missing keystore or password.
8module buildModule packaging failure.
9overwrite refusal--output already exists.

Any exception outside these categories propagates as an unhandled traceback rather than being silently mapped to a success-adjacent code.

Provider availability versus integrity

The pinned goopdl fork exits with code 3 only when anonymous Google Play authentication is unavailable, for example an unreachable or rate-limited dispenser. The builder treats that as provider unavailability and advances to the configured fallbacks in providers.md.

Every other Google Play failure is terminal. The builder never assumes that an integrity failure is safe to bypass, and a later provider can never satisfy a request that already failed verification.

Released under the MIT License.