XPath

Release tool for Flutter apps

Ship your Flutter apps to the App Store and Google Play from your own Mac

XPath is a self-hosted, open source release tool for Flutter apps. It builds, signs, uploads, tags and tracks your iOS and Android releases from your Mac or your own Linux box, with a Mac app, a command line, an MCP server for agents and remote runners.

An agent can start a release. Only you can approve it.

Apache-2.0 · macOS app (Apple silicon) · Linux x64 and arm64 · Docker

XPath's project overview: release 5.4.1 (3283) is building. Preflight passed on This Mac in 41 seconds, the iOS build has run 6 minutes 12 seconds on This Mac, the Android build finished on linux-builder-01, upload and tag wait. On the right, the App Store has not received the build yet and Google Play is in review.
A production release in flight: one row per stage, which machine each job runs on, and where each store stands. Screens on this page are the app's own test renders, with sample data.

What it is

What is XPath?

XPath is a release tool for Flutter apps that you run yourself. You point it at a GitHub repository; it scans the app's flavors, bundle IDs and signing setup without writing to your folder, then builds, tests, signs and uploads releases to App Store Connect, Google Play, Firebase App Distribution and Shorebird. It tags each release, opens the release pull request, follows each store's review until the build is live, and merges once both stores have it.

A headless engine, xpd, does the work and keeps the secrets. Four clients talk to it: the macOS app, the xp command line, xp mcp for AI agents, and xp runner on other Macs and Linux machines. XPath is free and licensed under Apache-2.0. It is not related to XPath, the XML query language.

Who it is for

For Flutter developers who already release from a Mac

  • You ship a Flutter app to both stores

    Today that means Xcode's Organizer, the Play Console, a version bump by hand and a script only you can run. XPath turns that into one dispatch with the same steps every time.

  • Your signing keys should stay on your machine

    Keystores, App Store Connect keys and Play service accounts live in your Keychain or an encrypted file on the machine that runs the engine. Nothing is uploaded to a build service.

  • You let a coding agent work in the repo

    The agent can dispatch builds, read logs and edit workflows through xp mcp. It cannot approve a production release, a push or a merge.

  • Not a fit if you have no Mac

    iOS builds and App Store uploads need a Mac with Xcode. If you have no Mac, or you want build capacity someone else maintains, a hosted CI fits better. See XPath vs Codemagic.

How a release flows

One production release, start to merge

The built-in prod-release workflow runs these stages in order. Steps that push, upload or talk to GitHub run on the engine; the build can go to any paired runner with the right tools. A stage marked you approve waits for you.

  1. Dispatch

    Pick the app, flavors, platforms and version bump. XPath previews every job, the machine it lands on and the approvals it will stop at, then allocates the build number once: higher than anything in the stores, the tags or its own counter, and never reused.

  2. Prepare you approve

    Bumps the version in pubspec.yaml and the plists, cuts release/5.4.1 and pushes it. The cut and the push each wait for your approval.

  3. Check

    Guards fail early with a fix: version files in sync, build number not used before, credentials valid, the App Store version train still open, Play's target API level.

  4. Build

    flutter build or shorebird release with the Flutter version the app pins in .fvmrc, then the symbols and a manifest with the SHA-256 of every artifact.

    This Mac, or a paired runner

  5. Upload

    App Store Connect, Google Play and Firebase App Distribution, for the stores the flavor has credentials for. An upload that Apple rejected after altool exited 0 still fails the step.

  6. Finalize

    Tags v5.4.1+3283, pushes the tag and opens the release pull request.

  7. Stores

    XPath asks each store for its status at most every ten minutes: uploaded, in review, approved, live. A rejection gets "New build, same version" with the next build number.

  8. Merge you approve

    Once every store it targets is live, the release branch can merge into main with a merge commit, of exactly the commit that was tagged.

