Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure Adobe OAuth credentials and API access across development, staging, and production environments with separate Developer Console projects, secret managers, and environment-specific scoping. Trigger with phrases like "adobe environments", "adobe staging", "adobe dev prod", "adobe environment setup", "adobe config by env".
.claude/skills/jeremylongshore-adobe-multi-env-setup/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | 47% | 0% |
| case-07 | ✗→✓ | ▲ Improved | 58% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 66% | 0% |
| case-10 | ✗→✓ | ▲ Improved | 25% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 55% | 0% |
Configure Adobe APIs across development, staging, and production environments using separate Developer Console projects, environment-specific OAuth credentials, and cloud-native secret management.
Adobe best practice: one Developer Console project per environment with separate OAuth credentials.
| Environment | Console Project | Scopes | Product Profile | |-------------|----------------|--------|-----------------| | Development | my-app-dev | openid,AdobeID | Dev sandbox | | Staging | my-app-staging | openid,AdobeID,firefly_api | Staging profile | | Production | my-app-prod | openid,AdobeID,firefly_api,ff_apis | Production profile |
typescript// src/config/adobe.ts interface AdobeEnvConfig { imsEndpoint: string; // Same across all envs fireflyEndpoint: string; // Same across all envs photoshopEndpoint: string; // Same across all envs scopes: string; // Different per env (least privilege) retries: number; timeoutMs: number; cache: { enabled: boolean; ttlMs: number }; } const configs: Record<string, AdobeEnvConfig> = { development: { imsEndpoint: 'https://ims-na1.adobelogin.com', fireflyEndpoint: 'https://firefly-api.adobe.io', photoshopEndpoint: 'https://image.adobe.io', scopes: 'openid,AdobeID', // Minimal scopes for dev retries: 1, // Fast failure in dev timeoutMs: 15_000, cache: { enabled: false, ttlMs: 0 }, // No cache in dev }, staging: { imsEndpoint: 'https://ims-na1.adobelogin.com', fireflyEndpoint: 'https://firefly-api.adobe.io', photoshopEndpoint: 'https://image.adobe.io', scopes: 'openid,AdobeID,firefly_api', retries: 3, timeoutMs: 30_000, cache: { enabled: true, ttlMs: 60_000 }, }, production: { imsEndpoint: 'https://ims-na1.adobelogin.com', fireflyEndpoint: 'https://firefly-api.adobe.io', photoshopEndpoint: 'https://image.adobe.io', scopes: 'openid,AdobeID,firefly_api,ff_apis', retries: 5, timeoutMs: 60_000, cache: { enabled: true, ttlMs: 300_000 }, }, }; export function getAdobeConfig(): AdobeEnvConfig & { clientId: string; clientSecret: string } { const env = process.env.NODE_ENV || 'development'; const config = configs[env] || configs.development; return { ...config, clientId: process.env.ADOBE_CLIENT_ID!, clientSecret: process.env.ADOBE_CLIENT_SECRET!, }; }
bash# --- Local Development --- # .env.local (git-ignored) ADOBE_CLIENT_ID=dev-client-id-from-console ADOBE_CLIENT_SECRET=p8_dev_secret ADOBE_SCOPES=openid,AdobeID # --- GCP Secret Manager --- # Create secrets for staging and production gcloud secrets create adobe-client-id-staging --data-file=- <<< "staging-client-id" gcloud secrets create adobe-client-secret-staging --data-file=- <<< "p8_staging_secret" gcloud secrets create adobe-client-id-prod --data-file=- <<< "prod-client-id" gcloud secrets create adobe-client-secret-prod --data-file=- <<< "p8_prod_secret" # Grant service account access gcloud secrets add-iam-policy-binding adobe-client-secret-prod \ --member="serviceAccount:my-app@project.iam.gserviceaccount.com" \ --role="roles/secretmanager.secretAccessor" # --- AWS Secrets Manager --- aws secretsmanager create-secret \ --name adobe/staging/credentials \ --secret-string '{"client_id":"...","client_secret":"p8_staging_..."}' aws secretsmanager create-secret \ --name adobe/production/credentials \ --secret-string '{"client_id":"...","client_secret":"p8_prod_..."}' # --- HashiCorp Vault --- vault kv put secret/adobe/staging client_id="..." client_secret="p8_staging_..." vault kv put secret/adobe/production client_id="..." client_secret="p8_prod_..."
yaml# .github/workflows/deploy.yml jobs: deploy: strategy: matrix: environment: [staging, production] environment: ${{ matrix.environment }} runs-on: ubuntu-latest env: NODE_ENV: ${{ matrix.environment }} ADOBE_CLIENT_ID: ${{ secrets[format('ADOBE_CLIENT_ID_{0}', matrix.environment)] }} ADOBE_CLIENT_SECRET: ${{ secrets[format('ADOBE_CLIENT_SECRET_{0}', matrix.environment)] }} steps: - uses: actions/checkout@v4 - run: npm ci && npm test - name: Verify Adobe credentials for ${{ matrix.environment }} run: | HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ 'https://ims-na1.adobelogin.com/ims/token/v3' \ -d "client_id=${ADOBE_CLIENT_ID}&client_secret=${ADOBE_CLIENT_SECRET}&grant_type=client_credentials&scope=openid,AdobeID") if [ "$HTTP_CODE" != "200" ]; then echo "::error::Adobe credential validation failed for ${{ matrix.environment }}" exit 1 fi - run: npm run deploy:${{ matrix.environment }}
typescript// Prevent accidental production operations in non-prod function requireEnvironment(required: string): void { const current = process.env.NODE_ENV || 'development'; if (current !== required) { throw new Error( `Operation requires ${required} environment, currently running in ${current}` ); } } // Usage: guard dangerous operations async function deleteAllCachedAssets() { requireEnvironment('production'); // ... actual deletion logic }
| Issue | Cause | Solution | |-------|-------|----------| | invalid_scope in staging | Scope not in staging project | Add API to staging Console project | | Wrong credentials deployed | Environment mismatch | Verify NODE_ENV matches secret path | | Secret access denied | Missing IAM binding | Grant secretAccessor role | | Config merge fails | Missing env config file | Ensure all environments defined |
Start with the smallest applicable command or code example already provided in this guide, using a non-production Adobe environment and credentials. Confirm the documented response or validation result before applying the pattern to production.
For observability setup, see adobe-observability.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 43,672 | 39,308 | -10% | 1 | 1 | 0% | 2,569 | 3,749 | +46% | 0 | 0 | — |
case-02 | pass→pass | 13,477 | 11,771 | -13% | 1 | 1 | 0% | 2,022 | 3,997 | +98% | 0 | 0 | — |
case-03 | fail→fail | 47,068 | 44,321 | -6% | 1 | 1 | 0% | 2,610 | 3,850 | +48% | 0 | 0 | — |
case-04 | fail→pass | 30,561 | 5,716 | -81% | 1 | 1 | 0% | 2,029 | 2,980 | +47% | 0 | 0 | — |
case-05 | fail→fail | 13,067 | 13,626 | +4% | 1 | 1 | 0% | 2,026 | 3,957 | +95% | 0 | 0 | — |
case-06 | pass→pass | 6,862 | 3,168 | -54% | 1 | 1 | 0% | 1,170 | 2,440 | +109% | 0 | 0 | — |
case-07 | fail→pass | 10,916 | 5,547 | -49% | 1 | 1 | 0% | 1,812 | 2,862 | +58% | 0 | 0 | — |
case-08 | fail→pass | 17,148 | 11,351 | -34% | 1 | 1 | 0% | 2,474 | 4,103 | +66% | 0 | 0 | — |
case-09 | pass→pass | 11,308 | 3,747 | -67% | 1 | 1 | 0% | 1,907 | 2,686 | +41% | 0 | 0 | — |
case-10 | fail→pass | 15,826 | 7,986 | -50% | 1 | 1 | 0% | 2,717 | 3,384 | +25% | 0 | 0 | — |
case-11 | pass→pass | 11,424 | 8,777 | -23% | 1 | 1 | 0% | 1,830 | 3,132 | +71% | 0 | 0 | — |
case-12 | fail→fail | 14,970 | 15,092 | +1% | 1 | 1 | 0% | 2,325 | 4,543 | +95% | 0 | 0 | — |
case-13 | pass→pass | 10,925 | 7,865 | -28% | 1 | 1 | 0% | 2,035 | 3,377 | +66% | 0 | 0 | — |
case-14 | pass→pass | 16,264 | 4,639 | -71% | 1 | 1 | 0% | 2,455 | 2,748 | +12% | 0 | 0 | — |
case-15 | fail→pass | 17,371 | 6,440 | -63% | 1 | 1 | 0% | 2,020 | 3,133 | +55% | 0 | 0 | — |
case-16 | pass→pass | 9,026 | 2,551 | -72% | 1 | 1 | 0% | 1,614 | 2,481 | +54% | 0 | 0 | — |
case-17 | pass→pass | 13,558 | 22,019 | +62% | 1 | 1 | 0% | 2,540 | 4,284 | +69% | 0 | 0 | — |
case-18 | fail→pass | 13,802 | 11,760 | -15% | 1 | 1 | 0% | 3,075 | 4,728 | +54% | 0 | 0 | — |
case-19 | fail→fail | 23,002 | 12,758 | -45% | 1 | 1 | 0% | 4,856 | 4,917 | +1% | 0 | 0 | — |
case-20 | fail→fail | 37,555 | 22,356 | -40% | 1 | 1 | 0% | 6,778 | 6,468 | -5% | 0 | 0 | — |
case-21 | pass→pass | 18,223 | 12,851 | -29% | 1 | 1 | 0% | 3,146 | 4,572 | +45% | 0 | 0 | — |
case-22 | pass→pass | 15,656 | 17,245 | +10% | 1 | 1 | 0% | 3,023 | 5,107 | +69% | 0 | 0 | — |
case-23 | pass→pass | 13,697 | 11,940 | -13% | 1 | 1 | 0% | 2,515 | 4,463 | +77% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +26 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.6-flash | verified | 8/13/2026 | +30% |
Other measured skills in the registry, with their headline benchmark lift.