Skip to content
Marketing
Skill

/suede-play-release

Suede Labs Google Play delivery skill: ship an Android release end to end from the agent interface, without opening the Play Console. Set up credentials, upload an AAB, promote between tracks, stage or complete a rollout, push per-locale release notes, and prove against the Play

BOOST
From plugin
suede-skills
12576 skills1 MCP
Install
$ npx -y skills add JasonColapietro/suede-creator-skills --skill suede-play-release --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/suede-play-release

Context preview

The summary Claude sees to decide when to auto-load this skill.

Suede Labs Google Play delivery skill: ship an Android release end to end from the agent interface, without opening the Play Console. Set up credentials, upload an AAB, promote between tracks, stage or complete a rollout, push per-locale release notes, and prove against the Play

SKILL.md

suede-play-release.SKILL.md
name: suede-play-release
description: "Suede AI Google Play delivery skill: ship an Android release from the agent interface and prove what is live. Preflight the publishing credential with a real Play API call, upload an AAB to a testing track, promote that exact versionCode, stage or complete a rollout, write per-locale release notes, and read back versionCode, status, and userFraction from the Play Developer API. One step stays a Play Console action the user takes: the first release-access grant for the service account. Use when uploading or promoting an Android build, wiring a Play service account and fastlane supply lanes, fixing per-versionCode changelogs, raising or halting a staged rollout, or answering what production is really serving. NOT FOR: planning, building, or policy-checking the app (use android-app-factory); Play listing, keyword, and screenshot work (use suede-aso); CI required checks (use suede-ci-gate)."

Suede Play Release

Iron Law: the Play API decides what shipped, not a green fastlane summary.
Every claim about a live release is a readback or it is a guess.

Gate policy: advisory, not blocking

Run every check and report results honestly. Verdicts are advice attached to the work, never a control that changes it. A failed check changes what you report, never what you do. The one exception is the production halt in Step 7: a public release is irreversible for the users who get it, so present the options and let the user pick.

Step 0: Preflight the credential before anything else

Never assume publishing works. Prove it with a real API call that changes nothing: open an edit and delete it. The script reads the key from the macOS login Keychain and needs `pyjwt` and `cryptography`; on Linux CI, load the same base64 JSON from the CI secret store and run the equivalent token exchange.

python3 scripts/play-preflight.py <package.name> [--service NAME] [--account NAME]

Three outcomes, three different actions:

| Result | Meaning | Do | | --- | --- | --- | | token fails | key is wrong or revoked | rotate, see Step 1 | | HTTP 401/403 on the edit | Play Console has not granted the account | Step 1's grant | | edit opens and deletes | publishing is wired | continue |

A 403 here is the normal state of a brand-new service account, not a bug.

Step 1: Credentials

Use a **dedicated publishing service account**, separate from any billing or purchase-verification account. A credential that can push releases should not also be able to void purchases. Give it no cloud IAM roles: all of its authority comes from the Play Console grant, so before that grant the key is inert.

Store the JSON in the login Keychain **base64-encoded**:

security add-generic-password -U -s GOOGLE_PLAY_SERVICE_ACCOUNT_JSON -a <account> -w

Run it with `-w` last and no value so it prompts and the key never enters shell history. Paste the base64, not the raw JSON.

Base64 is load-bearing. `security` hex-encodes any multi-line secret on read, so raw JSON comes back in one of two shapes depending on content. Base64 gives one shape and one decode path.

Granting access is a **Play Console UI action** and cannot be done from the API: invite the service-account email under Users and permissions with release permissions on the app. Report this to the user as a step only they can take, with the exact email and permissions, then re-run Step 0.

Step 2: Pull before every command

`fastlane` reads the working tree, not the remote. A stale checkout produces a run that succeeds and does nothing, because a missing changelog is a skip rather than an error.

git -C <repo> pull --ff-only && git -C <repo> log --oneline -1

If fastlane offers to set itself up, the Fastfile is not on disk. Answer no and pull; accepting scaffolds an empty config over the real one.

Step 3: Write the changelog first

Release notes live at `fastlane/metadata/android/<locale>/changelogs/<versionCode>.txt`, one file per locale per versionCode.

A missing file is **not** an error. Play silently serves the previous version's notes, so users read stale text against a new build and nothing tells you. Write one for every locale that has listing copy, before uploading.

for l in $(ls fastlane/metadata/android); do
  [ -f "fastlane/metadata/android/$l/changelogs/$VC.txt" ] || echo "MISSING: $l"
done

Match each locale's existing register rather than translating the English word for word. Check the limit: 500 characters.

Step 4: Verify the artifact, never the source tree

A source read is not evidence that a change reached the binary.

jarsigner -verify app/build/outputs/bundle/release/app-release.aab | head -1
grep -oE 'android:version(Code|Name)="[^"]*"' \
  app/build/intermediates/merged_manifests/release/*/AndroidManifest.xml

When the release changes an asset, hash it on both sides and require a match:

unzip -p <aab> 'base/res/*xxxhdpi*ic_launcher.png' | shasum -a 256
shasum -a 256 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png

`jarsigner` reporting a self-signed certificate is correct under Play App Signing, which re-signs with the real release key.

Step 5: Upload to a testing track first

fastlane android internal

Build uploads carry the binary and its changelogs only. Listing text, icon, feature graphic and screenshots move through a separate lane, so a routine upload cannot rewrite what the store says about the app.

Step 6: Promote, never re-upload

Play rejects a second bundle carrying a versionCode it already has. Re-uploading is not a slower path to the same place, it is an error.

Promote the versionCode already on the testing track, which is also the only thing that makes testing-first mean anything: the artifact reaching production is the one that was validated, bit for bit.

upload_to_play_store(
  version_code: <code>, track: "internal", track_promote_to: "production",
  skip_upload_aab: true,
Read more
Ships withsuede-skills

Open-source AI skills for SEO, AI search visibility, conversion copy, marketing strategy, and business operations. Reusable workflows for Claude Code and Codex, plus code review, app delivery, and creator tools.

Get the whole plugin

Other skills on suede-skills.