The log of an iOS build job, grouped by step: check out took 4 seconds, bump version 21 seconds, and the build iOS step shows flutter build ipa with the release flavor, build name 5.4.1 and build number 3283, a CocoaPods warning, and Xcode archive done in 312.4 seconds.
The log of a build job, grouped by step. Every line is masked against your known secrets before it is stored or shown.

What it does

What XPath handles for you

  • Scan

    Reads the repository as text, with no tool installed and no write: apps in a monorepo, flavors from Gradle, Xcode schemes and flavorizr.yaml, bundle IDs, signing team, Shorebird app IDs, the .fvmrc pin. Problems come back as findings with a fix, such as an iOS bundle ID one character away from the Android one.

  • Builds

    Each app builds with the Flutter version it pins, through fvm or XPath's own cache. A build only takes files written after it started, so a stale APK from an earlier run is never uploaded. Artifacts are kept with their SHA-256 until housekeeping frees the space.

  • Stores

    App Store Connect with an API key or an Apple ID, Google Play with a service account, Firebase App Distribution with no Node and no Firebase CLI. Each credential is checked with the service before it is saved, every day after, and again before a build.

  • Shorebird

    Releases and patches. A patch builds with the Flutter version the release was built with, not the app's current pin.

  • Tests

    flutter test and flutter analyze as steps. A test run fails only on new failures against the last green run of the base branch, so the failures you already know about do not block a release.

  • Workflows

    YAML documents with stages, a platform and flavor matrix, conditions and approval gates, edited in a visual builder or as text. Validation points at the line and column; every save is a new version, and each job records the version it ran.

  • Runners

    Pair another Mac for iOS or a Linux box for Android with a one-time token. Runners dial out to the engine, so nothing connects to them, and they take jobs that fit their tools and free slots.

  • Releases

    An App Store lane and a Play lane, a timeline, release notes grouped by commit type with "Copy for Slack" and "Copy for WhatsApp", and a reminder about min_version flags once a store is live.

  • Notifications

    macOS notifications and a menu bar item when something waits for you; an optional Slack webhook per project, masked like the logs.

  • Clients

    The Mac app, the xp command line with --json on every command, xp mcp for agents, and a Docker image for the engine on a server.

A release in review: an App Store lane at waiting for review and a Google Play lane in review, both with 5.3.7 live now. Below, a timeline of the approval, the store reviews and the build; release notes with copy buttons for Slack and WhatsApp; a forced-update reminder; and the release pull request. The merge button waits for both stores to go live.
A release in review in both stores. Merge stays off until both lanes are live.
The workflow builder: a pipeline with a check stage and a build stage, the build job's matrix, capabilities and steps, one of which uploads to Google Play behind a store submission gate; the YAML of the same workflow on the right, marked valid.
The workflow builder and the YAML it writes, side by side.
A test run with one new failure compared with the baseline of main: one failure that the baseline has too, three tests fixed since the baseline and one test missing from this run.
A test run compared with the baseline: one new failure fails it, known ones do not.
The dispatch sheet for a production release of the prod flavor on iOS and Android from main, keeping version 5.4.1. It lists four jobs in three stages: the iOS build on This Mac, the Android build on This Mac or linux-builder-01, the upload with an approval for store submission, and a finalize job.
Dispatch previews every job, where it lands and which approval it waits for.
The runners list: a Mac mini online and busy with one of three slots, with ios-sign, android and flutter capabilities; a Linux builder online and idle with android, flutter and swift-linux; an old Mac lost mid-job; and a revoked runner.
Runners, with what each machine can build and how many jobs it is running.

Safety

Your keys stay on your machine. Agents can't approve.

