Cascade CLI
Cascade builds, signs, uploads and submits Flutter releases through GitHub Actions. The dashboard shows separate execution and store status, safe failure explanations, release history and retained artifacts. Full build logs remain in GitHub Actions.
Package: cascade_cli. Executable: cascade. Candidate version: 0.1.28, compatible with workflow 2.2.0. The matching control plane must be deployed before the new package is published.
Install and prerequisites
Use Dart 3.5 or later, or Flutter with a compatible Dart SDK. Create an account at Cascade, install GitHub CLI, and authenticate it with gh auth login. Init requires a GitHub repository where you have write access; it binds release execution to that repository's default branch. Pull requests run validation only.
dart pub global activate cascade_cli
cascade --version
cascade --help
Add the pub global bin directory to PATH if Dart requests it. Upgrade with the same activate command. Cascade uses https://cascadeci.com by default.
First project
cascade login
cd /path/to/your_flutter_app
cascade init
# Fill cascade.secrets.env with values for the delivery lanes you want.
cascade match
# For Apple signing provisioning only, explicitly run:
# cascade match --ios
Enable the desired delivery lanes in App settings, then:
cascade doctor
git add cascade.project.yaml .github/workflows/cascade.yml .github/workflows/cascade-refresh.yml cascade.secrets.env.example .gitignore
git commit -m "[build-apk] Configure Cascade"
git push
Doctor resolves required secrets from the enabled lanes, so enable those lanes before the final check. Watch the exact run in GitHub Actions and the App Release Control Center. Do not commit cascade.secrets.env, signing keys or ~/.cascade/config.json.
Commands
cascade login: approve a device login in the browser.cascade logoutclears the saved CLI session.cascade init: create or link the App, bind the repository, and obtain current setup files from the authenticated server.cascade init --pick: choose an existing App.--newcreates a new App;--name MyAppsets the display name.cascade match: push filled release/signing/notification values from the local secrets file into opaque GitHub secret slots using the generated guide's mapping. Unused values may stay empty. It also sends the Google Play service account and/or App Store Connect API credential to Cascade’s authenticated status setup service. Signing keys/passwords are not included.cascade match --ios: explicitly provision Apple signing with fastlane, then upload the signing configuration. Existing secret uploads are attempted before provisioning. Install fastlane on a Mac and configure the Apple API key, Match repository and team ID first.cascade doctor: check login, Flutter project, project seal, both workflows, supported contract, server-issued workflow checksum, enabled lane requirements, local values and GitHub slot presence. It also reports automatic Android/iOS status setup without displaying credentials. It prints ASCII OK/WARN/ERROR and exits nonzero when required setup cannot be verified.cascade send --app APP_ID --file app-release.apk --to you@example.com: deliver an existing APK through the enabled Email lane using your CLI session. This route does not require a GitHub workflow or store credentials.cascade --versionorcascade version: show package and workflow versions.cascade --helpshows usage.
Files and upgrades
Init writes cascade.project.yaml, .github/workflows/cascade.yml, .github/workflows/cascade-refresh.yml, cascade.secrets.env.example and a gitignored cascade.secrets.env.
Both workflows are wholly Cascade-owned, sealed files. Init repairs missing markers and upgrades the contract by regenerating them from the server. Init no longer creates workflow backups or a local Markdown secrets guide. Keep independent custom jobs in separate workflow files and use Git history to review generated workflow changes. Existing recovery files are left untouched. Other workflow files are untouched. Init preserves existing local secret values and adds missing keys. Each init rotates the project seal and issued workflow checksum, so idempotence means safe repeat setup rather than identical bytes. Commit the new project seal and both workflows together; avoid running init during an active release.
The package does not bundle an older workflow template. The authenticated server returns version 2.2.0, a checksum and the companion lifecycle workflow; incompatible responses are rejected before files are written. The sealed bootstrap retrieves the current server-delivered runner bundle, including structured failure and release-result support. No monorepo checkout is needed by package users.
Choose only the credentials you need
Use cascade match and the public secrets guide for the current slot contract. Do not invent or rename slots.
- APK/Android release builds require Android keystore, alias and passwords.
- Play uploads additionally require the Play service account JSON and an existing configured application. Closed testing defaults to the
alphatrack and creates it if missing. - Email requires notification recipients; the Cascade operator configures the email service.
- Signed iOS builds, TestFlight and App Store submission require Apple API credentials and Match signing configuration, including
MATCH_GIT_URLandIOS_TEAM_ID.IOS_SCHEMEdefaults to Runner. - App Store submission uses listing data already in App Store Connect plus review answers inferred from the iOS project. Submission uses manual release and does not fall back to TestFlight.
Plain match does not start Apple provisioning merely because some Apple values are filled. Successful uploads remain if another upload fails; correct the reported names and rerun. Release/signing values continue to go to GitHub Secrets. Only the Google Play and App Store Connect API credentials are also used for Cascade status access where enabled. Setup errors identify each affected provider; rerun match after fixing them. Unvalidated access is reported as pending, not complete.
Release intents
Use a leading intent in the commit message with the corresponding enabled lane:
[build-apk] APK only
[build-ios] signed IPA artifact
[test-android-internal] Play internal testing
[test-android-closed] named Play closed testing
[test-android-open] Play open testing
[test-ios] internal TestFlight
[release-android-partial] production partial rollout
[release-android-full] production full rollout
[release-ios] App Store review submission
No intent defaults to APK and notification when the appropriate lanes are enabled. Disabled lanes are denied by the server's job plan. Upload or approval alone does not establish Live status.
Status and failure explanations
Run cascade match to configure Google Play and App Store Connect status credentials. After successful validation, Cascade reads updated store records directly. No Connect/Authorize GitHub step is required for store status. GitHub remains responsible for builds, signing, uploads and submissions; commit both generated workflows for those operations.
Persisted status renders immediately. Android and iOS are evaluated independently. An automatic check becomes eligible 20 minutes after the last successful exact-current check, or when no successful check exists. Reloads inside that window do not start another check. Historical releases do not auto-refresh. Failures, backoff and provider/GitHub limits can delay retries; this is not constant polling or a background scan.
Build Failed, Signing Failed, Upload Failed and Submission Failed describe execution outcomes. Processing Failed, In Review, Rejected, Live and Status refresh failed describe separate lifecycle or refresh outcomes. Cascade shows safe catalog reasons when reliable structured evidence exists; an opaque failure may have no precise root cause. Open GitHub Actions for full logs.
Cascade shows reviewer/rejection details only when official structured evidence exposes them. The current Google and Apple lifecycle readers do not expose detailed reviewer feedback. Open Google Play Console or App Store Connect for that detail.
Only store-status credentials are copied to Cascade, encrypted at rest; signing secrets remain in GitHub. If no successful store upload has been recorded yet, status validation awaits an exact release target. Rerun cascade match after the first successful store upload. Failed refreshes keep the last known status.
Troubleshooting
- Missing markers, companion workflow, invalid project seal or checksum mismatch: run
cascade init, then commit the project file and both workflows. - Unsupported workflow version: run
dart pub global activate cascade_cli, thencascade initagainst the matching server. - Missing/expired login: run
cascade login. - Missing GitHub CLI or authentication: install gh and run
gh auth login. - Values filled locally but missing on GitHub: run
cascade match. - Missing Apple signing setup: configure the listed Apple/Match values, then run
cascade match --ioson a Mac. - Lane denied: enable the desired lane in App settings and rerun doctor before pushing.
- Server unavailable: check connectivity and the configured API endpoint, then retry.
Links and license
Guide · Docs · Support · Contact · Package · Issues
Cascade is free. Support helps cover control-plane maintenance, email and storage. MIT license; see LICENSE.
Encrypted lifecycle refresh
The refresh companion uses opaque GitHub credential slots and an AES-256-GCM encrypted reader payload. Its separate decryption key is returned only after the server validates the scoped refresh request and GitHub OIDC identity. It does not receive the build workflow pack key. GitHub must still read the outer workflow triggers, permissions, jobs and dependency installation steps; these remain visible. Encryption hides the implementation in the committed file, but an authorized execution can decrypt it.
Deploy the compatible Cascade server before updating the CLI, then run cascade init and commit both generated workflows together. cascade match now obtains secret slot mappings from the authenticated server instead of a local guide. Re-run init after workflow pack-key rotation. The safe example and active gitignored secrets file remain; init/match do not create .bak-* or .mangled-* secret copies.
Automatic iOS configuration
Plain cascade match uploads filled credentials and reuses an existing signing
repository from ios/Matchfile or ios/fastlane/Matchfile. It detects one
unambiguous DEVELOPMENT_TEAM in ios/Runner.xcodeproj/project.pbxproj and a
unique custom shared scheme. Runner already defaults automatically. Explicit
MATCH_GIT_URL, IOS_TEAM_ID and IOS_SCHEME env values take precedence.
Current catalog keys stay in the env file even when empty. Add an override only
when detection is wrong. Existing files and overrides are preserved. Retired
Fastlane keys from older files are removed.
Run cascade match --ios explicitly to prepare certificates/profiles. It reuses
your signing repository or creates private storage when none is configured,
saves its URL to the active gitignored env file, and uploads it to GitHub.
Missing/ambiguous team or scheme configuration is reported rather than guessed.
Normal match never creates signing repositories or Apple certificates.
TestFlight and App Store review do not require IOS_SUBMISSION_INFORMATION;
match infers it from the project when empty. PLAY_CLOSED_TRACK defaults to
alpha. An iOS status message
of “saved, awaiting validation” concerns lifecycle validation, not empty API keys
or certificate setup; it is separate from signing preparation.