CONTRIBUTING.md

July 23, 2026 ยท View on GitHub

nvbangg/builder-for-morphe

Here you will find a step-by-step technical guide on how to set up your environment, run the patching script, customize the build configuration, and contribute to the project's development.

๐Ÿ”„ Sync Upstream

The Sync upstream workflow keeps your fork up to date with the upstream repository to pull in bug fixes and new features while still preserving your own configuration. It merges new commits automatically or opens a Pull Request if there are unresolvable conflicts.

[Optional] You can customize the sync behavior by adding the following variables and secrets to your repository:

NameTypeDescriptionDefault
IGNORE_SYNC_FILESVariableSpace-separated list of file paths to preserve during sync. Example: None to sync everything; config.toml sig.txt .github/workflows to not sync workflow changes.config.toml sig.txt
UPSTREAM_URLVariableOverrides the upstream repository URL.Auto-detects fork parent
PAT_TOKENSecretEnables automatic syncing of changes in .github/workflows/.None
How to create and add the PAT_TOKEN

By default, GitHub does not allow syncing changes in workflows, and you will have to Sync fork manually. If you still want to automatically sync these changes, you need to follow these steps:

  1. Go to Fine-grained personal access tokens and click Generate new token.
  2. Set Token name to PAT_TOKEN, set an appropriate Expiration, and under Repository access, select Only select repositories and choose your fork.
  3. Grant these Permissions: Contents (Read and write), Pull requests (Read and write), Workflows (Read and write).
  4. Click Generate token and copy the token value immediately.
  5. In your fork, go to Settings โ†’ Secrets and variables โ†’ Actions โ†’ Secrets tab.
  6. Click New repository secret, name it PAT_TOKEN, paste the token, and click Add secret.

๐Ÿ’ป Build Locally

  1. ๐Ÿ“‹ Requirements:
  1. ๐Ÿ“ฅ Installation:
git clone --depth 1 https://github.com/nvbangg/builder-for-morphe.git
cd builder-for-morphe

No further setup needed, as uv handles the Python environment and dependencies automatically.

  1. โ–ถ๏ธ Running:
uv run main.py # build all apps
uv run main.py SomeApp # build a specific app
uv run main.py SomeApp arm64-v8a # build with arch override
uv run main.py clear # remove build/, temp/ and build.md

Output APKs are saved to build/.

โš™๏ธ Configuration

All configuration lives in config.toml in the project root. Top-level keys define defaults inherited by every app entry. Each app is a TOML table.

[SomeApp]
apkmirror-dlurl = "https://www.apkmirror.com/apk/inc/app"
# uptodown-dlurl = "https://app.en.uptodown.com/android"
# github-dlurl = "https://github.com/owner/repo/releases/tag/app"

[SomeApp.patches]
# Simple form - fetches latest version, applies listed patches
"github:owner/some-patches" = ["Patch name A", "Patch name B"]

# Full form - pin a specific version and/or list patches to include
"github:owner/some-other-patches" = { version = "v1.2.3", include = ["Patch name C"] }
  1. ๐Ÿ“ฑ Available options:
๐Ÿ”‘ Key๐Ÿ“ Description๐Ÿ”ค Default๐Ÿ“Œ Scope
parallel-jobsNumber of concurrent buildsCPU countGlobal
brandUsed in output filenamesMorpheGlobal / Per-app
cli-versionCLI version to fetch (latest, dev, or a specific version string)latestGlobal / Per-app
cli-sourceGitHub or GitLab repo for CLI (github:owner/repo or gitlab:owner/repo)github:MorpheApp/morphe-desktopGlobal / Per-app
strict-sigcheckFail the build if an app is missing from sig.txt (see note below)trueGlobal only
app-nameDisplay name used in output filename and build labeltable name (hyphens replaced by spaces)Per-app
archTarget architecture (all, both, arm64-v8a, armeabi-v7a, x86_64, x86)allPer-app
versionTarget version (auto, latest, exp, or a specific version string) - latest fetches the newest APK available in the download source, exp also considers experimental patch versions, auto only stable onesautoPer-app
changelog-keywordsList of keywords used to detect if this app was updated in the release notes[]Per-app
apkmirror-dlurlAPKMirror page URL-Per-app
uptodown-dlurlUptodown page URL-Per-app
github-dlurlGitHub Releases page URL-Per-app
exclusive-patchesOnly apply patches listed in [AppName.patches], exclude everything elsefalsePer-app
patcher-argsExtra arguments passed directly to Morphe CLI-Per-app
skip-sigcheckCompletely bypasses signature checks for this app (see note below)falsePer-app only
enabledSet to false to skip this entrytruePer-app

