The skills
The plugin ships twelve skills:
- Nine are the train — the runbook and the checks that answer a question you were going to ask anyway.
- Two ride alongside it — store copy and Android signing.
- One is standalone — a widget performance audit.
The naming grammar behind all of them is
Skills are questions. Every skill’s deep
reference is its own SKILL.md in the plugin; this page tells you which one to
reach for, and when.
Required reading — release-model
The doctrine, as a loadable skill: frozen candidates, carried build numbers, gates, the frozen window. Other skills load it first; you should read its page once before your first train.
The driver — ship
The runbook itself: /reflutter:ship. Takes the app from a ready main to
verified artifacts in internal testing, one stage at a time, dry-run first,
stopping at every gate. User-invoked only — nothing starts a release for you.
Use case: you have a fix merged on
mainand want it in testers’ hands. You type/reflutter:ship, confirm the dry-run summary, and say “run live.” Everything from analysis to a freshness-verified.aab+.ipahappens in one lane; the next thing the runbook asks of you is store copy.
“Where were we?” — checking-train-status
Reconstructs the train’s position from evidence: the release receipt
(.release-state, written by the lanes on live milestones) when it exists,
git and filesystem archaeology otherwise. Read-only; ends with the single next
step.
Use case: you come back Monday, the terminal is closed, and you can’t remember whether Friday’s release uploaded. Ask “where were we with the release?” — you get the station, the evidence, any warnings, and the exact next command. Human-only facts (did you verify on device?) are asked, never assumed.
“Is this safe?” — verifying-candidate-integrity
The pre-finalize gate as a named step. Proves nothing is stranded on the RC branch, the frozen window held, every promoted stage consumed the RC tag, and Podfile.lock drift is classified. PASS/FAIL with evidence; any FAIL is a hard stop with the exact remediation.
Use case: production is verified and you are about to finalize — the one destructive step. Run the gate first: it is the difference between “finalize deleted the scaffolding” and “finalize silently destroyed a commit.” It also audits finished releases: point it at an old version and it checks the tag landed on the bump commit.
Something failed — diagnosing-lane-failures
The judgment layer for a red lane. Maps the failure to its real cause — env files, signing, Apple agreements, stale-binary false alarms, Podfile drift — and hands back one next action. Never advances the release; never retries a step that burned a build number.
Use case: the iOS build dies with “CocoaPods is installed but broken.” That message is almost always a lie. The skill knows the two real causes (cocoapods missing from the bundle; a non-UTF-8 locale), tells you which one you have, and what to run.
Fleet sweep — auditing-train-hygiene
One read-only pass over every app repo: stranded RC commits, diverged mains, tags off the bump commit, husk branches, stale receipts, release debt. One report, grouped by severity then app, every finding with evidence and a named remediation.
Use case: a quarterly “what did past trains leave behind?” pass across all your apps — or the calibration run before you schedule the scouts.
Standing watchers — scout-stranded-work · scout-train-staleness
Scheduled versions of the checks you would forget to run. scout-stranded-work
(daily) watches the two silent-data-loss conditions; scout-train-staleness
(weekly) watches for abandoned trains and quietly accumulating release debt.
Their thresholds are plain-English sentences inside each SKILL.md — edit them
there, no code involved. Scouts report and never act; a clean fleet is
reported explicitly.
Use case: you never think about them — until one reports “rc/2.22.0 has a commit that is not on main” the morning after a rushed session, before finalize would have destroyed it.
Onboarding an app — instrumenting-release-lanes
Puts a manual app on the train: writes the reflutter.json release block
(facts read from the build config, never guessed), scaffolds the one-line
Fastfile / tag-pinned Pluginfile / Gemfile, verifies signing, then proves the
wiring with a dry run of every derived lane. Never runs anything live.
Use case: a new app has been shipping via hand-run
flutter buildcommands. One invocation later it has the same lanes, guards, and receipt as every other app — and its first real train is a deliberate/reflutter:ship.
Store copy — drafting-store-notes
The store-listing step of the train. Drafts Google Play notes (en-US + es-419,
in Play’s template, within the character limit) and the TestFlight “What to
Test” file from the CHANGELOG.md entry, gets the copy approved in
conversation, then writes both files at the exact paths the prepare lane
printed. Invoked by ship after a successful prepare; the approved copy is then
immutable downstream.
Use case: the runbook has built verified artifacts and stops for store copy. You don’t hand-write it into two consoles — the skill drafts both locales and the What-to-Test file from the changelog, you approve, and it lands them where the upload step expects.
The GitHub release write-up and the public site record are separate authoring moments that also travel with a release; the runbook stops and hands off rather than drafting that copy itself.
Build readiness — release-signing
Train-adjacent, and a dependency of ship: per-flavor Android signing configs
(env-var-first, keystore/*.properties fallback), keytool keystore
generation per environment, a gitignored keystore/ folder, and the runtime
permissions the release build needs in the main manifest.
Use case: the first release build dies with a
FinalizeBundleTaskNullPointerException, or the app runs in debug but throwserrno 7host-lookup only in the release flavor. This skill is where both are fixed — and where a new app’s signing is set up before its first train.
Standalone — auditing-widget-performance
Not release machinery: an enforcing skill that audits widgets for Equatable
chain completeness, context.select scoping, RepaintBoundary placement, and
one-widget-per-file. It ships in the plugin with its own eval fixtures.
Use case: a list scrolls poorly or a
BlocBuilderrebuilds too often. Point this skill at the widget and it names the missingEquatablefield, the over-broadcontext.watch, or the absentRepaintBoundary.