Point it at the project — first run asks for the folder holding
pubspec.yaml with name: gcpay and remembers it
(~/.config/tahweel). Run any command from inside the project and it saves automatically.
Tools per command — firebase + jq for builds,
shorebird for production, python3 for taskboard listing. Each command checks and
tells you what's missing before doing anything.
Alias: twl works everywhere tahweel does.
Category 01
Build & release
The release cycle in three commands: test build → store release → force update.
$ tahweel build FIREBASE
Builds a test version and gets it to testers. Android uploads
straight to Firebase App Distribution; iOS builds for TestFlight (upload via Transporter).
Use it when a tester, manager, or QA needs the latest changes on a device — not when
you're shipping to the stores (that's production).
Build numbers live in Firebase RTDB per flavor + version and advance only after
a successful upload — a failed build never burns a number. iOS tracks its own ios key; no
notes or tester flags apply there.
$ tahweel lazy_build REMOTE QUEUE
Runs the whole Android build on the VPS. Zips the current project,
uploads it to the build server, and an Ubuntu box builds the APK and pushes it to Firebase App
Distribution — exactly like build, but nothing runs on your machine.
Use it when you don't have (or don't want to wait on) a local Flutter / Android / Firebase
toolchain — a teammate on any laptop, a quick fix between meetings, or a machine that just can't build.
Android only for now (the build server is Ubuntu).
$ tahweel lazy_build --notes "<release note>" # queue and return immediately$ tahweel lazy_build --notes "<note>" --watch# stay attached, stream the log$ tahweel lazy_build --cancel 42 # cancel by id (queued OR running)$ tahweel lazy_build --status# your recent builds, or one + its log
Option
What it does
-n, --notes "<text>"
Release note for this build. Required.
-p, --prod
Build the prod flavor (default: stage).
-b, --boss
Share with BOSS + MANAGER tester groups.
-m, --manager
Share with MANAGER only.
-w, --watch
Stay attached and stream the build log (default: detach right after upload).
--cancel <id>
Cancel a queued or running build; the server kills it and cleans up the uploaded code.
--status [id]
List recent builds, or show one build with its log tail.
--dry-run
Print the plan (flavor / sharing / notes); nothing is uploaded.
One-time setup: tahweel config set TAHWEEL_QUEUE_URL https://twl.towhid.space
and
tahweel config set TAHWEEL_QUEUE_TOKEN <your-token>. Each teammate gets their own token —
builds run on the VPS, and nobody needs SSH access to it. You must also be signed in via
firebase login with an authorized team account, or the build is refused. Every
build gets a simple numeric id (e.g. 42) you can cancel or check any time; cancelling wipes the
uploaded code from the server. Status changes are announced in the team Telegram group, and
--status shows your own recent builds.
$ tahweel production SHOREBIRD
Builds the store release: an AAB for Google Play or an IPA for the
App Store, via Shorebird — then opens the Play Console or Transporter plus the output folder for you.
Use it when the version in pubspec.yaml is final and you're publishing to the
stores. Flavor is always prod; version + build number are taken from
pubspec.yaml as-is — nothing is incremented.
$ tahweel production # interactive platform picker (default android)$ tahweel production android # AAB → opens Play Console + output folder$ tahweel production ios # IPA → opens Transporter + output folder
Option
What it does
android / -a, --android
Build the Android AAB.
ios / -i, --ios
Build the iOS IPA. Deep-cleans (DerivedData, Pods) and resets CocoaPods first.
$ tahweel production android
$ tahweel patch SHOREBIRD OTA
Pushes an over-the-air code patch to a version that's already
released — a hotfix that skips store review and lands on users' next app launch. Same Shorebird toolchain
as production.
Use it when a bug is live and you need the fix out now without a full store
release. Only Dart code ships in a patch — native or dependency changes still need
production. Patches the release matching
pubspec.yaml, so cut that release first.
$ tahweel patch # interactive platform picker (default android)$ tahweel patch android # OTA patch to the current Android release$ tahweel patch ios # OTA patch to the current iOS release
Option
What it does
android / -a, --android
Patch the Android release.
ios / -i, --ios
Patch the iOS release. Deep-cleans (DerivedData, Pods) and resets CocoaPods first.
$ tahweel patch android
Flavor is always prod; version + build come from pubspec.yaml
as-is. Because a patch reaches production users immediately, it confirms before pushing. Flutter version is
3.44.3 unless overridden via tahweel config set TAHWEEL_FLUTTER_VERSION.
$ tahweel force_update REMOTE CONFIG
Sets the minimum required app version and/or the release note in
Firebase Remote Config — the thing that pops the “please update” screen on users' phones.
Use it when a release is live in the stores and old versions must upgrade. It's
safe by default: edits only the local template
(remoteconfig.template.json) — nothing goes live without --deploy.
Review first with changes.
$ tahweel force_update <platform> <flavor> -v <version> # set minimum_version$ tahweel force_update <platform> <flavor> --current# use pubspec.yaml's version$ tahweel force_update <platform> <flavor> -n "note" # set release note$ tahweel force_update changes [flavor] # preview local vs. live$ tahweel force_update changes --reset# discard local, re-fetch live
Option
What it does
<platform> <flavor>
android | ios, then prod | stage. Required
(except changes).
-v, --version <X.Y.Z>
Minimum version to enforce (semver).
--current
Use the version name from pubspec.yaml instead of typing one.
-n, --note <text>
Release note. \n or real newlines become “• ” bullets; auto-translated to fr, ar, tr
via the agy CLI.
--deploy
Publish live. Without it, changes stay in the local template.
--reset
Discard the local template and re-fetch from live Remote Config.
Parameter mapping: prod → android_config /
ios_config; stage → stg_android_config /
stg_ios_config. The safe workflow: edit locally → changes to diff against live →
re-run with --deploy.
Category 02
Project & maintenance
When the build is haunted, or the CLI needs to know where the project lives.
$ tahweel clean DEEP CLEAN
From a quick flutter clean to the full exorcism: DerivedData, Pods, pod
reinstall on iOS; Gradle cache + gradlew clean on Android.
Use it when a build fails for no reason, behaves stale, or “works on my machine” strikes.
Start with plain clean; escalate to ios / android /
all when the quick one doesn't cure it.
The GCB Status board without leaving the terminal. Log in once — only the session
cookie is stored, never your password.
$ tahweel login / logout TASKBOARD
Signs in to the taskboard and saves the session so tasks and
status just work. logout clears it.
Use it once before any taskboard command, or again when the session expires
(expired sessions prompt a re-login and resume your command automatically). Prefer
--browser if password login hits a reCAPTCHA.
$ tahweel login [email] # password prompt in the terminal (never stored)$ tahweel login --browser# sign in on the site, paste its cookies — no password in the CLI$ tahweel logout # clear the saved session
Option
What it does
[email]
Pre-fill the email; you'll only type the password.
--browser
Log in on the real site; the browser handles the CDN bot-check and you paste the session cookies.
Handy when credential login is reCAPTCHA-blocked.
$ tahweel login --browser
$ tahweel tasks TASKBOARD
Lists your tasks, starts one, or marks one done — with a completion note, because
“done” without context helps no one.
Use it for the daily loop: check the board in the morning, start what you
pick up, end it with a note when it ships.
$ tahweel tasks [--completed] [--page N] # list tasks$ tahweel tasks start <id> # start a task$ tahweel tasks end <id> [note] # finish a task (note required)
Option
What it does
(default)
Active / pending / running tasks.
--completed
Completed (done) tasks instead.
--page N
Page N of results (default 1).
--json
Raw task rows as TSV (id, status, title, project, deadline) — for scripting.
$ tahweel tasks
$ tahweel tasks start 6949
$ tahweel tasks end 6949 "Shipped in 1.2.0"
$ tahweel status TASKBOARD
Shows or sets your availability on the board.
Use it at the start and end of your working block — no need to open the site just to
flip a toggle.
$ tahweel status # show current availability$ tahweel status available # go online$ tahweel status offline # go offline
$ tahweel status available
Category 04
The CLI itself
Settings, staying current — or removing it cleanly.
$ tahweel config
View and edit every saved setting in one place, instead of hunting through separate
commands. All settings live in one file under ~/.config/tahweel.
Use it to check the current project directory, set the build-queue URL/token, or set a
notification webhook — without editing files by hand.
$ tahweel config # show all settings + where they live$ tahweel config get <key> # print one value$ tahweel config set <key> <val> # change a setting$ tahweel config unset <key> # clear a setting$ tahweel config path # print the config file path$ tahweel config edit # open it in $EDITOR
Key
What it controls
SAVED_PROJECT_DIR
Project root (also set by tahweel setup).
TAHWEEL_WEBHOOK_URL
Slack/Discord webhook to notify after a build/release.
TAHWEEL_QUEUE_URL
Remote build server base URL for lazy_build (e.g.
https://twl.towhid.space).
TAHWEEL_QUEUE_TOKEN
Your personal API token for the remote build queue.
TAHWEEL_ANALYTICS
Set to off to disable the anonymous usage ping.
$ tahweel config set TAHWEEL_QUEUE_TOKEN <token>
$ tahweel update
Re-runs the installer to pull the latest version — or pins an exact Gist revision.
Use it whenever a new version ships. Pin a SHA if you need to roll back or stay on a
known-good revision.
version prints the installed version and warns if a newer one is
published (best-effort, silent offline). help shows the
top-level usage — and every major command answers --help with its own detailed page: