Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Analyze, plan, and execute Adobe SDK upgrades — including the critical JWT-to-OAuth migration, PDF Services SDK v3-to-v4, and Photoshop API endpoint changes (cutout v1 to remove-background v2). Trigger with phrases like "upgrade adobe", "adobe migration", "adobe breaking changes", "update adobe SDK", "jwt to oauth".
.claude/skills/jeremylongshore-adobe-upgrade-migration/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 218% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 46% | 0% |
| case-05 | ✗→✓ | ▲ Improved | -72% | 0% |
| case-08 | ✗→✓ | ▲ Improved | -19% | 0% |
| case-12 | ✗→✓ | ▲ Improved | 24% | 0% |
Guide for the most critical Adobe migrations: JWT to OAuth Server-to-Server, PDF Services SDK v3 to v4, Photoshop API v1 to v2 endpoints, and general SDK version upgrades.
Deadline passed: JWT (Service Account) credentials reached EOL June 2025. If you are still using JWT, migrate immediately.
typescript// BEFORE (JWT — no longer works) import jwt from 'jsonwebtoken'; const jwtToken = jwt.sign({ exp: Math.round(Date.now() / 1000) + 60 * 60 * 24, iss: orgId, sub: technicalAccountId, aud: `https://ims-na1.adobelogin.com/c/${clientId}`, 'https://ims-na1.adobelogin.com/s/ent_firefly_sdk': true, }, privateKey, { algorithm: 'RS256' }); // AFTER (OAuth Server-to-Server — current standard) const tokenResponse = await fetch('https://ims-na1.adobelogin.com/ims/token/v3', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ client_id: process.env.ADOBE_CLIENT_ID!, client_secret: process.env.ADOBE_CLIENT_SECRET!, grant_type: 'client_credentials', scope: process.env.ADOBE_SCOPES!, }), });
Migration steps:
client_credentials grantjsonwebtoken dependency and private key filesbash# Check current version npm list @adobe/pdfservices-node-sdk # Upgrade npm install @adobe/pdfservices-node-sdk@latest
Key breaking changes v3 -> v4:
typescript// BEFORE (v3) import PDFServicesSdk from '@adobe/pdfservices-node-sdk'; const credentials = PDFServicesSdk.Credentials .serviceAccountCredentialsBuilder() .fromFile('pdfservices-api-credentials.json') .build(); const executionContext = PDFServicesSdk.ExecutionContext.create(credentials); const extractPDFOperation = PDFServicesSdk.ExtractPDF.Operation.createNew(); // AFTER (v4) import { ServicePrincipalCredentials, PDFServices, ExtractPDFJob, ExtractPDFParams, ExtractElementType, } from '@adobe/pdfservices-node-sdk'; const credentials = new ServicePrincipalCredentials({ clientId: process.env.ADOBE_CLIENT_ID!, clientSecret: process.env.ADOBE_CLIENT_SECRET!, }); const pdfServices = new PDFServices({ credentials }); // Job-based API: submit job, poll for result const job = new ExtractPDFJob({ inputAsset, params }); const pollingURL = await pdfServices.submit({ job });
typescript// BEFORE (v1 — deprecated) const response = await fetch('https://image.adobe.io/sensei/cutout', { method: 'POST', // ... }); // AFTER (v2 — current) const response = await fetch('https://image.adobe.io/v2/remove-background', { method: 'POST', headers: { 'Authorization': `Bearer ${token}`, 'x-api-key': process.env.ADOBE_CLIENT_ID!, 'Content-Type': 'application/json', }, body: JSON.stringify({ input: { href: inputUrl, storage: 'external' }, output: { href: outputUrl, storage: 'external', type: 'image/png' }, }), });
bash# 1. Create upgrade branch git checkout -b upgrade/adobe-sdk # 2. Check for outdated packages npm outdated | grep @adobe # 3. Upgrade all Adobe packages npm install @adobe/pdfservices-node-sdk@latest \ @adobe/firefly-apis@latest \ @adobe/photoshop-apis@latest \ @adobe/lightroom-apis@latest # 4. Run tests npm test # 5. Fix any breaking changes (check changelogs) # Firefly: # PDF Services: # 6. Commit and test in staging git add package.json package-lock.json git commit -m "chore: upgrade Adobe SDKs to latest"
| Error After Upgrade | Cause | Solution | |---------------------|-------|----------| | invalid_client | Still using JWT credentials | Complete OAuth migration | | ExecutionContext is not a constructor | v3 API in v4 SDK | Use new Job-based API | | 404 /sensei/cutout | Old Photoshop endpoint | Update to /v2/remove-background | | Cannot find module | Import paths changed | Check SDK changelog for new imports |
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 CI integration during upgrades, see adobe-ci-integration.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | fail→pass | 33,939 | 46,064 | +36% | 1 | 1 | 0% | 1,440 | 4,584 | +218% | 0 | 0 | — |
case-02 | fail→pass | 10,954 | 7,077 | -35% | 1 | 1 | 0% | 2,080 | 3,028 | +46% | 0 | 0 | — |
case-03 | pass→pass | 14,352 | 6,624 | -54% | 1 | 1 | 0% | 2,617 | 2,933 | +12% | 0 | 0 | — |
case-04 | pass→pass | 15,212 | 10,570 | -31% | 1 | 1 | 0% | 2,678 | 3,666 | +37% | 0 | 0 | — |
case-05 | fail→pass | 52,687 | 3,944 | -93% | 1 | 1 | 0% | 8,237 | 2,268 | -72% | 0 | 0 | — |
case-06 | pass→pass | 5,563 | 2,553 | -54% | 1 | 1 | 0% | 1,045 | 1,970 | +89% | 0 | 0 | — |
case-07 | pass→pass | 7,798 | 2,513 | -68% | 1 | 1 | 0% | 1,236 | 1,879 | +52% | 0 | 0 | — |
case-08 | fail→pass | 13,951 | 2,586 | -81% | 1 | 1 | 0% | 2,419 | 1,967 | -19% | 0 | 0 | — |
case-09 | pass→pass | 11,661 | 6,332 | -46% | 1 | 1 | 0% | 2,406 | 2,763 | +15% | 0 | 0 | — |
case-10 | pass→pass | 9,621 | 2,387 | -75% | 1 | 1 | 0% | 1,616 | 1,848 | +14% | 0 | 0 | — |
case-11 | pass→pass | 9,955 | 3,619 | -64% | 1 | 1 | 0% | 1,844 | 2,214 | +20% | 0 | 0 | — |
case-12 | fail→pass | 12,973 | 6,655 | -49% | 1 | 1 | 0% | 2,183 | 2,698 | +24% | 0 | 0 | — |
case-13 | pass→pass | 33,000 | 2,418 | -93% | 1 | 1 | 0% | 550 | 1,901 | +246% | 0 | 0 | — |
case-14 | pass→pass | 10,878 | 4,870 | -55% | 1 | 1 | 0% | 1,850 | 2,386 | +29% | 0 | 0 | — |
case-15 | pass→pass | 7,416 | 2,201 | -70% | 1 | 1 | 0% | 962 | 1,854 | +93% | 0 | 0 | — |
case-16 | fail→pass | 17,102 | 4,440 | -74% | 1 | 1 | 0% | 2,733 | 2,216 | -19% | 0 | 0 | — |
case-17 | fail→pass | 12,465 | 5,567 | -55% | 1 | 1 | 0% | 2,053 | 2,604 | +27% | 0 | 0 | — |
case-18 | pass→pass | 10,431 | 5,321 | -49% | 1 | 1 | 0% | 1,769 | 2,434 | +38% | 0 | 0 | — |
case-19 | pass→pass | 6,374 | 5,249 | -18% | 1 | 1 | 0% | 1,112 | 2,508 | +126% | 0 | 0 | — |
case-20 | fail→fail | 14,658 | 13,425 | -8% | 1 | 1 | 0% | 2,879 | 4,175 | +45% | 0 | 0 | — |
case-21 | fail→fail | 14,971 | 13,159 | -12% | 1 | 1 | 0% | 2,978 | 4,162 | +40% | 0 | 0 | — |
case-22 | fail→fail | 17,095 | 12,762 | -25% | 1 | 1 | 0% | 3,472 | 4,148 | +19% | 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. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +32 percentage points is the difference between those two pass rates over the 21 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 | +18% |
Other measured skills in the registry, with their headline benchmark lift.