Generate SAP Automation Pilot commands with dynamic expressions, jq transformations, and composite workflows. Use when creating commands, building orchestration flows, or working with Automation Pilot expressions and script execution (Bash, Python, Node.js, PowerShell).
Generate SAP Automation Pilot commands with dynamic expressions, jq transformations, and composite workflows. Use when creating commands, building orchestration flows, or working with Automation Pilot expressions and script execution (Bash, Python, Node.js, PowerShell).
SAP Automation Pilot Command Development
This skill provides guidance for creating SAP Automation Pilot commands by composing existing reference commands from the content library.
Command Release Policy
Deployed commands start in DRAFT state. Do not release automatically — only release when:
The command has been tested and works correctly
The user explicitly requests release
Draft state allows safe iteration without affecting production.
Overview
SAP Automation Pilot commands are JSON definitions that automate operations on SAP BTP. Commands can be:
Atomic: Execute a single operation (e.g., HttpRequest, SendEmail)
Composite: Orchestrate multiple steps using executors
This ensures you always use valid executor names and correct parameters, even for newly added catalogs.
Dry Run
dryRun is always present on every executor. Set it to null unless you have a specific reason to provide mock output.
"dryRun":null
The dryRun: {output: {...}} form (with mock values) is only needed if a downstream executor references this executor's output AND you want dry-run mode to propagate realistic values through the chain. In practice, null is the standard.
IMPORTANT: Catalog Naming & ForEach Version
See references/catalogs.md for the complete catalog reference. Key rules:
Generated commands: Use <<<TENANT_ID>>> suffix (e.g., mycommands-<<<TENANT_ID>>>:MyCommand:1)
Built-in SAP commands: Use sapcp suffix (e.g., http-sapcp:HttpRequest:1)
ForEach: Always use ForEach:2, never ForEach:1 (deprecated)
Command Structure
Naming Conventions
Element
Convention
Example
Command name
PascalCase
RestartCfApp, GetHanaInstance
Input name
PascalCase
BtpCredentials, JiraConfig
Input/output keys
camelCase
resourceName, subAccount
Aliases
camelCase
getResource, createInstance
Catalog ID
kebab-case
mycommands-xxx
Names must not contain spaces (causes API issues). PascalCase matches SAP's built-in commands.
Basic Command Definition
{"id":"mycommands-<<<TENANT_ID>>>:CommandName:1","catalog":"mycommands-<<<TENANT_ID>>>","name":"CommandName","description":"What the command does","version":1,"inputKeys":{},"outputKeys":{},"configuration":null,"tags":{}}
Input Keys
Define command parameters:
"inputKeys":{"paramName":{"type":"string",// string, number, boolean, array, object"description":"Description","required":true,"sensitive":false,// true masks in logs"defaultValue":"value","minValue":1,// for numbers"maxValue":100}}
Additional optional fields exist: allowedValues (fixed set of valid options), suggestedValues (hints shown in UI), allowedValuesFromInputKeys and suggestedValuesFromInputKeys (dynamic lists from an input reference). Omit them when not needed.
defaultValue is always a JSON string on the wire regardless of the declared type. For non-string types, stringify the JSON: "defaultValue": "5" for a number, "defaultValue": "true" for a boolean, "defaultValue": "[\"a\",\"b\"]" for an array, "defaultValue": "{\"key\":\"val\"}" for an object.
Region inputs must always use allowedValuesFromInputKeys to constrain the value to the SAP-provided region list:
Commands with configuration orchestrate multiple steps:
"configuration":{"values":[],// Pre-computed values from input references"output":{},// Final output mapping"executors":[],// Steps to execute"listeners":[]// Event handlers}
Input References (values)
Load reusable credentials or metadata at execution time. Three forms of inputKey:
Expressions use jq 1.6 syntax wrapped in $(). Access data with:
.execution.input.key - Input values
.stepAlias.output.key - Previous step outputs
.regionData.field - Values from input references
$ - Global scope (use inside pipes)
See references/expressions.md for the full expression reference — patterns, string/array/object operations, type conversions, and utilities.
IMPORTANT: Expression Complexity Limits
Expressions have a complexity limit. If you get "Expression contains too many elements" error, break complex object construction into intermediate Void steps:
User: "Create a command that checks if an API endpoint is healthy"
Create a composite command with one http-sapcp:HttpRequest:1 executor
Add url and expectedStatus as input keys
Add validate to assert response status matches expected
Add autoRetry for transient failures (429, 500, 502, 503, 504)
Include dryRun with a mock 200 response
Use <<<TENANT_ID>>> suffix for the catalog
Example 2: Batch processing with ForEach
User: "Build a command that processes a list of items in parallel batches of 5"
Create a main composite command with an items input key (array type)
Create a sub-command for processing a single item
Use utils-sapcp:ForEach:2 (never ForEach:1) with batchSize: "5"
Pass items via the inputs parameter
Include dryRun on both the ForEach executor and the sub-command executors
Example 3: Trigger-and-poll workflow
User: "Create a command that starts an async operation and polls until it completes"
Create a composite command with a trigger step (HttpRequest PATCH/POST)
Add a polling step with repeat configuration
Set repeat.until to check for completion states (e.g., succeeded, failed)
Set repeat.maxCount and repeat.delay for timeout protection
Set failOnMaxCount: true so the command fails if polling exceeds the limit
Extract operation ID from the trigger response and pass to the poll URL
Troubleshooting
Error: "Expression contains too many elements"
Cause: A single expression builds an object with too many fields (>5-6 from different step outputs).
Solution: Break into intermediate utils-sapcp:Void:1 steps to build partial objects, then combine.
Error: Command references ForEach:1Cause: Using the deprecated version.
Solution: Always use utils-sapcp:ForEach:2. Version 1 is deprecated and must never be used.
Error: Catalog suffix uses -sapcp for a generated command
Cause: Applying the wrong suffix convention.
Solution: Generated commands use <<<TENANT_ID>>> suffix. Only SAP-provided built-in commands use -sapcp.
Error: Missing dryRun field on an executor
Cause: Executor defined without a dryRun field.
Solution: Always include "dryRun": null unless mock output propagation through a chain is needed.
Additional Resources
Reference Files
For detailed patterns and complete expression reference: