| name | sap-adt-cli |
| description | Read and write ABAP source code and metadata from SAP systems via the ADT REST API. Use when the user asks to read, view, analyze, modify, write, or activate ABAP programs, classes, function modules, function groups, interfaces, includes, CDS views, DDIC tables, structures, data elements, domains, type groups, transactions, or packages. Also handles: syntax checking, where-used analysis, Open SQL data preview, transport request management (list, create, release), and searching for ABAP objects by name. Write and transport operations require explicit capability flags enabled in config, AND require user confirmation for every individual operation — confirmation is one-time and never reused across operations in the same session. On first use, guides the user through SAP credential setup interactively. |
SAP ADT CLI Skill
Read ABAP source code and metadata from SAP via scripts/sap_adt_cli.py.
CLI Location
The CLI is scripts/sap_adt_cli.py inside this skill's directory.
Resolve the skill directory at runtime using the skill tool's path, then build the CLI path:
SKILL_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]:-$0}")")"
SAP_CLI="$SKILL_DIR/scripts/sap_adt_cli.py"
python3 "$SAP_CLI" <command> [args]
If you already know the absolute path to the skill directory (e.g. from the skill loader), use it directly:
SAP_CLI="$HOME/.agents/skills/sap-adt-cli/scripts/sap_adt_cli.py"
python3 "$SAP_CLI" <command> [args]
# Windows — skill installed via setup-opencode-abap-cli.bat (Junction)
$SAP_CLI = "$env:USERPROFILE\.agents\skills\sap-adt-cli\scripts\sap_adt_cli.py"
python "$SAP_CLI" <command> [args]
First run auto-installs click, requests, and urllib3. All source code output goes to stdout. Errors go to stderr with exit code 1.
CRITICAL: Credential Check Before First Command
Always run this before the first ABAP query in a session:
python3 "$SAP_CLI" status
Credentials configured → proceed
Output example:
URL: https://my-sap.example.com:8000
Username: DEVELOPER
Client: 100
Language: EN
SSL: verify
Write mode: DISABLED
Transport write: DISABLED
Config source: /home/user/.sap-adt-cli/config.json
Credentials NOT configured → collect and save non-interactively
You will see:
Not configured. Run: python3 sap_adt_cli.py configure
Or any ABAP command will print to stderr:
SAP credentials not configured.
...
Collect all credentials in a SINGLE question tool call — pass all fields as one array.
Do NOT ask one field at a time; multiple sequential calls create separate UI tabs that can
cause earlier answers to be overwritten before all values are saved.
Fields to ask (all at once):
1. SAP System URL — e.g. https://my-sap.example.com:8000 (include port)
2. SAP Username — dialog user, e.g. DEVELOPER
3. SAP Password — SAP logon password
4. SAP Client — 3-digit number, e.g. 100
5. Skip SSL check? — yes/no (yes = self-signed / internal systems, no = production with valid cert)
After receiving all answers from the single question call, save with one configure command:
python3 "$SAP_CLI" configure \
--url "https://my-sap.example.com:8000" \
--username "DEVELOPER" \
--client "100" \
--language "EN"
Pass the password via environment variable to avoid shell history exposure:
SAP_PASSWORD="mysecret" python3 "$SAP_CLI" configure \
--url "https://my-sap.example.com:8000" \
--username "DEVELOPER" \
--client "100"
Then verify:
python3 "$SAP_CLI" status
Credentials are saved to ~/.sap-adt-cli/config.json (permissions 0600) and reused in all future sessions.
To enable write or transport capabilities:
python3 "$SAP_CLI" configure
SAP_PASSWORD="mysecret" python3 "$SAP_CLI" configure \
--url "https://sap-dev.example.com:44300" \
--username "DEVELOPER" \
--client "400" \
--allow-write \
--no-allow-transport
| Flag | Default | Controls |
|---|
--allow-write / --no-allow-write | disabled | write-source, activate |
--allow-transport / --no-allow-transport | disabled | create-transport, release-transport |
One-time confirmation rule (CRITICAL for agent workflows):
Even when capability flags are enabled, every write/create/release operation
requires an interactive change preview and explicit [y/N] confirmation.
This confirmation applies to the current operation only and is immediately
discarded after use — it is NEVER stored, cached, or reused.
In the same conversation, if the user asks for another write/create/release
operation, confirmation must be obtained again from scratch.
Use --yes only when the caller has explicit out-of-band authorization
(e.g. a trusted CI pipeline). Never pass --yes on behalf of the user
based on a previous confirmation in the same conversation.
Security note: inform the user that credentials stored in SKILL-local .env
or ~/.sap-adt-cli/config.json are plain text. The JSON config file is
protected with 0600 permissions but is not encrypted.
Alternative A — SKILL-local .env (recommended for per-skill isolation):
cp "$(dirname "$SAP_CLI")/../.env.example" "$(dirname "$SAP_CLI")/../.env"
python3 "$SAP_CLI" status
Alternative B — env vars per invocation (no file written, useful for one-off sessions):
SAP_URL="https://..." SAP_USERNAME="USER" SAP_PASSWORD="pass" SAP_CLIENT="100" python3 "$SAP_CLI" status
Credential precedence is: process env vars > SKILL-local .env > ~/.sap-adt-cli/config.json.
Capability flags map to SAP_ALLOW_WRITE and SAP_ALLOW_TRANSPORT; keep both 0
unless the user explicitly authorizes write or transport operations.
Commands Quick Reference
| Command | Usage | Description |
|---|
configure | configure | Interactive credential setup wizard |
status | status | Show current connection config |
get-program | get-program <NAME> | ABAP program (report) source code |
get-class | get-class <NAME> | ABAP class source code |
get-function-group | get-function-group <NAME> | Function group top-include source |
get-function | get-function <NAME> --group <FG> | Function module source code |
get-include | get-include <NAME> | ABAP include source code |
get-interface | get-interface <NAME> | ABAP interface source code |
get-table | get-table <NAME> | DDIC table field definitions |
get-structure | get-structure <NAME> | DDIC structure definition |
get-type-info | get-type-info <NAME> | Domain or data element (tries domain first) |
get-package | get-package <NAME> | Package object list → JSON array |
get-transaction | get-transaction <NAME> | Transaction properties/package info |
search-object | search-object <QUERY> [--max-results N] | Quick object search (* wildcard) |
syntax-check | syntax-check <TYPE> <NAME> [--group <FG>] | ABAP syntax check — no system change |
get-cds-view | get-cds-view <NAME> | CDS View DDL source code |
get-type-group | get-type-group <NAME> | ABAP type group (TYPE POOL) source |
write-source | write-source <TYPE> <NAME> --file <PATH> | Write source code (allow_write + confirm each time) |
activate | activate <TYPE> <NAME> | Activate ABAP object (allow_write + confirm each time) |
where-used | where-used <TYPE> <NAME> [--max-results N] | Where-used list → JSON array |
run-sql | run-sql "<SQL>" [--max-rows N] | Open SQL SELECT → JSON; DML statements are blocked |
list-transports | list-transports [--user U] [--status D|R] | List transport requests → JSON |
create-transport | create-transport --description "<DESC>" | Create transport request (allow_transport + confirm each time) |
release-transport | release-transport <TRKORR> [--yes] | Release transport — irreversible (allow_transport + confirm each time) |
Usage Examples
SAP_CLI="<skill_dir>/scripts/sap_adt_cli.py"
python3 "$SAP_CLI" get-program SAPMV45A
python3 "$SAP_CLI" get-class ZCL_MY_CLASS
python3 "$SAP_CLI" get-function BAPI_SALESORDER_CREATEFROMDAT2 --group BAPI_SD_SALESORDER
python3 "$SAP_CLI" get-include MV45AFZZ
python3 "$SAP_CLI" get-interface ZIF_MY_INTERFACE
python3 "$SAP_CLI" get-table VBAK
python3 "$SAP_CLI" get-structure VBAKKOM
python3 "$SAP_CLI" get-type-info MATNR
python3 "$SAP_CLI" search-object "ZCL_*" --max-results 20
python3 "$SAP_CLI" get-package ZMYPACKAGE
python3 "$SAP_CLI" get-transaction VA01
python3 "$SAP_CLI" get-cds-view ZI_INVENTORY_POSITION
python3 "$SAP_CLI" get-type-group ICON
python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file /tmp/zcl.abap
python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file /tmp/zcl.abap --activate
cat updated.abap | python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file -
python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file /tmp/zcl.abap --yes
python3 "$SAP_CLI" activate class ZCL_MY_CLASS
python3 "$SAP_CLI" where-used class ZCL_PAYMENT_PROCESSOR --max-results 50
python3 "$SAP_CLI" where-used interface ZIF_MY_INTERFACE
python3 "$SAP_CLI" run-sql "SELECT * FROM t001 UP TO 10 ROWS"
python3 "$SAP_CLI" run-sql "SELECT bukrs, butxt FROM t001 WHERE spras = 'EN'" --max-rows 200
python3 "$SAP_CLI" list-transports
python3 "$SAP_CLI" list-transports --user SHREK --status D
python3 "$SAP_CLI" create-transport --description "Fix rounding issue"
python3 "$SAP_CLI" release-transport DEVK900001
python3 "$SAP_CLI" release-transport DEVK900001 --yes
Key Behaviors & Gotchas
- Object names: SAP names are case-insensitive but always use UPPERCASE for reliability (e.g.
VBAK, ZCL_MY_CLASS, not vbak)
- Source output:
get-program, get-class, get-function, etc. return raw ABAP source text
- XML output:
get-table, get-structure, get-type-info, get-transaction, search-object return raw XML from ADT — parse it or read it as-is
- JSON output:
get-package is the only command that returns a parsed JSON array
get-type-info fallback: tries domain first; if not found, falls back to data element
- SSL: for internal SAP systems with self-signed certs, configure with SSL disabled (
SAP_VERIFY_SSL=0 or answer "n" in wizard)
- Session reuse: the HTTP session is reused within a single script invocation; each
python3 "$SAP_CLI" ... call starts fresh
- Credentials precedence: process env vars > SKILL-local
.env > ~/.sap-adt-cli/config.json
- Capability flags — config layer:
write-source and activate require allow_write: true;
create-transport and release-transport require allow_transport: true.
Run configure to enable. list-transports is read-only and has no flag requirement.
- One-time confirmation — execution layer: every write/create/release operation
shows a change preview and requires
[y/N] confirmation before executing.
This confirmation is scoped to the current operation only — it is immediately
discarded after use and never cached or reused within the same session.
The next write/create/release in the same session requires a fresh confirmation.
- Agent rule — never reuse confirmation: when operating as an AI agent,
do not infer that a previous confirmation covers subsequent operations.
Every invocation of a write-capable command is independent.
Pass
--yes only with explicit user instruction for that specific call.
write-source lock protocol: flow is lock → PUT → unlock; unlock runs in
finally so objects are never left locked after an error.
release-transport is irreversible: once released, a transport cannot be
recalled. The confirmation preview explicitly calls this out.
run-sql Open SQL only: uses ADT Data Preview; accepts SAP Open SQL syntax
(e.g. UP TO N ROWS), not Native SQL or JDBC-style syntax.
run-sql DML blocked: statements starting with INSERT, UPDATE, DELETE,
MODIFY, or TRUNCATE are unconditionally rejected in this version.
Only SELECT statements are permitted. Detection is by first keyword,
case-insensitive — SELECT containing write keywords in values is safe.
where-used empty result: returns [] — not an error (exit 0).
get-cds-view name: use the CDS entity name (e.g. ZI_INVENTORY_POSITION),
not the underlying database table name.
syntax-check with function: requires --group <FG> (same as get-function).
Output Format
| Command | Output Format |
|---|
Source code commands (get-program, get-class, get-function, get-include, get-interface, get-cds-view, get-type-group) | Plain text ABAP source |
get-table, get-structure, get-type-info, get-transaction, search-object | Raw XML |
get-package, where-used, list-transports, run-sql | JSON array |
syntax-check | Plain text messages ([ERROR], [WARNING], [INFO] prefixed); "Syntax OK" if clean |
status | Plain text key-value pairs |
Error Handling
| Error Output | Cause | Action |
|---|
Not configured | No saved credentials | Guide user through configure |
HTTP 401 | Wrong username/password | Ask user to re-run configure |
HTTP 403 | Missing ADT authorization | User needs SAP_ADT_BASE role or equivalent |
HTTP 404 | Object name not found | Try search-object to find the correct name |
HTTP 503 | ADT service not active | SAP Basis must activate /sap/bc/adt in transaction SICF |
| SSL error | Certificate issue | Re-configure with SAP_VERIFY_SSL=0 |
Workflows
Read an unknown class:
python3 "$SAP_CLI" search-object "ZCL_ORDER*"
python3 "$SAP_CLI" get-class ZCL_ORDER_HANDLER
Explore a package:
python3 "$SAP_CLI" get-package ZMYPACKAGE
python3 "$SAP_CLI" get-program ZMYREPORT
python3 "$SAP_CLI" get-class ZCL_MYCLASS
Look up a BAPI signature:
python3 "$SAP_CLI" get-function BAPI_SALESORDER_CREATEFROMDAT2 --group BAPI_SD_SALESORDER
Understand a table structure:
python3 "$SAP_CLI" get-table VBAK
python3 "$SAP_CLI" get-type-info VBELN
Find a transaction's package/application:
python3 "$SAP_CLI" get-transaction VA01
Safe write workflow — syntax-check before writing:
python3 "$SAP_CLI" syntax-check class ZCL_MY_CLASS
python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file ./zcl_my_class.abap --activate
Find all usages of an interface:
python3 "$SAP_CLI" where-used interface ZIF_MY_INTERFACE --max-results 100
Quick data check without SE16N:
python3 "$SAP_CLI" run-sql "SELECT COUNT(*) AS CNT FROM ekko WHERE bstyp = 'F'"
Create and release a transport (two separate confirmations):
python3 "$SAP_CLI" create-transport --description "Sprint 12 — invoice fix"
python3 "$SAP_CLI" list-transports --status D
python3 "$SAP_CLI" release-transport DEVK900042
SAP Prerequisites
- ADT services active: transaction
SICF → path /sap/bc/adt → Activate
- User authorization: role
SAP_ADT_BASE or objects S_ADT_RES, S_RFC
- Write & activate (
write-source, activate): requires allow_write: true in config.
SAP user additionally needs S_DEVELOP with ACTVT=02 on relevant object types.
- Transport management (
create/release-transport): requires allow_transport: true in config.
SAP user needs S_CTS_ADMI or equivalent transport authorization.
list-transports is read-only and needs no additional flag.
- Data Preview (
run-sql): requires /sap/bc/adt/datapreview active in transaction SICF.