
Gpc Multi App
- 27 installs
- 1 repo stars
- Updated August 1, 2026
- yasserstudio/gpc-skills
Helps with ai & agent building tasks.
About
gpc-multi-app is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- gpc-multi-app
- AI & Agent Building
- AI-coding skill
Gpc Multi App by the numbers
- 27 all-time installs (skills.sh)
- Ranked #9,601 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-multi-appAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 27 |
|---|---|
| repo stars | ★ 1 |
| Last updated | August 1, 2026 |
| Repository | yasserstudio/gpc-skills ↗ |
What it does
Helps with ai & agent building tasks.
Files
gpc-multi-app
Managing multiple Google Play apps with GPC using profiles, scripting, and automation patterns.
When to use
- Managing multiple Android apps (portfolio, white-label, variants)
- Running the same GPC command across several apps
- Setting up per-app configurations and credentials
- Monorepo with multiple Android modules
- Different service accounts for different apps
Inputs required
- Authenticated GPC —
gpc auth statusmust show valid credentials - Package names — for all apps being managed
- Service account keys — may differ per app or developer account
Procedure
0. Understand app resolution
GPC resolves the target app in this order:
1. --app CLI flag (highest priority) 2. GPC_APP environment variable 3. .gpcrc.json in project directory 4. User config at ~/.config/gpc/config.json 5. Active profile override
1. Quick health check across all apps
Use gpc status --all-apps to check health across all configured apps at once:
gpc status --all-appsThis reports the status of every app defined in your profiles or config, without needing to switch profiles or pass --app for each one.
2. Per-app configuration with profiles
Set up named profiles for each app:
# Configure profiles in ~/.config/gpc/config.json{
"app": "com.example.main",
"profiles": {
"main": {
"app": "com.example.main",
"auth": { "serviceAccount": "/keys/main-sa.json" }
},
"lite": {
"app": "com.example.lite",
"auth": { "serviceAccount": "/keys/main-sa.json" }
},
"enterprise": {
"app": "com.example.enterprise",
"auth": { "serviceAccount": "/keys/enterprise-sa.json" }
}
}
}Use profiles per command:
gpc releases list --profile main
gpc releases list --profile lite
gpc releases list --profile enterpriseOr set via environment:
export GPC_PROFILE=enterprise
gpc releases list # uses enterprise profileRead: references/profile-patterns.md for advanced profile configurations.
3. Project-level .gpcrc.json
For monorepos, place .gpcrc.json in each app's directory:
monorepo/
├── apps/
│ ├── main/
│ │ ├── .gpcrc.json # { "app": "com.example.main" }
│ │ └── build.gradle
│ ├── lite/
│ │ ├── .gpcrc.json # { "app": "com.example.lite" }
│ │ └── build.gradle
│ └── enterprise/
│ ├── .gpcrc.json # { "app": "com.example.enterprise" }
│ └── build.gradle
└── .gpcrc.json # shared defaultsGPC walks up from the current directory to find .gpcrc.json, so running commands from each app's directory automatically uses the right package name.
4. Batch operations with shell scripts
Run the same command across all apps:
#!/bin/bash
# deploy-all.sh — upload to internal track for all apps
APPS=(
"com.example.main"
"com.example.lite"
"com.example.enterprise"
)
for app in "${APPS[@]}"; do
echo "Uploading $app..."
gpc releases upload "build/$app/app-release.aab" --track internal --app "$app"
done5. Batch vitals check
#!/bin/bash
# check-vitals.sh — check crash rate across all apps
APPS=("com.example.main" "com.example.lite" "com.example.enterprise")
THRESHOLD=2.0
FAILED=0
for app in "${APPS[@]}"; do
echo "Checking $app..."
if ! gpc vitals crashes --threshold "$THRESHOLD" --app "$app"; then
echo "FAIL: $app crash rate exceeds ${THRESHOLD}%"
FAILED=1
fi
done
exit $FAILED6. CI/CD for multiple apps
Read: references/ci-multi-app.md for CI platform-specific multi-app workflows.
GitHub Actions matrix strategy
name: Deploy All Apps
on:
push:
tags: ['v*']
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
app:
- { package: "com.example.main", aab: "main/app-release.aab" }
- { package: "com.example.lite", aab: "lite/app-release.aab" }
- { package: "com.example.enterprise", aab: "enterprise/app-release.aab" }
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Upload to internal
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SA_KEY }}
GPC_APP: ${{ matrix.app.package }}
run: npx @gpc-cli/cli releases upload ${{ matrix.app.aab }} --track internal7. Different service accounts per app
When apps belong to different developer accounts:
# Use different env vars per command
GPC_SERVICE_ACCOUNT=$(cat keys/main.json) gpc releases list --app com.example.main
GPC_SERVICE_ACCOUNT=$(cat keys/client.json) gpc releases list --app com.client.appOr use profiles (recommended):
{
"profiles": {
"main": {
"app": "com.example.main",
"auth": { "serviceAccount": "/keys/main-sa.json" }
},
"client": {
"app": "com.client.app",
"auth": { "serviceAccount": "/keys/client-sa.json" }
}
}
}8. Bulk metadata sync
Sync listings for all apps from a shared metadata structure:
# metadata/
# ├── com.example.main/
# │ └── en-US/
# ├── com.example.lite/
# │ └── en-US/
for dir in metadata/*/; do
app=$(basename "$dir")
echo "Syncing $app..."
gpc listings push --dir "$dir" --app "$app" --dry-run
doneVerification
gpc config list --profile <name>shows correct app and auth per profile- Commands with
--appor--profiletarget the right app - Batch scripts exit 0 when all apps succeed
- CI matrix runs deploy independently per app
.gpcrc.jsonin subdirectories correctly overrides the default app
Failure modes / debugging
| Symptom | Likely Cause | Fix |
|---|---|---|
| Wrong app targeted | --app not set, picking up default | Always pass --app or use profiles explicitly |
API_FORBIDDEN on one app | Service account lacks access for that app | Check permissions per app in Play Console |
| Batch script fails silently | Missing error handling in loop | Use set -e or check $? after each command |
| Profile not found | Typo in profile name | Check gpc config list for available profiles |
| CI matrix job fails one app | Independent failure | Matrix jobs run independently — check logs per app |
.gpcrc.json not picked up | Running from wrong directory | GPC walks up from cwd; ensure you're in the right dir |
Related skills
- gpc-setup — initial auth and profiles configuration
- gpc-ci-integration — CI pipeline setup for single apps
- gpc-sdk-usage — programmatic multi-app management with the TypeScript SDK
- gpc-user-management — managing per-app permissions for team members
{
"skill_name": "gpc-multi-app",
"evals": [
{
"id": 1,
"prompt": "We have 3 white-label Android apps that share the same codebase but have different package names (com.brand-a.app, com.brand-b.app, com.brand-c.app). They all use the same developer account. How do I set up GPC to deploy all 3 efficiently?",
"expected_output": "Shows profile configuration for 3 apps and batch deployment patterns",
"files": [],
"expectations": [
"Sets up named profiles in config.json for each brand",
"Shows --profile flag for per-command app targeting",
"Provides a batch shell script to deploy all 3 apps",
"Mentions GitHub Actions matrix strategy as a CI option",
"Notes that same service account works if all apps are under one developer account"
]
},
{
"id": 2,
"prompt": "We have a monorepo with 2 Android apps in apps/main/ and apps/lite/. Each has its own build output. How should I structure the GPC config so commands automatically target the right app depending on which directory I'm in?",
"expected_output": "Shows per-directory .gpcrc.json pattern for monorepos",
"files": [],
"expectations": [
"Creates .gpcrc.json in each app's directory with the correct package name",
"Explains that GPC walks up from cwd to find .gpcrc.json",
"Shows running gpc commands from each app's directory",
"Mentions that a root .gpcrc.json can hold shared config",
"No need for --app flag when .gpcrc.json is correctly placed"
]
},
{
"id": 3,
"prompt": "I manage apps for 2 different clients, each with their own Google Play developer account and service account key. I need to switch between them frequently. What's the cleanest setup?",
"expected_output": "Shows profile-based setup with different auth per client",
"files": [],
"expectations": [
"Creates profiles with different auth.serviceAccount paths per client",
"Includes developerId in profiles for user management commands",
"Shows GPC_PROFILE env var for session-level switching",
"Shows --profile flag for per-command switching",
"Mentions that different developer accounts need separate service accounts"
]
}
]
}
CI/CD for Multiple Apps
Platform-specific patterns for deploying multiple apps in CI.
GitHub Actions — Matrix strategy
name: Deploy All Apps
on:
push:
tags: ['v*']
jobs:
deploy:
runs-on: ubuntu-latest
strategy:
matrix:
include:
- app: com.example.main
aab: main/app-release.aab
- app: com.example.lite
aab: lite/app-release.aab
- app: com.example.pro
aab: pro/app-release.aab
fail-fast: false # Don't cancel other apps if one fails
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- name: Upload to beta
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SA_KEY }}
GPC_APP: ${{ matrix.app }}
run: npx @gpc-cli/cli releases upload ${{ matrix.aab }} --track betaGitHub Actions — Different service accounts
jobs:
deploy:
strategy:
matrix:
include:
- app: com.ourcompany.app
secret: PLAY_SA_KEY_MAIN
- app: com.client.app
secret: PLAY_SA_KEY_CLIENT
steps:
- name: Upload
env:
GPC_SERVICE_ACCOUNT: ${{ secrets[matrix.secret] }}
GPC_APP: ${{ matrix.app }}
run: npx @gpc-cli/cli releases upload app.aab --track betaGitLab CI — Parallel jobs
.deploy-template:
image: node:20
stage: deploy
only: [tags]
script:
- npx @gpc-cli/cli releases upload ${AAB_PATH} --track beta
deploy-main:
extends: .deploy-template
variables:
GPC_APP: com.example.main
AAB_PATH: main/app-release.aab
deploy-lite:
extends: .deploy-template
variables:
GPC_APP: com.example.lite
AAB_PATH: lite/app-release.aabBatch vitals check in CI
# GitHub Actions
- name: Check vitals for all apps
env:
GPC_SERVICE_ACCOUNT: ${{ secrets.PLAY_SA_KEY }}
run: |
FAILED=0
for app in com.example.main com.example.lite com.example.pro; do
echo "Checking $app..."
if ! npx @gpc-cli/cli vitals crashes --threshold 2.0 --app "$app"; then
echo "::warning::$app crash rate exceeds threshold"
FAILED=1
fi
done
exit $FAILEDSequential deployment with promotion gates
jobs:
deploy-internal:
strategy:
matrix:
app: [com.example.main, com.example.lite]
steps:
- name: Upload to internal
env:
GPC_APP: ${{ matrix.app }}
run: npx @gpc-cli/cli releases upload app.aab --track internal
promote-beta:
needs: deploy-internal
strategy:
matrix:
app: [com.example.main, com.example.lite]
steps:
- name: Promote to beta
env:
GPC_APP: ${{ matrix.app }}
run: npx @gpc-cli/cli releases promote --from internal --to betaMulti-App Profile Patterns
Configuration patterns for managing multiple apps with GPC profiles.
Basic profile setup
~/.config/gpc/config.json:
{
"app": "com.example.main",
"profiles": {
"main": {
"app": "com.example.main"
},
"lite": {
"app": "com.example.lite"
}
}
}gpc releases list --profile main
gpc releases list --profile liteDifferent service accounts per profile
When apps belong to different developer accounts:
{
"profiles": {
"our-app": {
"app": "com.ourcompany.app",
"auth": { "serviceAccount": "/keys/our-sa.json" }
},
"client-a": {
"app": "com.client-a.app",
"auth": { "serviceAccount": "/keys/client-a-sa.json" },
"developerId": "1111111111"
},
"client-b": {
"app": "com.client-b.app",
"auth": { "serviceAccount": "/keys/client-b-sa.json" },
"developerId": "2222222222"
}
}
}Environment-based profiles
{
"profiles": {
"dev": {
"app": "com.example.app.dev",
"auth": { "serviceAccount": "/keys/dev-sa.json" }
},
"staging": {
"app": "com.example.app.staging",
"auth": { "serviceAccount": "/keys/staging-sa.json" }
},
"production": {
"app": "com.example.app",
"auth": { "serviceAccount": "/keys/prod-sa.json" }
}
}
}# Deploy to each environment
gpc releases upload app.aab --track internal --profile dev
gpc releases upload app.aab --track beta --profile staging
gpc releases upload app.aab --track production --profile productionWhite-label apps
{
"profiles": {
"brand-a": {
"app": "com.brand-a.app",
"auth": { "serviceAccount": "/keys/main-sa.json" }
},
"brand-b": {
"app": "com.brand-b.app",
"auth": { "serviceAccount": "/keys/main-sa.json" }
},
"brand-c": {
"app": "com.brand-c.app",
"auth": { "serviceAccount": "/keys/main-sa.json" }
}
}
}Same service account if all apps are under one developer account.
Profile via environment variable
export GPC_PROFILE=production
gpc releases list # uses production profile
# Override per command
gpc releases list --profile stagingMonorepo pattern
Instead of profiles, use .gpcrc.json per app directory:
monorepo/
├── apps/main/.gpcrc.json → { "app": "com.example.main" }
├── apps/lite/.gpcrc.json → { "app": "com.example.lite" }
└── .gpcrc.json → shared config (no app set)cd apps/main && gpc releases list # uses com.example.main
cd apps/lite && gpc releases list # uses com.example.liteCombining profiles with CI
# GitHub Actions — deploy all white-label apps
jobs:
deploy:
strategy:
matrix:
profile: [brand-a, brand-b, brand-c]
steps:
- name: Deploy
run: npx @gpc-cli/cli releases upload app-${{ matrix.profile }}.aab --track beta --profile ${{ matrix.profile }}#!/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);