
Gpc Release Flow
- 30 installs
- 1 repo stars
- Updated August 1, 2026
- yasserstudio/gpc-skills
Helps with ai & agent building tasks.
About
gpc-release-flow is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- gpc-release-flow
- AI & Agent Building
- AI-coding skill
Gpc Release Flow by the numbers
- 30 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #9,299 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/yasserstudio/gpc-skills --skill gpc-release-flowAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 30 |
|---|---|
| repo stars | ★ 1 |
| Last updated | August 1, 2026 |
| Repository | yasserstudio/gpc-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
GPC Release Flow
When to use
Use this skill when the task involves:
- Uploading AAB/APK files to Google Play
- Creating releases on any track (internal, alpha, beta, production)
- Promoting releases between tracks
- Managing staged rollouts (increase, halt, resume, complete)
- Setting release notes
- Using
gpc publishfor end-to-end release workflow - Pre-submission validation with
gpc validate - Checking release status across tracks
- Updating a private app (created via
gpc enterprise publishin v0.9.56+) — after the initial custom-app creation, all subsequent operations use the standard commands in this skill against the assignedpackageName
Not this skill:
- Creating a new private app for Managed Google Play — use
gpc-enterprise(v0.9.56+). After creation, come back here for version uploads and track management.
Inputs required
- Path to AAB/APK file
- Target track (internal, alpha, beta, production, or custom)
- Rollout percentage (for staged rollouts)
- Release notes (inline or from file)
- Whether
--dry-runis desired (preview without executing)
Procedure
0) Pre-flight validation
Before uploading, run the preflight compliance scanner and validate the bundle:
# Policy compliance scan (offline -- checks manifest, permissions, 64-bit, secrets)
gpc preflight app-release.aab --fail-on error
gpc preflight app-release.apk --fail-on error # APK also supported
# File format and track validation
gpc validate app-release.aab
gpc validate app-release.aab --track beta # Validate for specific trackgpc preflight checks the AAB/APK against Google Play policies (target SDK, permissions, native libs, etc.). gpc validate checks file format, version code conflicts, and track compatibility.
1) Upload and release
A) Quick release (one command)
The publish command handles the full flow — upload, track assignment, release notes, and commit:
gpc publish app-release.aab --track internal
gpc publish app-release.aab --track beta --notes "Bug fixes and improvements"
gpc publish app-release.aab --track production --rollout 10
# Set in-app update priority (0-5) so clients can prompt updates (v0.9.70+)
gpc publish app-release.aab --track production --rollout 10 --in-app-update-priority 5
# Retain older version codes alongside the new upload (v0.9.70+)
gpc publish app-release.aab --track production --retain-version-codes 42,43
# Validate only — run the full pipeline (upload, track assignment, validate) but stop
# before committing. Useful for CI dry-validation against the real API. (v0.9.68+)
gpc publish app-release.aab --track beta --validate-onlyMulti-language release notes from directory:
gpc publish app-release.aab --track beta --notes-dir ./release-notes/
# Falls back to default.txt when a locale-specific file is missing (v0.9.70+)B) Step-by-step release
For more control, use individual commands:
# Upload AAB (creates edit, uploads, assigns to track)
gpc releases upload app-release.aab --track internal
# Upload APK (auto-detected, uses correct endpoint)
gpc releases upload app-release.apk --track internal
# Upload with staged rollout
gpc releases upload app-release.aab --track production --rollout 10
# Upload as draft (not visible to users until explicitly released)
gpc releases upload app-release.aab --track production --status draft
# Validate only — upload and validate but do not commit (v0.9.68+)
gpc releases upload app-release.aab --track beta --validate-only
# Set release notes
gpc releases notes set --track beta --lang en-US --notes "Bug fixes"
gpc releases notes set --track beta --file release-notes/ # From directoryNew in v0.9.47: APK files are auto-detected and uploaded via the correctedits.apks.uploadendpoint. Use--status draftto create draft releases for manual review in the Play Console before going live.
npm publishing (v0.9.77+): GPC packages are published via Trusted Publisher (OIDC) with Staged Publishing. CI stages packages automatically; a maintainer approves with 2FA before they go live on npm. No long-livedNPM_TOKENis used. Seegpc-ci-integrationfor CI/CD workflow details.
Additional upload flags (v0.9.51+)
# Upload native debug symbols (ProGuard mapping or native code symbols)
gpc releases upload app.aab --track internal --mapping-type proguard # default
gpc releases upload app.aab --track internal --mapping-type nativeCode
# Target a specific device tier configuration
gpc releases upload app.aab --track production --device-tier-config 12345
gpc releases upload app.aab --track production --device-tier-config LATEST
# Skip sending changes for review (required for rejected apps)
gpc releases upload app.aab --track production --changes-not-sent-for-review
# Fail safely if there are changes already in review
gpc releases upload app.aab --track production --error-if-in-review| Flag | Values | Description |
|---|---|---|
--mapping-type | proguard (default), nativeCode | Specifies the type of debug symbols to upload alongside the bundle. Use nativeCode when shipping native (C/C++) libraries |
--device-tier-config | numeric ID or LATEST | Applies a device tier targeting configuration so different APKs are served to different device classes |
--changes-not-sent-for-review | boolean flag | Commits the edit without sending changes for review. Required when a previous submission was rejected and you are not yet ready for re-review |
--error-if-in-review | boolean flag | Causes the command to exit with a non-zero code if there are already changes in review, instead of silently overwriting them |
--validate-only | boolean flag | Runs the full upload and validation pipeline but stops before edits.commit. The edit is deleted after validation. Useful for CI pre-merge checks (v0.9.68+) |
--in-app-update-priority | 0-5 | Sets the in-app update priority for this release. 0 = default (no urgency), 5 = highest urgency. Clients using the Play Core in-app update API can read this to decide whether to show a flexible or immediate update prompt (v0.9.70+) |
--retain-version-codes | comma-separated | Comma-separated list of version codes to retain alongside the new upload. Prevents older APKs/AABs from being deactivated by the new release (v0.9.70+) |
Fastlane-style changelog fallback (v0.9.70+)
When --notes-dir is used and no locale-specific file exists for a given locale, GPC falls back to default.txt in the notes directory. This matches Fastlane's convention and avoids empty release notes for unlisted locales.
Rejected Apps
When Google Play rejects a submission, your app enters a "changes in review" state. Subsequent uploads or promotions will fail unless you handle this explicitly:
1. If you want to push changes without triggering a new review (e.g., updating metadata while fixing the rejection reason), use --changes-not-sent-for-review. This commits your edit but leaves the review state untouched. 2. If you want to guard against accidentally overwriting in-review changes (e.g., a CI pipeline that should not clobber a pending review), use --error-if-in-review. The command will exit with code 4 (API error) if changes are currently in review. 3. If you are ready to re-submit for review, omit both flags and upload normally. Google Play will replace the pending submission with your new one.
These flags apply to gpc releases upload, gpc publish, gpc releases promote, gpc releases rollout, gpc listings push/update/delete, gpc listings images upload/delete, gpc testers add/remove/import, gpc tracks create/update, and gpc apps update.
Note (v0.9.52+): When--changes-not-sent-for-reviewis set, GPC skips server-side edit validation (edits.validate) and goes straight toedits.commit. This is required because Google's validate endpoint does not accept thechangesNotSentForReviewparameter and rejects edits for apps with rejected updates. Your changes are still validated by the commit call itself.
Read:
references/upload-lifecycle.md
2) Check release status
# Full picture — releases, vitals, and reviews in one command
gpc status
# Releases only, all tracks
gpc releases status
# Specific track detail
gpc releases status --track production
# JSON for scripting
gpc status --output json | jq '.releases[] | select(.track == "production")'3) Promote between tracks
# Promote from internal to beta
gpc releases promote --from internal --to beta
# Promote from beta to production with staged rollout
gpc releases promote --from beta --to production --rollout 5
# Copy release notes from another track when promoting
gpc releases promote --from internal --to production --copy-notes-from internal
# Promote as draft (review in Play Console before going live)
gpc releases promote --from internal --to beta --status draftNote: Since v0.9.39, gpc releases promote auto-retries once on 409 EDIT_CONFLICT (another edit is open).Promote also supports the review-control flags (v0.9.51+):
# Promote without sending for review (rejected app workflow)
gpc releases promote --from internal --to beta --changes-not-sent-for-review
# Fail if changes are already in review
gpc releases promote --from beta --to production --rollout 5 --error-if-in-review3b) Preview before publishing
# Read-only preview of release state across all tracks
gpc diff
# Compare two specific tracks
gpc diff --from internal --to production
# Compare local metadata vs remote
gpc diff --metadata fastlane/metadata3c) Release lifecycle visibility
# List releases on a track with lifecycle states (DRAFT, IN_REVIEW, PUBLISHED, etc.)
gpc releases list --track production
gpc releases list --track beta --jsonNew in v0.9.46: The releases.list endpoint provides release lifecycle states without opening an edit session. Use it to check whether a release is still in review, has been published, or is in draft -- useful for CI pipelines that need to gate on review completion.3d) Release stats and history
# Release count per track with status breakdown
gpc releases count
# Show release history from GitHub
gpc changelog
gpc changelog --tag v0.9.47
# Generate GitHub Release notes from local commits (v0.9.61+)
gpc changelog generate # markdown for the next release
gpc changelog generate --format prompt | pbcopy # paste into Claude/ChatGPT
gpc changelog generate | gh release create vX -F - # one-command release
gpc changelog generate --strict # fail CI on linter warnings (jargon, scope leaks)::: tip Two different release notes flows
- Play Store
recentChanges[](per-locale, 500-char):gpc changelog generate --target play-store --locales auto --ai --apply(v0.9.64+, end-to-end) orgpc publish --notes-from-git --since vX - GitHub Release notes (canonical markdown template, smart clustering, LLM-prompt mode):
gpc changelog generate(v0.9.61+)
:::
Multilingual Play Store release notes (v0.9.62+)
For per-locale Play Store "What's new" text, pass --target play-store with --locales:
# Translate via your own LLM key (BYO, v0.9.63+)
gpc changelog generate --target play-store --locales auto --ai
# Explicit locales, no AI — placeholder text for non-source locales
gpc changelog generate --target play-store --locales en-US,fr-FR,de-DE
# Auto-detect from your live Play listing (one API round-trip)
gpc changelog generate --target play-store --locales auto --app com.example.app
# Preview the prompt without spending tokens
gpc --dry-run changelog generate --target play-store --locales auto --aiKey behaviors:
- en-US source is the same bullet list as the github target, truncated to 500 Unicode code points if over
- With
--ai(v0.9.63+): non-source locales are translated via the user's own LLM key. Auto-detects priority env order:AI_GATEWAY_API_KEY→ANTHROPIC_API_KEY→OPENAI_API_KEY→GOOGLE_GENERATIVE_AI_API_KEY. Non-reasoning model defaults (claude-sonnet-4-6,gpt-4o-mini,gemini-2.5-flash). Override with--provider/--model. - Without
--ai: non-source locales get a[needs translation]placeholder. Use--format promptto emit a translation-ready LLM prompt for the offline / no-key workflow. --strictexits 1 if any locale overflows 500 chars OR (with--ai) any locale fails to translate- Lazy-loaded: running without
--aiimports none of the AI SDK deps. Cold-start budget preserved. - AI SDK v6 (v0.9.82+): the underlying
@ai-sdk/*packages were upgraded from 5.x to 6.0. The public--aiinterface and all model provider options are unchanged. No migration steps are required for users.
Writing translated notes into a draft release (v0.9.64+)
Once your release notes are generated (with or without --ai), write them directly into the latest draft on a Play Store track:
# Full pipeline: generate + translate + apply
gpc changelog generate --target play-store --locales auto --ai --apply
# Apply to a specific track (default: production)
gpc changelog generate --target play-store --locales auto --ai --apply --track beta
# Preview what would be written (no API call)
gpc changelog generate --target play-store --locales auto --ai --apply --dry-runKey behaviors:
--applyrequires--target play-store(not compatible with--format prompt)- Writes into the latest draft release on the track. If no draft exists, exits with
RELEASE_NO_DRAFT(exit code 1) and suggests creating one first - Uses
withRetryOnConflictfor 409 edit conflicts --dry-runshows the notes that would be written without touching the API
Bundle upload race fix (v0.9.64+, extended v0.9.77): After uploading a large AAB (65MB+), GPC pollsbundles.listwith Fibonacci backoff (2s, 3s, 5s, 8s, 13s, 21s, 34s -- ~86s total) before callingedits.validate. This fixes intermittentINVALID_ARGUMENT: Some of the Android App Bundle uploads are not completed yeterrors that affected all AAB upload paths. GPC is the only known CLI that handles this server-side processing gap; Google's API docs do not document the async behavior.
Multi-retry guard on validate/commit (v0.9.77): After bundle processing completes,edits.validateandedits.commiteach retry up to 3 times with escalating timeouts (15s, 30s, 45s). This handles transient server-side delays where the bundle is processed but the edit is not yet committable.
See apps/docs/guide/multilingual-release-notes.md for the full walkthrough, including the Vercel AI Gateway path (cost-per-run in USD reported back).
4) Manage staged rollouts
# Increase rollout percentage
gpc releases rollout increase --track production --to 50
# Halt rollout (stops further distribution)
gpc releases rollout halt --track production
# Resume halted rollout
gpc releases rollout resume --track production
# Complete rollout (100%)
gpc releases rollout complete --track productionRollout commands also support review-control flags (v0.9.51+):
# Increase rollout without triggering review (rejected app workflow)
gpc releases rollout increase --track production --to 50 --changes-not-sent-for-review
# Complete rollout, but fail if there are changes in review
gpc releases rollout complete --track production --error-if-in-reviewRead:
references/rollout-strategies.md
5) Track management
gpc tracks list # List all tracks
gpc tracks get production # Show track details + current releasesAssign an existing version code to a different track (v0.9.78+)
If an AAB is already uploaded, you can assign its version code to a different track without re-uploading:
gpc releases assign 42 --track beta
gpc releases assign 42 --track production --rollout 10This is useful when you want to move a version code from one testing track to another, or when a CI build uploaded to internal and you want to assign it to alpha for a wider audience.
Create a custom closed testing track (v0.9.79+)
Google Play supports custom closed testing tracks in addition to the built-in internal, alpha, beta, and production tracks:
gpc tracks create --track-id my-custom-track --name "Partner Testing"Uses edits.tracks.create under the hood. After creation, use the custom track ID in any --track flag.
6) Preview with dry-run
All write operations support --dry-run:
gpc releases upload app.aab --track beta --dry-run
gpc releases promote --from beta --to production --rollout 10 --dry-run
gpc releases rollout increase --track production --to 50 --dry-runWith --json and --dry-run together, the output includes executed[] and skipped[] arrays so CI pipelines can inspect which steps would have run (v0.9.79+):
{
"dryRun": true,
"executed": [],
"skipped": ["upload", "validate", "commit"]
}7) Interactive mode
When flags are omitted, GPC prompts interactively (if TTY detected):
gpc releases upload app.aab
# Prompts for: track, rollout percentage, release notesDisable with --no-interactive or GPC_NO_INTERACTIVE=1.
Verification
gpc statusshows the release on the expected track with correct status and rolloutgpc releases statusconfirms version code matches the uploaded AAB- Rollout percentage is correct
- Release notes are set for the expected languages
gpc vitals crashes --version <code>shows no spikes post-release (or usegpc statusto check vitals across all metrics)
Failure modes / debugging
| Symptom | Likely Cause | Fix |
|---|---|---|
Version code already used | Same version code exists on this track | Increment versionCode in build |
APK_NOT_SIGNED | Missing or invalid signing | Use Play App Signing or check keystore |
EDIT_CONFLICT | Another edit is in progress | Wait and retry, or use Console UI to discard pending edit |
| Rollout stuck | Rollout was halted | gpc releases rollout resume --track <track> |
| Wrong track | Promoted to wrong track | Create new release on correct track |
Commit rejection: reviewPending and nextStep (v0.9.79+)
When Google Play rejects the edits.commit call because changes must go through review, GPC returns a structured result instead of a plain error:
{
"reviewPending": true,
"nextStep": "Your changes are under Google review. Check Play Console for status or use --changes-not-sent-for-review to bypass review for non-reviewed tracks."
}The reviewPending field is always a boolean. The nextStep string is human-readable guidance. CI pipelines can key on reviewPending === true to decide whether to poll, notify, or exit.
Internal track skips review (v0.9.79+)
The internal testing track does not require Google review. When committing to the internal track, GPC sets reviewSkipped: true in the structured output to indicate that the commit went through immediately without entering the review queue.
Read:
references/troubleshooting.mdreferences/pre-release-pipeline.md— end-to-end: validate → upload → vitals gate → promote → staged rollout
8) Real-Time Developer Notifications (RTDN)
Monitor subscription and purchase events in real time:
gpc rtdn status # Check Pub/Sub topic configuration
gpc rtdn decode <payload> # Decode base64 notification payload
gpc rtdn test # Guidance for testing RTDN setupPreviously known bugs (fixed in v0.9.78)
All items below were resolved in v0.9.78. Listed for historical context only.
| Bug | Status |
|---|---|
tracks update silently wipes tracks | Fixed: versionCode coercion + nested JSON support |
--changes-not-sent-for-review flag never reaches API | Fixed: validateAndCommit auto-rescue on validate (15+ commands) |
| Cannot assign already-uploaded versionCode to a new track without re-uploading | Fixed: gpc releases assign <versionCode> --track <track> |
Related skills
- gpc-setup: Authentication and configuration
- gpc-metadata-sync: Store listings and screenshots
- gpc-vitals-monitoring: Post-release crash monitoring
- gpc-ci-integration: Automated releases in CI/CD
- gpc-monetization: Subscriptions, IAP, RTDN notifications
- gpc-enterprise: Private app publishing to Managed Google Play via the Play Custom App Publishing API (v0.9.56+)
{
"skill_name": "gpc-release-flow",
"evals": [
{
"id": 1,
"prompt": "I just finished building my app and the AAB is at app/build/outputs/bundle/release/app-release.aab. I want to push it to our internal testing track first so QA can look at it, then if it's good we'll promote it to beta. What's the fastest way to do this with gpc?",
"expected_output": "Shows how to upload to internal track and then promote to beta, with validation step",
"files": [],
"expectations": [
"Uses gpc publish or gpc releases upload with --track internal",
"Mentions gpc validate as optional pre-check",
"Shows gpc releases promote --from internal --to beta for promotion",
"Mentions gpc releases status to verify the release landed correctly",
"Suggests --dry-run for previewing before executing"
]
},
{
"id": 2,
"prompt": "Our production release is at 25% rollout and we're seeing a spike in crashes on Samsung devices running Android 13. The crash rate jumped from 0.5% to 3.2%. Should we halt the rollout? How do I do that and what are our options after halting?",
"expected_output": "Recommends halting immediately, shows the command, explains options after halting (fix and re-release vs resume)",
"files": [],
"expectations": [
"Recommends halting given crash rate exceeds safe threshold",
"Shows gpc releases rollout halt --track production",
"Explains that halting stops new installs but doesn't remove from existing users",
"Suggests checking vitals with gpc vitals crashes --version",
"Recommends creating a new release with the fix rather than resuming the bad one"
]
},
{
"id": 3,
"prompt": "I want to set up a safe production rollout strategy. We release every 2 weeks and right now we just push to 100% which is scary. Can you help me design a staged rollout plan I can follow each release?",
"expected_output": "Provides a multi-day staged rollout plan with GPC commands and vitals checks at each stage",
"files": [],
"expectations": [
"Provides a multi-stage rollout plan (e.g., 1% → 10% → 50% → 100%)",
"Includes vitals checks between stages using gpc vitals crashes --threshold",
"Shows gpc releases rollout increase commands for each stage",
"Shows gpc releases rollout complete for final stage",
"Mentions exit code 6 for threshold breach as safety gate"
]
},
{
"id": 4,
"prompt": "I want to fully automate our staged rollout — internal → alpha → 10% production → 100% production with time gates and crash gates. Can GPC handle this automatically without me manually running commands each time?",
"expected_output": "Shows gpc train with .gpcrc.json config as the automated release pipeline solution",
"files": [],
"expectations": [
"Introduces gpc train as the automated release pipeline solution",
"Shows the .gpcrc.json release-train config with stages and gates",
"Shows gpc train start to kick off the pipeline",
"Explains that gates (crash/ANR thresholds) automatically pause progression",
"Shows gpc train status to monitor current stage and time remaining"
]
},
{
"id": 5,
"prompt": "I'm getting EDIT_CONFLICT when trying to upload a new release. I think I had a previous gpc command crash mid-upload. How do I fix this?",
"expected_output": "Explains stale edit conflict and shows recovery steps",
"files": [],
"expectations": [
"Explains that a crashed session can leave an open (pending) edit on the API",
"Notes that GPC v0.9.35+ auto-retries with a fresh edit via withFreshEdit()",
"Suggests discarding the pending edit via Google Play Console UI if still stuck",
"Recommends upgrading to v0.9.35+ which handles this automatically",
"Shows the retry is automatic — no manual cleanup needed in v0.9.35+"
]
}
]
}
Pre-Release Validation Pipeline
End-to-end workflow for safely getting a release from build to production.
Full pipeline
validate AAB → upload to internal → smoke test → promote to beta →
wait for vitals → gate on crash rate → promote to production → staged rolloutStep 1 — Validate before upload
Always validate before uploading to avoid wasted edit sessions:
# Pre-submission checks: file format, size, track compatibility
gpc validate app.aab --track beta
# With ProGuard mapping and release notes
gpc validate app.aab --track production --mapping mapping.txt --notes-dir changelogs/
# In CI — exits non-zero if validation fails
gpc validate app.aab --track beta --output json | jq '.valid'gpc validate checks: AAB file integrity, file size (warns if >100 MB), track name validity, ProGuard mapping file existence, release notes length.
Step 2 — Upload to internal first
gpc releases upload app.aab --track internalInternal track has no minimum requirements and is always the right first destination. Lets you smoke test before touching beta or production.
Step 3 — Check current status
gpc status
# → RELEASES shows internal with your new version
# → VITALS shows current crash/ANR rates
# → REVIEWS shows recent sentimentIf gpc status exits with code 6, vitals are breached — do not promote.
Step 4 — Promote to beta
gpc releases promote --from internal --to beta --rollout 100Or use gpc publish for the end-to-end flow (validate + upload + promote in one command):
gpc publish app.aab --track beta --notes "Release notes here"Step 5 — Wait and check vitals
Crash data from a new release takes 6-48 hours to appear. Check:
# After waiting (next day or per monitoring schedule)
gpc vitals crashes --version <versionCode>
gpc vitals anr --version <versionCode>
# Or use the unified status with a fresh fetch
gpc status --refreshStep 6 — Gate on vitals before production
# Check crash rate (exits 6 if breached)
gpc vitals crashes --threshold 2.0
# Check ANR rate
gpc vitals anr --threshold 0.47
# Or check both via gpc status (exits 6 if any threshold breached)
gpc statusStep 7 — Promote to production with staged rollout
# Start at 10% to catch issues before full rollout
gpc releases promote --from beta --to production --rollout 10
# Increase over time once stable
gpc releases rollout increase --track production --to 25
gpc releases rollout increase --track production --to 50
gpc releases rollout increase --track production --to 100
# Emergency brake if needed
gpc releases rollout halt --track productionGitHub Actions example
v0.9.74+ security pattern: Scope GPC_SERVICE_ACCOUNT to individual steps that need it (upload, promote) rather than setting it at the job level. This limits credential exposure — steps that don't call the Play API (validate, vitals read, status) do not receive the secret.name: Release to Production
on:
workflow_dispatch:
inputs:
version_name:
description: 'Version name (e.g. 1.5.0)'
required: true
jobs:
release:
runs-on: ubuntu-latest
env:
GPC_APP: com.example.app
steps:
- uses: actions/checkout@v4
- name: Install GPC
run: npm install -g @gpc-cli/cli
- name: Validate AAB
run: gpc validate app-release.aab --track internal
- name: Upload to internal
# GPC_SERVICE_ACCOUNT is scoped to this step only (v0.9.74+: least-privilege pattern)
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
run: gpc releases upload app-release.aab --track internal
- name: Gate on vitals before promotion
run: |
gpc vitals crashes --threshold 2.0
gpc vitals anr --threshold 0.47
- name: Promote to production (10% rollout)
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SERVICE_ACCOUNT }}
run: gpc releases promote --from internal --to production --rollout 10
- name: Post status to step summary
if: always()
run: gpc status --refresh --output markdown >> $GITHUB_STEP_SUMMARYTiming notes
| Action | Data availability |
|---|---|
| Upload completes | Immediate |
| Release visible in Play Console | 5-30 minutes |
| Crash/ANR data for new version | 6-48 hours |
| vitals compare (trend) | 2+ days of data needed |
| Review sentiment shift after release | 1-7 days |
Rollback
If production release has issues:
# Halt the rollout immediately
gpc releases rollout halt --track production
# Promote the previous stable version back
gpc releases promote --from internal --to production --rollout 100Multi-Language Release Notes
Managing release notes (what's new text) across languages with GPC.
Setting release notes during upload
# Upload with release notes
gpc releases upload app-release.aab \
--track beta \
--release-notes "en-US=Bug fixes and performance improvements"
# Multiple languages
gpc releases upload app-release.aab \
--track beta \
--release-notes "en-US=Bug fixes and improvements" \
--release-notes "ja-JP=バグ修正とパフォーマンスの向上" \
--release-notes "fr-FR=Corrections de bugs et améliorations"Using a release notes file
For many languages, use a directory of text files:
gpc releases upload app-release.aab \
--track production \
--release-notes-dir release-notes/Directory structure
release-notes/
├── en-US.txt
├── ja-JP.txt
├── fr-FR.txt
├── de-DE.txt
└── es-ES.txtEach file contains the plain text release notes for that language.
Release notes with gpc publish
gpc publish app-release.aab \
--track production \
--rollout 10 \
--release-notes-dir release-notes/Character limits
| Field | Limit |
|---|---|
| Release notes | 500 characters per language |
Tips
- Keep release notes under 500 characters per language
- Use the same
release-notes/directory across releases — update files per version - Commit release notes to git for history and review
- Release notes carry forward when promoting between tracks
- If no release notes are provided during promotion, the previous track's notes are used
Rollout Strategies
Staged Rollout Overview
Staged rollouts let you release to a percentage of users before going to 100%. This reduces risk by catching issues early.
Recommended Rollout Pattern
Day 1: Release to internal track (QA team)
Day 2: Promote to beta track (beta testers)
Day 3: Promote to production at 1% rollout
Day 4: Check vitals → increase to 10%
Day 5: Check vitals → increase to 50%
Day 7: Check vitals → complete (100%)Commands for this pattern:
# Day 1
gpc publish app.aab --track internal
# Day 2
gpc releases promote --from internal --to beta
# Day 3
gpc releases promote --from beta --to production --rollout 1
# Day 4 (check vitals first)
gpc vitals crashes --threshold 2.0
gpc releases rollout increase --track production --to 10
# Day 5
gpc vitals crashes --threshold 2.0
gpc releases rollout increase --track production --to 50
# Day 7
gpc vitals crashes --threshold 2.0
gpc releases rollout complete --track productionRollout State Machine
upload/promote
│
▼
┌──────────┐
│ inProgress│ (rollout < 100%)
└─────┬─────┘
│
┌───────┼───────┐
▼ ▼ ▼
increase halt complete
│ │ │
▼ ▼ ▼
inProgress halted completed
│ (done)
▼
resume
│
▼
inProgressRollout Commands
| Command | What it does |
|---|---|
rollout increase --to N | Increase percentage to N% |
rollout halt | Stop distribution (users who have it keep it) |
rollout resume | Resume a halted rollout at previous percentage |
rollout complete | Push to 100% |
Vitals-Gated Rollout (CI)
v0.9.74+ behavior change: gpc releases rollout increase now checks crash/ANR thresholds before executing the rollout increase. If any threshold is breached, the command exits with code 6 and the rollout percentage is not changed. In earlier versions, the vitals check ran after the API call.#!/bin/bash
set -e
# Upload to production at 5%
gpc releases upload app.aab --track production --rollout 5
# Wait for crash data
sleep 3600 # 1 hour
# Option A (v0.9.74+): pass thresholds directly — vitals are checked before the increase
# Exits 6 without touching rollout if thresholds are breached
gpc releases rollout increase --track production --to 50 \
--crash-threshold 2.0 --anr-threshold 0.47
# Option B: explicit pre-check (any version)
gpc vitals crashes --threshold 2.0 # exits 6 if breached
gpc vitals anr --threshold 0.47 # exits 6 if breached
gpc releases rollout increase --track production --to 50Halting a Rollout
If you detect issues after release:
# Immediately halt distribution
gpc releases rollout halt --track production
# Investigate
gpc vitals crashes --version <code>
# After fixing, create a new release (don't resume the bad one)
gpc publish fixed-app.aab --track production --rollout 5Important Notes
- You can only increase rollout percentage, never decrease (except by halting)
- Halting stops new installs but doesn't remove the app from existing users
- Completing a rollout is irreversible
- Each track can have only one active staged rollout
Release Flow Troubleshooting
Common Upload Errors
Version code already used
The version code in your AAB/APK already exists on this track.
Fix: Increment versionCode in your app's build.gradle:
android {
defaultConfig {
versionCode 143 // Increment this
}
}APK_NOT_SIGNED or signing errors
Possible causes: 1. AAB is not signed at all 2. Using wrong signing key 3. Play App Signing not set up
Fix: Ensure you're signing with the correct upload key:
# Check signing info
jarsigner -verify -verbose app-release.aabEDIT_CONFLICT
Another edit is already in progress for this app.
Possible causes: 1. Console UI has an unsaved draft 2. Another CI job is running simultaneously 3. Previous GPC command failed mid-edit
Fix: 1. Open Play Console → check for unsaved changes → discard 2. Add concurrency limits to CI jobs:
concurrency:
group: play-store-${{ github.ref }}
cancel-in-progress: false3. Wait and retry
Upload timeout
Fix: Increase timeout for large files:
export GPC_TIMEOUT=120000 # 2 minutes
gpc releases upload large-app.aab --track internalPromotion Errors
No release to promote
The source track has no release to promote.
Fix: Check current releases:
gpc releases statusEnsure the source track has a completed release (not draft or halted).
Version code conflicts on target track
The target track already has a release with the same or higher version code.
Fix: Upload a new version with a higher version code.
Rollout Errors
Cannot decrease rollout percentage
Google Play doesn't allow decreasing rollout percentage.
Fix: Either:
- Halt the rollout:
gpc releases rollout halt --track production - Or complete it:
gpc releases rollout complete --track production
Cannot resume — rollout is not halted
The rollout is in inProgress state, not halted.
Fix: Check current state:
gpc releases status --track productionDebugging with --dry-run
Preview any write operation without executing:
gpc releases upload app.aab --track beta --dry-run
gpc releases promote --from beta --to production --dry-run
gpc releases rollout increase --track production --to 50 --dry-runDry-run shows what would happen, including edit creation and API calls.
Debugging with --verbose
Enable debug logging to see API requests:
gpc releases upload app.aab --track beta --verboseShows: HTTP method, URL, request/response details, timing.
Upload & Edit Lifecycle
How Google Play Edits Work
Google Play uses an "edit" lifecycle for all mutations. GPC manages this automatically, but understanding it helps debug issues.
Edit Flow
1. Insert Edit → Creates a new edit (gets editId)
2. Modify Edit → Upload AAB, set track, set release notes
3. Validate Edit → Check for errors before committing
4. Commit Edit → Apply all changes atomically
(or Delete Edit → Discard all changes on failure)Key Rules
- Only one active edit per app — if another edit exists (from Console UI or another tool), GPC will get an
EDIT_CONFLICTerror - Edits expire after 1 hour — long-running operations may need a new edit
- Commit is atomic — all changes in an edit are applied together or not at all
- GPC handles this automatically — you don't need to manage edits manually
Upload Process
What gpc releases upload does:
1. Creates a new edit 2. Uploads the AAB/APK file (with progress reporting) 3. Assigns the uploaded bundle to the specified track 4. Sets the rollout percentage (default: 100%) 5. Optionally sets release notes 6. Validates the edit 7. Commits the edit (or deletes on failure)
What gpc publish does (end-to-end):
Same as above, but also:
- Reads release notes from
--notesflag or--notes-dirdirectory - Supports multi-language notes from directory structure
- Provides a single-command UX for the most common workflow
File Requirements
| Type | Format | Max Size |
|---|---|---|
| AAB | Android App Bundle (.aab) | 150 MB |
| APK | Android Package (.apk) | 100 MB |
- AAB is strongly preferred (required for new apps since August 2021)
- Version code must be higher than any existing version on the target track
- App must be signed (Play App Signing or legacy keystore)
Resumable Uploads
GPC uses Google's resumable upload protocol for reliable transfers:
- Files >= 5 MB are uploaded in 8 MB chunks (streamed from disk, never buffered in memory)
- Files < 5 MB use simple upload (single POST, less overhead)
- Auto-resume on failure -- interrupted uploads resume from the last successful byte; session URIs valid for 1 week
- Real-time progress bar -- shows bytes uploaded, throughput, and ETA in interactive terminals
Environment Variables
| Variable | Default | Description |
|---|---|---|
GPC_UPLOAD_CHUNK_SIZE | 8388608 (8 MB) | Chunk size in bytes. Must be a multiple of 256 KB |
GPC_UPLOAD_RESUMABLE_THRESHOLD | 5242880 (5 MB) | File size threshold for switching to resumable upload |
GPC_UPLOAD_TIMEOUT | Auto (30s + 1s/MB) | Upload timeout in milliseconds |
Expansion Files (OBB)
APK expansion files (OBB) allow you to attach additional data files to an APK when the APK itself is under the size limit but your app needs extra assets. Expansion files are only supported for APK uploads (not AAB).
Types
| Type | File Name Pattern | Max Size | Description |
|---|---|---|---|
| Main | main.<versionCode>.<packageName>.obb | 2 GB | Primary expansion file, downloaded with the APK |
| Patch | patch.<versionCode>.<packageName>.obb | 2 GB | Optional secondary file for incremental updates |
Upload via GPC
# Upload main expansion file for a specific APK version code
gpc releases upload-expansion main app.obb --apk-version-code 143
# Upload patch expansion file
gpc releases upload-expansion patch patch.obb --apk-version-code 143Key Rules
- Expansion files are linked to a specific APK version code. Each APK version can have at most one main and one patch OBB.
- When you upload a new APK without new expansion files, the previous version's expansion files carry forward automatically.
- AAB (Android App Bundle) does not use expansion files. AAB handles asset delivery through Play Asset Delivery instead.
- Maximum size per expansion file is 2 GB.
- Expansion files use the
edits.expansionfiles.uploadAPI endpoint under the hood.
#!/usr/bin/env node
/**
* Detection script for GPC CLI.
* Returns JSON with installation status, version, auth state, and config.
* Used by Claude Code skill system for deterministic environment detection.
*
* Exit codes:
* 0 — GPC detected (may or may not be authenticated)
* 1 — GPC not found
*/
import { execSync } from "node:child_process";
import { existsSync } from "node:fs";
import { join } from "node:path";
function run(cmd) {
try {
return execSync(cmd, { encoding: "utf-8", timeout: 10000 }).trim();
} catch {
return null;
}
}
const result = {
installed: false,
version: null,
installMethod: null,
authStatus: null,
authMethod: null,
profile: null,
envAuth: false,
defaultApp: null,
configFile: null,
nodeVersion: process.version,
};
// Check if gpc is installed globally
const versionOutput = run("gpc --version");
if (!versionOutput) {
// Try npx
const npxVersion = run("npx gpc --version 2>/dev/null");
if (!npxVersion) {
console.log(JSON.stringify(result, null, 2));
process.exit(1);
}
result.version = npxVersion;
result.installed = true;
result.installMethod = "npx";
} else {
result.version = versionOutput;
result.installed = true;
result.installMethod = "global";
}
// Check auth status
const authOutput = run("gpc auth status --json 2>/dev/null");
if (authOutput) {
try {
const auth = JSON.parse(authOutput);
result.authStatus = auth.status || "unknown";
result.authMethod = auth.method || null;
result.profile = auth.profile || null;
} catch {
result.authStatus = "parse_error";
}
}
// Check for env-based auth
if (process.env.GPC_SERVICE_ACCOUNT) {
result.envAuth = true;
}
// Check default app
const configOutput = run("gpc config get app --json 2>/dev/null");
if (configOutput) {
try {
const config = JSON.parse(configOutput);
result.defaultApp = config.value || config.app || null;
} catch {
result.defaultApp = configOutput || null;
}
}
// Check for .gpcrc.json in current directory
const rcPath = join(process.cwd(), ".gpcrc.json");
if (existsSync(rcPath)) {
result.configFile = rcPath;
}
console.log(JSON.stringify(result, null, 2));
process.exit(0);