[AppName.patches] table - defines which patch bundles to use and which patches to apply from each:

FieldDescriptionDefault
keyPatch source (github:owner/repo or gitlab:owner/repo)-
versionVersion to fetch (latest, dev, or a specific tag)latest
includeList of patch names to apply from this source. Empty list applies all patches[]
excludeList of patch names to explicitly disable from this source[]

Each patch source is fetched exactly once and reused across all apps that reference the same (source, version) pair.

  1. ๐Ÿ” Signature verification flags:

The build system includes two independent flags for controlling APK signature verification.

  • strict-sigcheck (Global root level only | Default: true)
    Controls the strict requirement for sig.txt:
  • When set to false, the build will not fail if an app is missing from sig.txt (useful for forks and local testing). If a signature entry does exist, it is still verified normally.
  • skip-sigcheck (Per-app [AppName] level only | Default: false)
    Acts as a total bypass of signature verification for one specific app.
  • When set to true, the build completely ignores sig.txt and native APK certificate checks for that app. Use this only for pre-modified APKs (e.g. with PairIP removed) where the original certificate is gone.

How to add a signature entry to sig.txt (only needed when skip-sigcheck is false):

  • Method 1 (Quick): Copy the original SHA-256 fingerprint directly from a trusted source like APKMirror (listed on every APK download page).
  • Method 2 (Manual): Use the provided toolchain on the original, unmodified APK: java -jar apksigner.jar verify --print-certs <app.apk>

Format for sig.txt: <sha256-fingerprint> <package.name>

  1. ๐Ÿค– Smart Build:

When changelog-keywords are defined for an application, the CI will only build that app if its keywords are found in the upstream patch release notes.

  • changelog-keywords (Per-app level only | Default: [])
    A list of keyword strings to search for in the release notes. If not specified, the app will always be built regardless of changelog content.
  1. โž• Adding a new patch source:
  • Add your app entries to config.toml with a [AppName.patches] table pointing to your patch repo, and set brand accordingly (see the configuration table above for all available options).
  1. ๐Ÿ”‘ Keystore:

To sign APKs with a custom keystore, create a .env file in the project root:

KEYSTORE_BASE64=<base64-encoded keystore>
KEYSTORE_PASS=<keystore password>
KEYSTORE_ALIAS=<keystore alias>

To encode an existing keystore:

base64 -w 0 my.keystore

On GitHub Actions, set KEYSTORE_BASE64, KEYSTORE_PASS and KEYSTORE_ALIAS as repository secrets under Settings โ†’ Secrets and variables โ†’ Actions instead of a .env file, as they are passed to the build automatically.

If no keystore is configured, morphe.keystore is used as a fallback if it exists in the project root. If neither is present, the CLI signs with its built-in debug keystore. On GitHub Actions this means every release will have a different signature, making app updates impossible.

๐Ÿค Contributing

  1. ๐Ÿž Bug reports:

For bugs in the build script itself, use the Script Bug Report template. For bugs in patched applications, use the Build Result Bug Report template.

  1. ๐Ÿ’ก Suggestions:

Feature ideas belong in the Discussions tab, as this keeps the issue tracker focused on bugs.

  1. ๐Ÿ› ๏ธ Pull Requests:

Pull requests are welcome. AI-assisted contributions are accepted, but all changes must be manually reviewed before submitting, as you are responsible for every line you put your name on. I reserve the right to reject any contribution that does not align with the project's vision. By submitting a pull request, you agree to license your contribution under the terms of the GNU GPLv3 license.