# Sap Adt Cli

> Read and write ABAP source code and metadata from SAP systems via the ADT REST API.

- **Type:** Skill
- **Install:** `agentstack add skill-shrek-abaper-sap-engineering-skill-sap-adt-cli`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [shrek-abaper](https://agentstack.voostack.com/s/shrek-abaper)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [shrek-abaper](https://github.com/shrek-abaper)
- **Source:** https://github.com/shrek-abaper/sap-engineering-skill/tree/main/skills/sap-adt-cli

## Install

```sh
agentstack add skill-shrek-abaper-sap-engineering-skill-sap-adt-cli
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 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:

```bash
SKILL_DIR="$(dirname "$(realpath "${BASH_SOURCE[0]:-$0}")")"
SAP_CLI="$SKILL_DIR/scripts/sap_adt_cli.py"
python3 "$SAP_CLI"  [args]
```

If you already know the absolute path to the skill directory (e.g. from the skill loader), use it directly:

```bash
# Linux / macOS — skill installed via clone + symlink
SAP_CLI="$HOME/.agents/skills/sap-adt-cli/scripts/sap_adt_cli.py"
python3 "$SAP_CLI"  [args]
```

```powershell
# 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"  [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:**

```bash
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:**

```bash
python3 "$SAP_CLI" configure \
  --url      "https://my-sap.example.com:8000" \
  --username "DEVELOPER" \
  --client   "100" \
  --language "EN"
  # add --no-verify-ssl if user said yes to skipping SSL
```

Pass the password via environment variable to avoid shell history exposure:

```bash
SAP_PASSWORD="mysecret" python3 "$SAP_CLI" configure \
  --url "https://my-sap.example.com:8000" \
  --username "DEVELOPER" \
  --client "100"
```

Then verify:

```bash
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:**

```bash
# Interactive — answer prompts for write/transport flags
python3 "$SAP_CLI" configure

# Non-interactive — pass flags explicitly
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):

```bash
cp "$(dirname "$SAP_CLI")/../.env.example" "$(dirname "$SAP_CLI")/../.env"
# edit .env and fill SAP_URL, SAP_USERNAME, SAP_PASSWORD, SAP_CLIENT
python3 "$SAP_CLI" status
```

**Alternative B — env vars per invocation** (no file written, useful for one-off sessions):

```bash
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 ` | ABAP program (report) source code |
| `get-class` | `get-class ` | ABAP class source code |
| `get-function-group` | `get-function-group ` | Function group top-include source |
| `get-function` | `get-function  --group ` | Function module source code |
| `get-include` | `get-include ` | ABAP include source code |
| `get-interface` | `get-interface ` | ABAP interface source code |
| `get-table` | `get-table ` | DDIC table field definitions |
| `get-structure` | `get-structure ` | DDIC structure definition |
| `get-type-info` | `get-type-info ` | Domain or data element (tries domain first) |
| `get-package` | `get-package ` | Package object list → JSON array |
| `get-transaction` | `get-transaction ` | Transaction properties/package info |
| `search-object` | `search-object  [--max-results N]` | Quick object search (`*` wildcard) |
| `syntax-check` | `syntax-check   [--group ]` | ABAP syntax check — no system change |
| `get-cds-view` | `get-cds-view ` | CDS View DDL source code |
| `get-type-group` | `get-type-group ` | ABAP type group (TYPE POOL) source |
| `write-source` | `write-source   --file ` | Write source code *(allow_write + confirm each time)* |
| `activate` | `activate  ` | Activate ABAP object *(allow_write + confirm each time)* |
| `where-used` | `where-used   [--max-results N]` | Where-used list → JSON array |
| `run-sql`           | `run-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 ""` | Create transport request *(allow_transport + confirm each time)* |
| `release-transport` | `release-transport  [--yes]` | Release transport — irreversible *(allow_transport + confirm each time)* |

---

## Usage Examples

```bash
SAP_CLI="/scripts/sap_adt_cli.py"

# Source code
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

# Dictionary
python3 "$SAP_CLI" get-table VBAK
python3 "$SAP_CLI" get-structure VBAKKOM
python3 "$SAP_CLI" get-type-info MATNR

# Discovery
python3 "$SAP_CLI" search-object "ZCL_*" --max-results 20
python3 "$SAP_CLI" get-package ZMYPACKAGE
python3 "$SAP_CLI" get-transaction VA01

# CDS View & Type Group (read-only)
python3 "$SAP_CLI" get-cds-view ZI_INVENTORY_POSITION
python3 "$SAP_CLI" get-type-group ICON

# Write & activate (requires allow_write + confirmation each time)
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  # skip confirm (trusted automation only)
python3 "$SAP_CLI" activate class ZCL_MY_CLASS

# Where-used (read-only)
python3 "$SAP_CLI" where-used class ZCL_PAYMENT_PROCESSOR --max-results 50
python3 "$SAP_CLI" where-used interface ZIF_MY_INTERFACE

# Open SQL via Data Preview (read-only)
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

# Transport management
python3 "$SAP_CLI" list-transports                        # read-only — no flag needed
python3 "$SAP_CLI" list-transports --user SHREK --status D
python3 "$SAP_CLI" create-transport --description "Fix rounding issue"   # allow_transport + confirm
python3 "$SAP_CLI" release-transport DEVK900001           # allow_transport + confirm (irreversible warning)
python3 "$SAP_CLI" release-transport DEVK900001 --yes     # skip confirm (trusted automation only)
```

---

## 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 ` (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:**
```bash
python3 "$SAP_CLI" search-object "ZCL_ORDER*"
python3 "$SAP_CLI" get-class ZCL_ORDER_HANDLER
```

**Explore a package:**
```bash
python3 "$SAP_CLI" get-package ZMYPACKAGE
# → JSON list of all objects; pick the ones you need
python3 "$SAP_CLI" get-program ZMYREPORT
python3 "$SAP_CLI" get-class ZCL_MYCLASS
```

**Look up a BAPI signature:**
```bash
python3 "$SAP_CLI" get-function BAPI_SALESORDER_CREATEFROMDAT2 --group BAPI_SD_SALESORDER
```

**Understand a table structure:**
```bash
python3 "$SAP_CLI" get-table VBAK
python3 "$SAP_CLI" get-type-info VBELN   # look up field type
```

**Find a transaction's package/application:**
```bash
python3 "$SAP_CLI" get-transaction VA01
```

---

**Safe write workflow — syntax-check before writing:**
```bash
python3 "$SAP_CLI" syntax-check class ZCL_MY_CLASS
# → fix any errors locally, then:
python3 "$SAP_CLI" write-source class ZCL_MY_CLASS --file ./zcl_my_class.abap --activate
# → preview shown, confirmation required; confirmation discarded after use
```

**Find all usages of an interface:**
```bash
python3 "$SAP_CLI" where-used interface ZIF_MY_INTERFACE --max-results 100
# → JSON list of all implementing/using objects
```

**Quick data check without SE16N:**
```bash
python3 "$SAP_CLI" run-sql "SELECT COUNT(*) AS CNT FROM ekko WHERE bstyp = 'F'"
```

**Create and release a transport (two separate confirmations):**
```bash
python3 "$SAP_CLI" create-transport --description "Sprint 12 — invoice fix"
# → preview shown, confirmation #1 required → Created transport: DEVK900042
python3 "$SAP_CLI" list-transports --status D
# → JSON list (read-only, no confirmation)
python3 "$SAP_CLI" release-transport DEVK900042
# → irreversible-warning preview shown, confirmation #2 required (fresh, not reused)
```

---

## 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/a

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [shrek-abaper](https://github.com/shrek-abaper)
- **Source:** [shrek-abaper/sap-engineering-skill](https://github.com/shrek-abaper/sap-engineering-skill)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-shrek-abaper-sap-engineering-skill-sap-adt-cli
- Seller: https://agentstack.voostack.com/s/shrek-abaper
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
