Use when migrating a project from the legacy ForgeRock SDK (FRAuth, FRSession, forgerock-ios-sdk, forgerock-android-sdk, @forgerock/javascript-sdk) to the new Ping Identity Journey SDK. Trigger whenever the user mentions migrating, upgrading, porting, or converting ForgeRock code to the Ping SDK — phrases like "ForgeRock to Ping migration", "upgrade FRAuth", "replace FRSession", "move off @forgerock/javascript-sdk", "migrate to @forgerock/journey-client", "upgrade to Ping Journey SDK", or even a vaguer "help me modernize our ForgeRock auth". Works on Android (Kotlin), iOS (Swift), and JavaScript/TypeScript codebases. Preserves old code as comments so rollback is trivial, verifies the app still builds, and writes a line-numbered report of every change.
How this skill is triggered — by the user, by Claude, or both
Slash command
/ping-orchestration-sdks:forgerock-to-ping-journey-migrationThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Help a developer move an existing app off the legacy ForgeRock SDK and onto the new Ping Identity Journey SDK. This skill drives a careful, auditable migration: scan the codebase, preview the plan, comment-out-and-replace (never silent delete), verify the build, and leave behind a report the developer can hand to a reviewer.
Help a developer move an existing app off the legacy ForgeRock SDK and onto the new Ping Identity Journey SDK. This skill drives a careful, auditable migration: scan the codebase, preview the plan, comment-out-and-replace (never silent delete), verify the build, and leave behind a report the developer can hand to a reviewer.
| Platform | Legacy package | New package | Reference |
|---|---|---|---|
| Android (Kotlin) | org.forgerock:forgerock-auth (FRAuth/FRSession) | com.pingidentity.sdks:journey | android-migration.md |
| iOS (Swift) | ForgeRock/forgerock-ios-sdk (FRAuth/FRUser) | ForgeRock/ping-ios-sdk (PingJourney/PingOidc) | ios-migration.md |
| JavaScript/TypeScript | @forgerock/javascript-sdk | @forgerock/journey-client + @forgerock/oidc-client | javascript-migration.md |
Each reference file is a complete before/after mapping (imports, classes, methods, parameter changes). Load only the file(s) that match the detected platform(s) — do not pre-read all three.
Fire this skill whenever the user indicates they want to port ForgeRock auth code to the Ping SDK, even without using the word "migrate". Examples of triggering phrases: "we need to move off FRAuth", "convert this to journey-client", "what would it take to upgrade our ForgeRock integration", "replace FRSession.authenticate with the new SDK". When in doubt, offer — being slightly pushy here is correct because the user already has legacy code on disk that will break when ForgeRock is sunset.
Read these before starting. They guide every judgment call below.
TODO(ping-migration): and ask the developer before proceeding.Execute these phases in order. Skip none silently — if the developer wants to skip a phase, they must say so.
Identify which platform(s) the target project uses. Look for:
build.gradle, build.gradle.kts, settings.gradle*, gradle.properties, app/src/main/AndroidManifest.xmlPackage.swift, *.xcodeproj, *.xcworkspace, Podfile, Podfile.lockpackage.json (check dependencies for @forgerock/javascript-sdk or @forgerock/ping-protect)A monorepo may contain more than one. If so, confirm with the developer which target(s) they want to migrate in this session before proceeding.
Read AGENTS.md and CLAUDE.md at the project root (and any subproject roots relevant to the platform). These files commonly hold entry-point info, auth module location, custom build commands, and preferred conventions — all critical for a safe migration.
If neither file exists, offer to create AGENTS.md using agents-template.md as a starting point. Fill it in from what you can observe: project structure, primary language, build command, location of existing auth code. Ask the developer to confirm or correct before saving. The file benefits this migration and future work, which is why it is worth the small detour.
If the developer declines, proceed without it but note this in the final report.
Before changing anything, confirm the app builds in its current state. Ask the developer:
"Want me to run the build now to confirm a clean baseline, or do you already know it builds?"
If they say yes, or are unsure, run the appropriate command (see Build commands below). If the build fails, stop here. Help fix the pre-existing failure first — you cannot migrate safely on top of a broken baseline. Resume when the build is green.
If the developer says "just trust me, it builds", accept and continue, but record this in the report so they know they opted out of the baseline check.
Ask the developer:
"Do you want me to scan the whole project, or migrate a specific area (e.g. a single file, a feature module, the login flow)?"
Honor partial scope. Partial scope is common and legitimate — a team may want to migrate incrementally, module by module. If partial, confirm the exact set of files/directories before scanning.
Using Grep and Read, build an inventory of legacy SDK usage in the chosen scope. The reference files list every legacy symbol you should search for. Key anchors to grep:
FRSession, FRUser, FRAuth, NodeListener, FROptions, FRDeviceCollector, import org.forgerock.android, WebAuthRegistrationCallback, DeviceBindingCallback, FRListener, PingOneProtect*FRAuth, FRSession, FRUser, FROptions, import FRAuth, import FRCore, WebAuthnRegistrationCallback, WebAuthnAuthenticationCallback, SelectIdPCallback, FRGoogleSignIn, FRFacebookSignIn, FRCaptchaEnterprise, Node.next { ... } completion-handler style@forgerock/javascript-sdk, Config.set, FRAuth.start, FRAuth.next, FRUser.logout, UserManager.getCurrentUser, TokenManager.getTokens, TokenStorage, FRWebAuthn, CallbackType, FRCallback, FRStep, @forgerock/ping-protectAlso inventory:
build.gradle*, Package.swift, Podfile, package.json — to know which declarations will need updating.AndroidManifest.xml redirect URIs, iOS Info.plist URL schemes, JS index.html — in case the new SDK requires different entries.Present the findings to the developer before editing. Structure:
## Migration plan (preview)
Platform(s): Android
Scope: app/src/main/java/com/example/auth/**
Dependency changes (1 file):
- app/build.gradle.kts — remove org.forgerock:forgerock-auth, add com.pingidentity.sdks:journey
Code changes (4 files, 12 sites):
- app/src/main/java/com/example/auth/AuthManager.kt — 5 sites
line 23: FROptionsBuilder.build { ... } → Journey { ... }
line 41: FRSession.authenticate → journey.start
line 56: NodeListener<FRSession> → Node sealed-class handling
line 78: NameCallback setter → property assignment
line 102: FRUser.getCurrentUser()?.logout() → journey.user()?.logout()
- app/src/main/java/com/example/auth/LoginViewModel.kt — 4 sites
...
Manual review items (2):
- app/src/main/java/com/example/auth/DeviceHelper.kt:87 — uses custom FRDeviceCollector
composition; the new API uses DefaultDeviceCollector. I'll add a TODO but
want your input on whether the custom collectors are still needed.
- app/src/main/AndroidManifest.xml:34 — redirect URI scheme matches legacy
sample; confirm it still applies to your new OIDC client.
Proceed? (y / partial / no)
Let the developer edit the plan — they may want to skip a file, defer an item, or adjust the scope. Do not start Phase 7 until they approve.
For each site, comment out the legacy code and insert the new code directly below. Use this marker convention so a single grep locates every change:
Android / iOS (Kotlin/Swift line comments):
// [ping-migration] BEGIN legacy — safe to delete after verifying the migration
// FRSession.authenticate(context, "Login", nodeListener)
// [ping-migration] END legacy
val node: Node = journey.start("Login")
JavaScript/TypeScript (line comments):
// [ping-migration] BEGIN legacy — safe to delete after verifying the migration
// const step = await FRAuth.start();
// [ping-migration] END legacy
const result = await journeyClient.start({ journey: 'Login' });
Why begin/end markers on both sides? A single-line comment is easy to miss in a diff; the paired markers make the boundary unambiguous and let the developer remove the block with a single multi-line selection later.
Dependency files. Before editing, check whether the new dependency is already declared (developer may have started the migration). If yes, skip that entry and note it in the report. When modifying, comment out the legacy line with the same marker convention and add the new declaration below. For package.json, where JSON does not support comments, update dependencies in place but list both the removed and added packages in the report's "Dependencies" section.
Ambiguous transforms. When the mapping requires a judgment call — e.g., a legacy callback-based flow that needs to become a coroutine/async block in a different part of the file, or behavioral changes like NodeListener.onException splitting into ErrorNode/FailureNode — do not guess. Insert a TODO(ping-migration): comment explaining the ambiguity and ask the developer in chat before making the change:
// TODO(ping-migration): onException previously handled both API errors and
// unexpected exceptions. The new SDK splits these into ErrorNode (API errors,
// has .message) and FailureNode (exceptions, has .cause). Do you want to
// preserve a single error path, or branch on node type for different UX?
Work one file at a time so failures are isolated and the report stays coherent.
Ask the developer:
"Ready to run the build to verify? (This can take a few minutes.)"
If yes, run the appropriate build command. If the build passes, proceed to Phase 9.
If it fails:
If the developer declines to run the build, write the report with a clear banner at the top: ⚠️ Build verification was skipped — migration is not yet confirmed to compile.
Write MIGRATION_REPORT.md at the project root (or at the root of the migrated subproject, if partial). Use report-template.md as the structure. The report must include:
TODO(ping-migration): left behind, with file:line pointers.grep -R "\[ping-migration\] BEGIN legacy" and remove the commented blocks.The report should be readable standalone — a reviewer who was not in the session should understand what changed and why.
Use the project's standard build command. If AGENTS.md specifies one, prefer that. Otherwise:
| Platform | Command (adjust to project layout) |
|---|---|
| Android | ./gradlew assembleDebug (or ./gradlew :app:assembleDebug) |
| iOS (SPM) | xcodebuild -scheme <scheme> -destination 'generic/platform=iOS Simulator' build |
| iOS (CocoaPods) | pod install then xcodebuild -workspace <name>.xcworkspace -scheme <scheme> build |
| JavaScript | Detect via package.json — npm run build, pnpm build, or yarn build depending on lockfile |
Always confirm the exact command with the developer if the project deviates. For iOS, the scheme and destination vary per project; ask before the first build.
These transformations cannot be safely automated. Always flag them in the report:
FRListener implementations and fake FRStep objects do not translate mechanically — they need rewriting against the new type system.FRGoogleSignIn, FRFacebookSignIn, etc. are replaced with separate PingExternalIdP* modules; the app-level configuration (Google Client ID, Facebook App ID) may need fresh setup in Ping.WebAuthRegistrationCallback → FidoRegistrationCallback; DeviceBindingCallback.bind(...) signature is different). Always show the developer the diff before applying.AGENTS.md when the project lacks one.MIGRATION_REPORT.md.Load only the reference(s) relevant to the detected platform(s). The migration mappings are long — do not preload all of them.
npx claudepluginhub pingidentity/ping-sdk-agent-skills --plugin ping-orchestration-sdksCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.