Help us improve
Share bugs, ideas, or general feedback.
From agentforce-mobile-sdk-android
Walks through integrating Agentforce Mobile SDK into an Android app: discovers use case, selects auth flow, adds Maven dependencies, and scaffolds Kotlin files including Compose chat host. Use when adding Agentforce chat.
npx claudepluginhub salesforce/agentforcemobilesdk-android --plugin agentforce-mobile-sdk-androidHow this skill is triggered — by the user, by Claude, or both
Slash command
/agentforce-mobile-sdk-android:integrate-agentforce-androidThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill walks a consumer through wiring the **Agentforce Mobile SDK** into their Android app. It is **interactive** — ask the user the questions in each phase before generating code. Don't assume; the wrong auth flow is the most common integration mistake.
references/auth-flows.mdreferences/chat-presentation.mdreferences/client-setup.mdreferences/dep-detection.mdreferences/logger-setup.mdreferences/snippets/AgentforceHolder.ktreferences/snippets/AppAgentforceUIDelegate.ktreferences/snippets/AppCredentialProvider+Guest.ktreferences/snippets/AppCredentialProvider+OAuth.ktreferences/snippets/AppCredentialProvider+OrgJWT.ktreferences/snippets/AppLogger.ktreferences/snippets/AppNavigation.ktreferences/snippets/AppNetwork.ktreferences/snippets/ChatHost+BottomSheet.ktreferences/snippets/ChatHost+Dialog.ktreferences/snippets/ChatHost+EmbeddedPanel.ktreferences/snippets/ChatHost+FullScreenActivity.ktGuides deployment workflows with CI/CD patterns, rolling/blue-green/canary strategies, multi-stage Dockerfiles for Node.js, health checks, rollbacks, and production checklists for web apps.
Share bugs, ideas, or general feedback.
This skill walks a consumer through wiring the Agentforce Mobile SDK into their Android app. It is interactive — ask the user the questions in each phase before generating code. Don't assume; the wrong auth flow is the most common integration mistake.
agentforce-sdk/ or agentforce-service/ Gradle modules at the root, refuse and tell the user to cd into their app first.Guest(url) or OrgJWT by default. They're only correct in specific situations. Recommend the path that matches the user's described use case.AgentforceClient for the conversation's lifetime. Stash it in your Application or a long-lived ViewModel; if it's recreated mid-chat the conversation is lost.AskUserQuestion for branching choices. Don't free-text prompts — give 2–4 explicit options.{{TOKENS}} in the final files. Collect values up front; if the user can't provide a value, leave a clearly-marked // TODO: comment instead.Look in the current working directory for:
settings.gradle.kts / settings.gradle (root of an Android Gradle project)build.gradle.kts / build.gradle (in app module)app/ (or similar) module containing AndroidManifest.xmlIf none is present, ask the user where the Android project root is and cd there. If the directory contains agentforce-sdk/ and agentforce-service/ modules at the root, refuse — that's this SDK's own repo (or its internal counterpart).
See references/dep-detection.md for the full Gradle setup decision tree.
Ask first what they're building, then map to an auth flow:
AskUserQuestion: "What kind of agent are you integrating?"
- Employee agent (signed-in users, internal tools) → AgentforceMode.FullConfig (employee path)
- Public service agent (customer-facing, no sign-in) → AgentforceMode.ServiceAgent
- Other / not sure → see references/auth-flows.md
Ask the follow-up:
AskUserQuestion: "How are you obtaining auth credentials?"
- Salesforce Mobile SDK (UserAccountManager) → AgentforceAuthCredentials.OAuth(authToken, orgId, userId)
- Org JWT → AgentforceAuthCredentials.OrgJWT(orgJWT)
AppCredentialProvider from references/snippets/AppCredentialProvider+OAuth.kt. The provider's getAuthCredentials() reads from SalesforceSDKManager.getInstance().userAccountManager.currentUser — or wraps the consumer's existing token-source class if they already have one.references/snippets/AppCredentialProvider+OrgJWT.kt. Ask for the source of the JWT (a function reference, encrypted SharedPreferences key, or a backend call) and wire getAuthCredentials() to call into it on every invocation. Don't cache.For both employee paths, use AgentforceMode.FullConfig(configuration). Salesforce currently exposes EmployeeAgentConfiguration as well, but the public SDK path most apps follow is FullConfig with an AgentforceConfiguration.builder(...) — that's what the README shows and it accepts every option (network, navigation, logger, theme).
This is the simplest path:
AgentforceMode.ServiceAgent(serviceAgentConfiguration, agentforceConfiguration).AgentforceAuthCredentialProvider — for unauthenticated service agents, scaffold one that returns AgentforceAuthCredentials.Guest(url = "<your salesforceDomain>"). See references/snippets/AppCredentialProvider+Guest.kt.esDeveloperName, organizationId, and serviceApiURL from the deployment.Walk them through references/auth-flows.md. The two extra options to surface here:
Guest(url) — for public agents going through the Agent API behind an Experience Cloud site. Most "public agent" cases should use Branch B's MIAW service-agent flow instead.PassThroughAuth(miawJWT, eventID) — only for service agents whose MIAW deployment uses AuthorizationMethod.PASSTHROUGH. The consumer's backend mints a MIAW JWT and the SDK calls fetchMIAWJWTForPassthrough(...) on demand.AskUserQuestion: "Where should the chat UI live?"
- Bottom sheet (recommended) → ChatHost+BottomSheet.kt
- Full-screen Activity / route → ChatHost+FullScreenActivity.kt
- Embedded panel in an existing screen → ChatHost+EmbeddedPanel.kt
- Dialog / modal popup → ChatHost+Dialog.kt
Each option corresponds to one snippet in references/snippets/. AgentforceClient.AgentforceConversationContainer(conversation, onClose) is a @Composable — drop it inside any composable scope.
See references/chat-presentation.md for the patterns and how to remember showChat state across configuration changes (rememberSaveable).
Based on the chosen branch:
| Branch | Required values |
|---|---|
| Employee + Mobile SDK | salesforceDomain (instance URL, e.g. https://mycompany.my.salesforce.com); agentId |
| Employee + Org JWT | Same as above, plus the JWT source (function/closure, secure storage key, or backend endpoint) |
| Public Service Agent | esDeveloperName, organizationId, serviceApiURL, plus a salesforceDomain for the Guest URL |
| Guest (via "Other") | salesforceDomain, agentId |
Ask one question per missing value. If the user gives "I don't know" for a Service Agent value, point them back at the MIAW deployment link and stop.
Edit two Gradle files. See references/dep-detection.md for full details and KTS/Groovy variants.
settings.gradle.kts — add Maven reposdependencyResolutionManagement {
repositories {
google()
mavenCentral()
maven { url = uri("https://jitpack.io") }
maven { url = uri("https://opensource.salesforce.com/AgentforceMobileSDK-Android/agentforce-sdk-repository") }
maven { url = uri("https://s3.amazonaws.com/inapp.salesforce.com/public/android") }
maven { url = uri("https://s3.amazonaws.com/salesforce-async-messaging-experimental/public/android") }
}
}
build.gradle.kts — plugins and dependenciesplugins {
id("com.android.application")
id("kotlin-android")
id("kotlin-kapt")
id("kotlinx-serialization")
}
android {
compileOptions {
isCoreLibraryDesugaringEnabled = true
}
}
dependencies {
api("com.salesforce.android.agentforcesdk:agentforce-sdk:15.0.2")
coreLibraryDesugaring("com.android.tools:desugar_jdk_libs:2.1.5")
// Optional: voice support
// api("com.salesforce.android.agentforcesdk:agentforce-sdk-voice:15.0.2")
}
The consumer needs:
@Composable.If their app is not Compose-based, surface this and ask whether they want to add Compose to the existing module. The SDK does not ship a View-based chat surface.
Create the package com.<their.package>.agentforce and write the following, substituting placeholders with values from Phase 3:
| File | When | Source snippet |
|---|---|---|
AppCredentialProvider.kt | Always | snippets/AppCredentialProvider+OAuth.kt, +OrgJWT.kt, or +Guest.kt based on Phase 1 |
AppNetwork.kt | Always | snippets/AppNetwork.kt (OkHttp-backed Network impl) |
AppLogger.kt | Always | snippets/AppLogger.kt (android.util.Log-backed Logger impl) |
AppNavigation.kt | Always | snippets/AppNavigation.kt (no-op Navigation to start) |
AgentforceHolder.kt | Always | snippets/AgentforceHolder.kt (initializes the client; lives on Application) |
AppAgentforceUIDelegate.kt | Always | snippets/AppAgentforceUIDelegate.kt |
AgentforceChatHost.kt | Always | one of snippets/ChatHost+*.kt based on Phase 2 |
AgentforceHolder.kt is parameterized by mode — pass the right AgentforceMode and the right conversation-starter call (startAgentforceConversation() for employee/full-config, startAgentforceServiceConversation(esDeveloperName = ...) for service agents).
The logger conforms to com.salesforce.android.mobile.interfaces.logging.Logger (methods e/i/w, no d). Wire it via .setLogger(AppLogger()) on the configuration builder.
AgentforceClient should outlive any single Activity. Patch the consumer's Application subclass:
class MyApp : Application() {
lateinit var agentforce: AgentforceHolder
private set
override fun onCreate() {
super.onCreate()
agentforce = AgentforceHolder(application = this)
}
}
…and register the Application class in AndroidManifest.xml:
<application
android:name=".MyApp"
... >
If the consumer already uses Hilt or another DI framework, surface that instead — provide AgentforceHolder as a @Singleton rather than putting it on Application directly.
Tell the user:
./gradlew :app:dependencies or via Android Studio). Expect a clean sync../gradlew :app:assembleDebug. If it fails on BUILD_LIBRARY_FOR_DISTRIBUTION-equivalent or duplicate-class errors, check the Maven repo order in settings.gradle.kts (Salesforce repos must come before mavenCentral() if you hit conflicts).AgentforceHolder is owned at the Application level (or as a Hilt singleton). If it's instantiated inside an Activity, the conversation will reset on rotation.AgentforceSDK (the default for the scaffolded AppLogger) to see SDK loglines.AuthorizationMethod.USERVERIFIED or PASSTHROUGH was chosen, remind the user to implement fetchMIAWJWTForPassthrough(...) and getIdentityToken() on their AgentforceAuthCredentialProvider.If the build fails, common causes:
kotlin-kapt or kotlinx-serialization plugins.settings.gradle.kts.references/auth-flows.md — full credential-flow decision tree, including Guest, OrgJWT, and PassThroughAuth edge cases.references/client-setup.md — AgentforceClient.init(...), mode selection, holder pattern, conversation lifecycle.references/logger-setup.md — Logger and Network interface conformance.references/chat-presentation.md — bottom sheet / full-screen / embedded / dialog Compose patterns.references/dep-detection.md — Gradle KTS/Groovy variants and Compose enablement check.references/snippets/*.kt — file templates with {{PLACEHOLDERS}} to substitute.