Uploads store metadata via fastlane for iOS/Android and pauses with exact manual steps for final app review submission and production promotion.
How this skill is triggered — by the user, by Claude, or both
Slash command
/flutter-flame-harness:flame-harness-submitThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Phase 10 of the flutter-flame-harness pipeline. Uploads store text metadata and app categories via
Phase 10 of the flutter-flame-harness pipeline. Uploads store text metadata and app categories via fastlane for both iOS and Android, then pauses the pipeline with exact manual steps for the final review submission / production promotion that cannot be automated.
All file schemas (config.md, state.md, pipeline-log.md) and the phase transition table are
defined in docs/harness-protocol.md — that document is the single source of truth (§1 for
config.md; §2 for state.md keys and pause_reason values; §6 for pipeline-log.md schema;
§7 for the submit → metadata-done → paused transition and the (paused) → resume → retro
transition). Do not redefine schemas here.
Boundary: Text metadata upload is automated. The final "Submit for Review" tap on iOS and the "Promote to production" action on Android are manual — the Apple and Google APIs do not permit fully automated submission without human confirmation after the review build is staged.
Prerequisites: Phase 9 (flame-harness-screenshot) completed; screenshots and ASO metadata
already uploaded; state.md shows next_role: submit.
Before any action, load:
docs/harness/config.md — extract app_slug, bundle_id, app_name, and default_language
(per protocol §1).docs/harness/state.md — confirm next_role: submit (per protocol §2).Derive the game project root for <app_slug> from config.md / the harness working directory (the games live under the same parent as the harness, e.g. …/AndroidStudioProjects/<app_slug>/).
Before uploading, write the store-listing + App-Review files from the developer block in
config.md (sourced from credentials/store-metadata.md) so they actually get uploaded — these are
otherwise empty and the listing/review info would be missing.
iOS (deliver picks these up automatically):
ios/fastlane/metadata/copyright.txt ← developer.copyrightko, en-US): support_url.txt ← developer.homepage, marketing_url.txt ←
developer.homepage, privacy_url.txt ← developer.privacyios/fastlane/metadata/review_information/: first_name.txt, last_name.txt, phone_number.txt,
email_address.txt ← developer.*; notes.txt ← reviewer notes (e.g. the ATT screen-recording
note for an ads build).Android (contact email + website have no supply field — set via the Publisher API):
templates/set_contact_details.rb.template → android/fastlane/set_contact_details.rb,
fill __PACKAGE__=bundle_id, __EMAIL__=developer.email, __WEBSITE__=developer.homepage,
and run cd android && ruby fastlane/set_contact_details.rb.Run the fastlane metadata and categories lanes for both platforms. These lanes push text metadata (localized titles, descriptions, release notes) and app category assignments to the stores without uploading a binary.
cd <game>/ios
fastlane metadata
fastlane categories
fastlane metadata pushes all locale text files under ios/fastlane/metadata/ to App Store
Connect via deliver (titles, subtitles, descriptions, keywords, promotional text,
release notes).fastlane categories sets the primary and secondary App Store category. The categories lane
must already exist in the generated ios/fastlane/Fastfile (written by Phase 8
flame-harness-build).cd <game>/android
fastlane metadata
fastlane release_notes
fastlane metadata pushes all locale text files under android/fastlane/metadata/android/ to
Google Play (titles, short descriptions, full descriptions) via upload_to_play_store with
skip_upload_apk: true and skip_upload_aab: true.fastlane release_notes pushes the changelogs/<version-code>.txt files for the current
release.If any fastlane lane exits non-zero, do NOT proceed to the pause step. Instead write
docs/harness/state.md with status: paused, pause_reason: manual_action, and
next_role: submit (retry), then explain the error and stop.
After both upload sequences complete successfully, the pipeline must pause so the developer can perform the final submission actions that cannot be automated.
Pre-submit rejection checklist (print this with the manual steps — these are the rejections
already hit; see docs/game-gotchas.md → Store rejections):
ITSAppUsesNonExemptEncryption=false) so no per-upload prompt.PrivacyInfo.xcprivacy, which is a bundled manifest — the
label is a Connect form). A missing/empty label blocks release. Use the Data-collection profile
below.PrivacyInfo.xcprivacy present in the bundle; tracking matches the ATT prompt.developer.privacy); Content Rating (IARC), Data Safety, and
Target Audience questionnaires completed with the Data-collection profile below. (Contact
email/website were set in Phase 0 via the API script.)tagForChildDirectedTreatment, and Play Target Audience must include children — keep all three
consistent or expect a rejection / FTC exposure.Per docs/harness-protocol.md §7 (submit → metadata-done event row) and §7 rule 3 (when
status is paused, pause_reason must be non-empty), write docs/harness/state.md atomically
with exactly these field changes (leave created_at, current_round, resume_attempts
unchanged):
status: paused
current_phase: submit
next_role: retro
pause_reason: manual_action
updated_at: "<ISO-8601 UTC now>"
Important: next_role: retro is set at pause time because a paused state stores the role to
run after resume. flame-harness-resume reads next_role directly from state.md (it does
NOT set next_role itself) and dispatches Skill("flame-harness-<next_role>"). Setting
next_role: retro here is what causes resume to advance to retro rather than re-dispatching
submit (see Resume Contract below).
Append one row to docs/harness/pipeline-log.md per the schema in docs/harness-protocol.md §6,
using the transition event name metadata-done (matches protocol §7):
| <ISO-8601 UTC now> | pause | submit | metadata-done: iOS metadata+categories uploaded, Android metadata+release_notes uploaded; awaiting manual Submit for Review (iOS) and production promotion (Android) |
After writing state, print the following instructions verbatim for the developer:
PIPELINE PAUSED — MANUAL SUBMISSION REQUIRED
Fastlane has uploaded all text metadata and categories. You must now complete the final submission steps manually, as the Apple and Google APIs do not support fully automated review submission.
iOS — Submit for Review
flame-harness-build (Phase 8).Android — Promote to Production
flame-harness-build (Phase 8).Data-collection profile — the privacy questionnaires on both stores ask the same underlying question. For a typical offline Flame game with AdMob (and no login/analytics/PII), fill them with:
| Question | Answer |
|---|---|
| Collects data? | Yes — only if AdMob is enabled (skip_admob: false); otherwise No. |
| Data type | Identifiers — advertising ID / device ID (AdMob). No name, email, location, contacts, photos, health, financial, or messages. |
| Purpose | Third-party advertising (and, if ATT-authorized, measurement). |
| Linked to identity? | No (no account/login). |
| Used for tracking? | Yes if ATT-authorized (advertising ID → cross-app). Declare this on iOS App Privacy → "Tracking". |
| Shared with third parties? | Yes — the AdMob SDK (Google). |
| Encrypted in transit? | Yes. |
| User can request deletion? | Not applicable (no server-side user data). |
skip_admob: true, declare Data Not Collected.skip_admob: true, "No data collected".tagForChildDirectedTreatment(true) — all three must agree.When you have completed all of the above steps on both platforms, run:
/flame-harness-resume
flame-harness-resume will confirm you are done, clear the pause, and launch
flame-harness-retro (the pipeline was already set to next_role: retro at pause time).
This section documents the expected behaviour of flame-harness-resume when it encounters the
pause written by this skill. It is informational — flame-harness-resume is the authoritative
implementation (see its SKILL.md).
Per docs/harness-protocol.md §7:
metadata-done; it sets status: paused with pause_reason: manual_action.(paused) → resume → retro.flame-harness-resume will:
pause_reason to "" (per §7 rule 8).status: running atomically (per §7 rules 1 and 2). flame-harness-resume does NOT
set next_role — it reads whatever next_role is already in state.md. Because this
skill wrote next_role: retro at pause time, resume dispatches retro.resume_attempts (per §7 rule 4).resume row to pipeline-log.md (per §6).next_role (= retro) from the updated state.md and dispatch
Skill("flame-harness-retro").The retro phase (next_role: retro) is the final phase; when it completes it sets
status: completed (per §7 retro → complete row).
npx claudepluginhub tjdrhs90/flutter-flame-harness --plugin flutter-flame-harnessCaptures store screenshots in multiple locales via Flutter integration_test (ads hidden), fills ASO keywords, and uploads via fastlane. Part of the flutter-flame-harness pipeline.
Guides mobile app deployment to App Store Connect and Google Play Console: configuration, code signing/provisioning, Fastlane automation, review compliance, phased rollouts, Crashlytics/Sentry integration.
Builds and submits mobile apps using local fastlane pipelines with pre-submission checklists. Activates on queries about app builds, store submission, or mobile deployment.