Provides reference for SAP BTP CLI operations including session management, login methods, targeting subaccounts, JSON output, and command taxonomy. Guides other skills and scripts before issuing btp commands.
npx claudepluginhub sap-samples/btp-neo-java-app-migration --plugin sap-btp-neo-migrationThis skill is limited to using the following tools:
Complete reference for the SAP BTP CLI (`btp`) — session management, full command taxonomy, JSON output patterns, and scope boundaries. Use this skill as a toolset when other skills need to issue BTP CLI commands.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Processes PDFs: extracts text/tables/images, merges/splits/rotates pages, adds watermarks, creates/fills forms, encrypts/decrypts, OCRs scans. Activates on PDF mentions or output requests.
Share bugs, ideas, or general feedback.
Complete reference for the SAP BTP CLI (btp) — session management, full command taxonomy, JSON output patterns, and scope boundaries. Use this skill as a toolset when other skills need to issue BTP CLI commands.
btp --version
# Example: SAP BTP command line interface (client v2.x.x)
The BTP CLI operates against the BTP Account API — it manages the account layer (subaccounts, entitlements, security, service manager). It does NOT manage Cloud Foundry runtime objects (apps, CF service instances, CF spaces) — those require the cf CLI.
The CLI uses a session file stored in ~/.btp/ that caches the login token. A session is valid for a limited time (roughly 12 hours for SSO, longer for some flows). Commands fail silently with "Authorization failed" or "Unknown session" when expired.
btp login --sso
# Opens browser → SAP ID Service login → returns to CLI
btp login --user <email> --password <password>
# Not recommended for CI/CD — prefer service key + REST APIs
btp login --sso --idp <custom-idp-origin>
# Use when your user is managed by a custom IdP (not SAP ID Service)
IMPORTANT: There is NO client-credentials login for the BTP CLI. For headless/automated workflows, use the underlying BTP REST APIs directly with OAuth2 service keys instead.
After login, set the default subaccount scope so you don't need --subaccount on every command:
btp target --subaccount <subaccount-id>
# e.g. btp target --subaccount 2f964175-0856-47b2-b77a-469c74df0cca
Check current target:
btp target
# Shows: global account, subaccount, org, space
Clear target:
btp target --reset
# Set JSON as default for all commands
btp set config --format json
# Or per-command
btp --format json list security/role-collection
Before running commands in a script, verify the session is active:
btp --format json list accounts/subaccount 2>&1 | grep -q '"subaccounts"' \
&& echo "Session OK" || echo "Session expired — run: btp login"
--subaccount is optional when targeted — if you ran btp target --subaccount <id>, omit it. If targeting a different subaccount, pass it explicitly.btp vs cf — BTP CLI manages the account layer; cf CLI manages the CF runtime layer. Neither can substitute for the other.btp login requires a browser or interactive terminal; cannot be used in CI pipelines with stored credentials. Use REST APIs with service keys instead.--global-account or --subaccount to specify.--of-idp vs --origin — when assigning role collections to users from a custom IdP, use --of-idp <idp-origin> (not --origin). Example: btp assign security/role-collection "MyRC" --to-user user@example.com --of-idp sap.default.btp update security/trust --set-default does not exist — setting the default IdP in a CF subaccount must be done manually in BTP Cockpit → Security → Trust Configuration.jq keys on first use.--format json placement — must come right after btp, before the verb: btp --format json list ... (not btp list ... --format json).See references/command-quick-reference.md for a single-table quick reference of all 70+ commands.
Commands for managing the global account, subaccounts, directories, and environment instances.
# Global Account
btp get accounts/global-account
btp update accounts/global-account --display-name <name>
# Subaccounts
btp list accounts/subaccount
btp get accounts/subaccount <id>
btp create accounts/subaccount \
--display-name <name> \
--region <region> \
--subdomain <subdomain>
btp update accounts/subaccount <id> --display-name <name>
btp delete accounts/subaccount <id>
btp move accounts/subaccount <id> --to-directory <dir-id>
# Directories
btp list accounts/directory
btp get accounts/directory <id>
btp create accounts/directory --display-name <name>
btp update accounts/directory <id> --display-name <name>
btp delete accounts/directory <id>
btp enable accounts/directory <id> --for entitlements
btp enable accounts/directory <id> --for authorizations
# Environment Instances (CF Org provisioning)
btp list accounts/environment-instance [--subaccount <id>]
btp get accounts/environment-instance <id> [--subaccount <id>]
btp create accounts/environment-instance \
--environment cloudfoundry \
--service cloudfoundry \
--plan standard \
--subaccount <id> \
--display-name <name> \
--parameters '{"instance_name":"<org-name>"}'
btp update accounts/environment-instance <id> \
--subaccount <id> \
--parameters '{"memory":<MB>}'
btp delete accounts/environment-instance <id> [--subaccount <id>]
# Labels
btp list accounts/label [--subaccount <id>]
btp set accounts/label --key <key> --value <val> [--subaccount <id>]
btp delete accounts/label --key <key> [--subaccount <id>]
# Resource providers
btp list accounts/resource-provider
btp get accounts/resource-provider <provider>/<key>
btp create accounts/resource-provider \
--provider <AWS|AZURE|GCP> \
--technical-name <key>
btp delete accounts/resource-provider <provider>/<key>
# Custom Properties
btp list accounts/custom-property [--subaccount <id>]
btp set accounts/custom-property --key <key> --value <val>
# List what's available and assigned
btp list accounts/entitlement [--subaccount <id>]
btp list accounts/entitlement --show-technical-info
# Assign entitlement quota to a subaccount
btp assign accounts/entitlement \
--service-name <service> \
--plan-name <plan> \
--subaccount <id> \
--amount <N>
# For CF Runtime (unlocks memory/routes quota):
btp assign accounts/entitlement \
--service-name APPLICATION_RUNTIME \
--plan-name MEMORY \
--subaccount <id> \
--amount <MB>
# Assign entitlement to a directory
btp assign accounts/entitlement \
--service-name <service> \
--plan-name <plan> \
--directory <id> \
--amount <N> \
--distribute
# Subscriptions (SaaS applications)
btp list accounts/subscription [--subaccount <id>]
btp subscribe accounts/subaccount \
--app-name <app> \
--plan <plan> \
[--subaccount <id>]
btp unsubscribe accounts/subaccount \
--app-name <app> \
[--subaccount <id>]
Commands for managing roles, role collections, users, and trust.
# Role Collections
btp list security/role-collection [--subaccount <id>]
btp get security/role-collection "<name>" [--subaccount <id>]
btp create security/role-collection "<name>" \
--description "<desc>" \
[--subaccount <id>]
btp update security/role-collection "<name>" \
--description "<new-desc>" \
[--subaccount <id>]
btp delete security/role-collection "<name>" [--subaccount <id>]
# Adding roles to a role collection
btp add security/role \
--role-collection "<rc-name>" \
--role-name "<role-name>" \
--app-id "<appid>" \
--role-template "<template-name>" \
[--subaccount <id>]
# Note: --app-id is the XSUAA xsappname!application suffix, e.g. "nonosgi-auth!t12345"
# Get it from: btp --format json list security/app | jq '.[] | select(.name=="<appname>") | .appId'
# Removing roles from a role collection
btp remove security/role \
--role-collection "<rc-name>" \
--role-name "<role-name>" \
--app-id "<appid>" \
--role-template "<template-name>" \
[--subaccount <id>]
# Users
btp list security/user [--subaccount <id>]
btp get security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
btp create security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
btp delete security/user <email> [--of-idp <idp-origin>] [--subaccount <id>]
# Assign/unassign role collections to users
btp assign security/role-collection "<rc-name>" \
--to-user <email> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
btp unassign security/role-collection "<rc-name>" \
--from-user <email> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
# Assign/unassign role collections to user groups
btp assign security/role-collection "<rc-name>" \
--to-group <group-name> \
[--of-idp <idp-origin>] \
[--subaccount <id>]
# XSUAA Applications (inspect app scopes/roles deployed by MTA)
btp list security/app [--subaccount <id>]
btp get security/app <appid> [--subaccount <id>]
# Lists all scopes and role-templates available from a deployed XSUAA app
# Trust Configuration
btp list security/trust [--subaccount <id>]
btp get security/trust <origin> [--subaccount <id>]
btp create security/trust \
--idp <ias-tenant-id-or-host> \
[--subaccount <id>]
btp update security/trust <origin> \
--description "<desc>" \
[--subaccount <id>]
btp delete security/trust <origin> [--subaccount <id>]
btp migrate security/trust "<origin>" [--subaccount <id>]
# migrate: convert a SAML trust to OIDC (for IAS tenants only)
# Settings
btp list security/setting [--subaccount <id>]
btp get security/setting <key> [--subaccount <id>]
btp set security/setting <key>=<value> [--subaccount <id>]
btp unset security/setting <key> [--subaccount <id>]
Commands for managing services via Service Manager.
# Service Offerings and Plans
btp list services/offering [--subaccount <id>]
btp get services/offering <id> [--subaccount <id>]
btp list services/plan [--subaccount <id>]
btp get services/plan <id> [--subaccount <id>]
# Service Instances
btp list services/instance [--subaccount <id>]
btp get services/instance <id> [--subaccount <id>]
btp create services/instance \
--offering-name <svc> \
--plan-name <plan> \
--display-name <name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp update services/instance <id> \
--display-name <new-name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp delete services/instance <id> [--subaccount <id>]
# Service Bindings (service keys)
btp list services/binding [--subaccount <id>]
btp get services/binding <id> [--subaccount <id>]
btp create services/binding \
--instance-id <instance-id> \
--display-name <binding-name> \
[--parameters '{"key":"value"}'] \
[--subaccount <id>]
btp delete services/binding <id> [--subaccount <id>]
# Brokers
btp list services/broker [--subaccount <id>]
btp get services/broker <id> [--subaccount <id>]
btp create services/broker \
--name <name> \
--url <url> \
--user <user> \
--password <password> \
[--subaccount <id>]
btp update services/broker <id> \
--url <new-url> \
[--subaccount <id>]
btp delete services/broker <id> [--subaccount <id>]
# Platforms (service manager platforms)
btp list services/platform [--subaccount <id>]
btp get services/platform <id> [--subaccount <id>]
btp register services/platform \
--name <name> \
--type <type> \
[--subaccount <id>]
btp unregister services/platform <id> [--subaccount <id>]
btp list connectivity/destination [--subaccount <id>]
btp get connectivity/destination <name> [--subaccount <id>]
# Note: these are early commands, do NOT rely on them for production automation
# Use the Destination Service REST API for reliable destination management
btp list accounts/backup-configuration
btp get accounts/backup-configuration <id>
btp update accounts/backup-configuration <id> --enable
See references/json-output-schemas.md for full schema examples.
# List all role collection names
btp --format json list security/role-collection | jq '.[].name'
# Get appId for a specific XSUAA app by display name
btp --format json list security/app | \
jq '.[] | select(.name | startswith("nonosgi-auth")) | {name, appId}'
# List all role-templates available for an app
btp --format json get security/app "<appid>" | \
jq '.roleTemplates[] | {name, description}'
# Check if a role collection exists
btp --format json list security/role-collection | \
jq 'any(.[]; .name == "MyRoleCollection")'
# Get CF org details from environment instance
btp --format json list accounts/environment-instance | \
jq '.environmentInstances[] | select(.environmentType == "cloudfoundry") | {displayName, labels}'
# List users in a role collection
btp --format json get security/role-collection "MyRC" | \
jq '.userReferences[] | .value'
# Extract subaccount ID by display name
btp --format json list accounts/subaccount | \
jq '.value[] | select(.displayName == "MySubaccount") | .guid'
# Get binding credentials (service key)
btp --format json get services/binding <binding-id> | \
jq '.credentials'
#!/bin/bash
set -e
# 1. Verify session is active
if ! btp --format json list accounts/global-account &>/dev/null; then
echo "ERROR: BTP CLI session expired. Run: btp login"
exit 1
fi
# 2. Target subaccount
SUBACCOUNT_ID="2f964175-0856-47b2-b77a-469c74df0cca"
btp target --subaccount "$SUBACCOUNT_ID"
# 3. Check if role collection already exists before creating
RC_NAME="MyApp-Users"
EXISTS=$(btp --format json list security/role-collection | jq --arg name "$RC_NAME" 'any(.[]; .name == $name)')
if [ "$EXISTS" = "false" ]; then
btp create security/role-collection "$RC_NAME" --description "Users of MyApp"
echo "Created role collection: $RC_NAME"
else
echo "Role collection already exists: $RC_NAME"
fi
After deploying an MTA with XSUAA, get the appId (needed for btp add security/role):
# List all XSUAA apps — appId has the format "<xsappname>!t<number>"
btp --format json list security/app | jq '.[] | {name, appId}'
Role collections created before XSUAA app deployment have no roles. After deploying, add them:
# 1. Get the appId
APP_ID=$(btp --format json list security/app | \
jq -r '.[] | select(.name | startswith("nonosgi-auth")) | .appId')
# 2. List available role-templates from the app
btp --format json get security/app "$APP_ID" | jq '.roleTemplates[] | .name'
# 3. Add each role-template to the appropriate role collection
btp add security/role \
--role-collection "nonosgi-auth-Everyone" \
--role-name "Everyone" \
--app-id "$APP_ID" \
--role-template "Everyone"
# List existing trust configurations
btp list security/trust
# Create OIDC trust with IAS tenant
btp create security/trust \
--idp <ias-tenant-hostname-or-id> \
--subaccount <subaccount-id>
# e.g. --idp nss.accounts.ondemand.com
# After creation, set it as default in BTP Cockpit manually
# (btp update security/trust --set-default does NOT exist)
When cf push or cf deploy fails with SUBSCRIPTION_QUOTA — total memory: 0, routes: 0:
# Check current entitlements
btp list accounts/entitlement --subaccount <id>
# Assign CF Runtime memory — triggers BTP to create and apply a new org quota
btp assign accounts/entitlement \
--service-name APPLICATION_RUNTIME \
--plan-name MEMORY \
--subaccount <id> \
--amount 3072 # MB — 3 GB minimum for typical apps
# After assignment, BTP automatically:
# 1. Creates a new org quota named "<guid>-t-<subaccount-guid>"
# 2. Applies it to the CF org (replaces SUBSCRIPTION_QUOTA)
# Note: btp assign can take 30-60 seconds to propagate to CF
Gotcha: Space quotas (
cf create-space-quota) do NOT override org-level route limits. The org quota must be fixed. Only BTP Cockpit entitlement assignment (or thebtp assign accounts/entitlementcommand above) creates the correct org quota automatically.
# Check if CF environment already exists
btp --format json list accounts/environment-instance --subaccount <id> | \
jq '.environmentInstances[] | select(.environmentType == "cloudfoundry")'
# Create CF environment (provisions a CF org)
btp create accounts/environment-instance \
--environment cloudfoundry \
--service cloudfoundry \
--plan standard \
--subaccount <id> \
--display-name "My CF Org" \
--parameters '{"instance_name":"my-org-name"}'
After any BTP CLI operation, verify with:
# Verify role collection was created
btp --format json list security/role-collection | jq '.[].name'
# Verify role was added to collection
btp --format json get security/role-collection "<rc-name>" | \
jq '.roleReferences[] | {roleTemplateName, roleTemplateAppId}'
# Verify user assignment
btp --format json get security/role-collection "<rc-name>" | \
jq '.userReferences[] | .value'
# Verify trust created
btp list security/trust
# Verify entitlement applied
btp --format json list accounts/entitlement | \
jq '.[] | select(.serviceName == "APPLICATION_RUNTIME")'
# Verify service instance created
btp --format json list services/instance | jq '.[] | {name, offering, plan, state}'
| Symptom | Cause | Solution |
|---|---|---|
Authorization failed. Unknown session | BTP CLI session expired | Run btp login (browser SSO) |
btp add security/role fails with "app not found" | Wrong --app-id format | Use full XSUAA appId (xsappname!tXXXX), get from btp list security/app |
btp assign with --of-idp fails | Wrong flag name | Use --of-idp (not --origin) for custom IdP users |
Role collection shows empty after btp add security/role | Race condition or targeting wrong subaccount | Verify with btp get security/role-collection <name>, check --subaccount param |
btp create security/trust fails | IAS tenant not yet connected | Use IAS tenant hostname (not GUID), verify IAS tenant exists |
btp assign accounts/entitlement appears to do nothing | BTP Cockpit hasn't reflected the change yet | Wait 60 seconds; then check btp list accounts/entitlement |
| CF quota still 0 after entitlement assignment | BTP creates quota async | Wait 1-2 minutes, then run cf quotas to see new quota appear |
--set-default flag not recognized by btp update security/trust | This subcommand does not exist | Set default IdP manually in BTP Cockpit → Security → Trust Configuration |
| Task | Reason | Alternative |
|---|---|---|
| Manage CF apps, spaces, routes, services | These are CF runtime layer objects | cf CLI |
| Create CF service instances | CF service instances live in CF org/space | cf create-service |
| Manage destinations (create, update, delete) | No reliable BTP CLI support for destinations | Destination Service REST API |
| Headless/CI login with client credentials | Login is always interactive (browser/password) | BTP REST APIs with service keys |
| Set default IdP in trust configuration | No --set-default flag exists | BTP Cockpit → Security → Trust |
| Abort stuck MTA operations | MTA operations run in CF layer | cf mta-ops, cf deploy -i -a abort |
| Access Neo subaccount resources | BTP CLI targets CF subaccounts only | Neo CLI (neo.sh) or Neo REST APIs |