Secrets

  • On macOS, secrets live in your login Keychain; large ones such as keystores go to a file encrypted with a key kept in the Keychain. On Linux, an XChaCha20-Poly1305 encrypted file.
  • Every log line is masked against the secrets the engine knows. Secrets never go on a command line and the API never returns one once it is saved.
  • A runner gets the keystore or the Shorebird key only for the job it leased, once per key, and wipes it when the job ends. The GitHub token and store credentials never leave the engine.
  • XPath writes nothing to your repository except the release commits, branch and tag. No telemetry: the daily update check is one anonymous request to GitHub's release list, and XP_NO_UPDATE_CHECK=1 turns it off.

Approvals

  • Each device gets its own token, stored as a SHA-256 hash: app, cli, mcp or runner. Only app and cli tokens approve.
  • xp mcp has no tool to approve, deny, merge or change a gate, and the engine answers 403 to an mcp token that tries.
  • An approval is bound to the project, the commit and the version. If any of them changes it no longer counts, and one nobody decides expires after 24 hours.
  • In the app, Return never approves. Approve takes ⌘ Return after a one-second delay, from a sheet that says what happens if you approve.

Found a security problem? Report it privately, as SECURITY.md describes.

Agents

Let your coding agent run the release, up to the gate

xp mcp is an MCP server for agents such as Claude Code. It can list projects, read runs, jobs, log tails, test results and store status, validate and save workflows, and dispatch them. When a production release reaches a gate, the run waits; the agent tells you, you approve in the app or with xp approvals approve, and the agent carries on.

claude mcp add xpath -- xp mcp

Agent skills teach Claude Code, Cursor, Codex and other agents how to release with XPath, write workflows, set it up and change it. Install them from the repository of the app the agent will release:

npx skills add AbdurahmanAlmehdi/x-path

Install

Install XPath

Mac app

Download XPath-<version>.dmg from the latest release. It is signed with Developer ID and notarized by Apple, for Apple silicon Macs. The app carries the engine and the xp command. On first launch it starts the engine as a login item, links xp into your PATH and checks for Xcode, git, fvm, gh and Shorebird.

Download for Mac

You need Xcode, git and the Flutter toolchain your apps use. Shorebird only for over-the-air patches.

Linux

The engine and the command line for x64 and arm64. The script downloads the latest release, checks its SHA-256, installs into ~/.local and, where systemd runs a user session, starts xpd as a user service. Run it again to update.

curl -fsSL https://xpath.abdurahman.ly/install | sh

A machine that only runs jobs for an engine elsewhere:

curl -fsSL https://xpath.abdurahman.ly/install | sh -s -- --runner

Docker

The engine for linux/amd64 and linux/arm64. The image has no Flutter: builds go to paired runners.

docker run -d --name xpath -p 127.0.0.1:7480:7480 \
  -v xpath-data:/data ghcr.io/abdurahmanalmehdi/xpath:latest
docker exec xpath xpd token create --name laptop --kind cli

Then

  • Connect GitHub: paste a token or import it from the GitHub CLI.
  • Add a project by its folder or owner/name, and review the scan.
  • Add credentials per flavor. Each is checked before it is saved.
  • Dispatch a dev build.

The README covers every option, the API and the workflow format.

Questions

Questions people ask

Does XPath need a Mac?

For iOS, yes. iOS builds need a Mac with Xcode, and App Store uploads run on the engine, so the engine must run on a Mac to ship to the App Store. An engine on Linux or in Docker can build and ship Android, and can send iOS builds to a paired Mac runner.

How much does XPath cost?

Nothing. XPath is open source under Apache-2.0. You run it on hardware you already have, and you still need your own Apple Developer and Google Play developer accounts.

Is XPath a CI service?

No. It is software you install, and it runs only on your machines. It is narrower than a general CI: it does Flutter releases, from version bump and build to store review and merge.

Does my app's repository need changes?

No. XPath reads your repository and keeps its own mirror to build from. It writes only the release commit, branch, tag and pull request that a production release makes.

Who makes XPath?

Abdurahman Almehdi, who built it to ship his own Flutter apps. Contributions are welcome under the rules in CONTRIBUTING.md.