ARC-1 Tool Reference¶
Complete documentation for all MCP tools available in ARC-1.
ARC-1 exposes 12 intent-based tools designed for AI agents. Instead of 200+ individual tools (one per object type per operation), ARC-1 groups by intent with a type parameter for routing. This keeps the LLM's tool selection simple, with the schema payload guarded by CI budgets and a hyperfocused 1-tool mode for tight context windows.
Experimental aggregate multi-target mode can add one catalog utility, SAPTargets. It is not one
of the 12 core intent tools and is never exposed on /mcp or a pinned target route.
Error intelligence: ARC-1 enriches many SAP ADT failures with concise, actionable hints (for example lock conflicts, enqueue issues, missing authorizations, and transport/corrNr problems). Hints can include SAP transaction references like SM12 (locks), SU53 (authorization), and SE09 (transport checks) to speed up troubleshooting.
SAPTargets (aggregate multi-target only)¶
List the SAP targets that can be selected through /multi/mcp. The tool takes no target parameter
and does not contact SAP. Listing a target proves only that ARC-1 accepted its configuration; it
does not prove that the current user's SAP identity can access it.
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | No | Case-insensitive filter over target IDs and descriptions. Admin results also match destination name, status, code, and message. Maximum 160 characters. |
offset |
integer | No | Admin-only diagnostic-page offset. Follow diagnosticNextOffset when the bounded result is truncated. |
- A reader sees
SAPTargetsonly when more than one target is active. Its compact response contains target IDs, descriptions, andidentity(per-userorshared). - An Admin sees it with zero, one, or many targets, including paged, secret-safe registry and quarantine diagnostics. Destination URLs, credentials, tokens, certificates, and raw Cloud Connector location IDs are never returned. It remains available when registry discovery fails.
- It is never listed on
/<SYSTEM>/<CLIENT>/mcp, an alias-pinned route, or the explicitly configured single-target/mcproute.
See Multi-System Setup for the response shape, privacy boundary, and target-selection behavior.
SAPRead¶
Read the supported SAP ABAP object types listed below.
Use SAPRead for exact implementation behavior, an exact reference, one method body, grep output, inactive drafts, revision history, or metadata. For business purpose, reviews or test design, start with SAPContext(action="deps", type=..., name=...) for available KTD and dependency contracts, then verify source. Compare documented requirements with actual behavior and report mismatches; do not treat existing code as the specification. If KTD is missing, requirements supplied by the user or other documentation still count; without requirements, intent is unverified.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
type |
string | Yes | Object type (see below; includes AUTH, FEATURE_TOGGLE, VERSIONS, VERSION_SOURCE on on-prem systems, ENHO on both, and the server-driven objects DSFD/DESD/EVTB/EVTO/DTSC/CSNM/COTA/DTDC/UIAD/DRTY/APLO/SAJC/SAJT/TABL/DTI where the system advertises them — release-dependent) |
name |
string | No | Object name (e.g., ZTEST_PROGRAM, ZCL_ORDER, MARA) |
action |
string | No | "diff" — return a unified diff between two source versions on this system (only the hunks, not two full sources), using from/to. Source types only: PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, BDEF, SRVD, DDLX, TABL (CDS views are DDLS; classic DDIC VIEW is unsupported — it has no plain-text source). Note: SAP only snapshots a version on transport release, so from/to revision ids are sparse — active vs inactive (pending unactivated changes) is the most reliable use. |
from |
string | No | For action="diff": OLD side — "active" (default), "inactive", a revision id (from a VERSIONS response), or its canonical source/revision URI. URI inputs use the same endpoint, authority, traversal, query, fragment, and control-character checks as versionUri. |
to |
string | No | For action="diff": NEW side — defaults to "inactive". Same accepted values as from. |
fromLabel |
string | No | For action="diff": optional display label for the OLD side in the summary and patch header, e.g. DNT-6-6: Validate discounts (DS7K900123). Does not affect source resolution. |
toLabel |
string | No | For action="diff": optional display label for the NEW side in the summary and patch header, e.g. active or inactive draft. Does not affect source resolution. |
format |
string | No | Output format: "text" (default), "structured", or "editable" (fresh source + SHA-256 for guarded writes; see Source preconditions). For action="diff", structured returns a machine-readable diff envelope; for ordinary reads, structured supports CLAS metadata and DEVC package listings (see below). |
include |
string | No | For CLAS: main, testclasses, definitions, implementations, macros. With method=, an explicit include selects that exact source (including main) before method extraction. For DDLS: elements (extract CDS view elements). For TEXT_ELEMENTS: symbols, selections, or headings — one part of the text pool; omit for the whole PROG/FUGR pool or CLAS symbols. |
method |
string | No | For CLAS: method name to read (e.g., get_name), a qualified local-class method (e.g., lhc_travel~accept), or * to list methods. With no include=, lhc_*/lcl_* automatically read implementations, ltc_* reads testclasses, and other names read MAIN. |
grep |
string | No | Case-insensitive regex; returns only matching source lines (+3 lines of context, with line numbers) instead of the full object — token-efficient search over source-bearing types (PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, BDEF, SRVD, SRVB, SKTD/KTD, DDLX, TABL, VIEW). For CLAS, matches are annotated with the owning class/method; combine with include= to scope a section, but not with method=. For FUGR, grep implies expand_includes and searches each include on its own: matches are grouped under === <include> === with line numbers counted within that include. Falls back to a literal search when the pattern is not valid regex. |
lineStart |
integer | No | First source line (1-based, inclusive); requires lineEnd. Supports PROG, CLAS, INTF, FUNC, INCL, DDLS, DCLS, BDEF, SRVD, DDLX and TABL. CLAS include selects one source section. Plain text only: do not combine with grep, method, diff, structured/editable output, signature or element extraction. Draft/version notices precede the numbered source. |
lineEnd |
integer | No | Last source line (inclusive); requires lineStart. Clamped to the source end; a start beyond the source is an error. |
expand_includes |
boolean | No | For FUGR: expand include source inline, up to 80 source blocks (including main) and five include levels. grep implies this expansion; see Function-group source search. |
group |
string | No | For FUNC, and for VERSIONS or API_STATE with objectType="FUNC": function group name; resolved through search when omitted, including namespaced functions and SAP_BASIS 750's decorated search names. |
versionUri |
string | No | For VERSION_SOURCE: canonical source/revision URI from a VERSIONS response (revisions[].uri). Only known source endpoint shapes are accepted; unrelated ADT endpoints, absolute URLs, authority changes, dot segments, queries, fragments, controls, encoded backslashes, and ambiguous nested encodings are rejected. Encoded slashes remain valid inside namespaced ABAP object names. |
maxRows |
number | No | For TABLE_CONTENTS/TABLE_QUERY: requested row cap (default 100, clamped to 10,000). Wide results can hit the server's cumulative byte ceiling at fewer rows. For TABLE_CONTENTS, SAP can return N+1 (observed on 758 and BTP ABAP); prefer TABLE_QUERY when an exact cap matters. |
maxResults |
number | No | For DEVC: maximum package objects to list (default 200, clamped to 1–1000). SAP may truncate larger packages at the requested limit. |
sqlFilter |
string | No | Legacy TABLE_CONTENTS condition. Do not rely on it for portable automation: the 758 endpoint expects a different SELECT-shaped payload, so condition-only filters are unusable there. Prefer TABLE_QUERY where. |
columns |
array | No | For TABLE_QUERY: fields to project; omit for all columns. Example: ["MANDT","MATNR"]. |
where |
array | No | For TABLE_QUERY: ANDed {field,op,value?} conditions. Operators: =, !=, <>, <, <=, >, >=, LIKE, NOT LIKE, IN, NOT IN, IS NULL, IS NOT NULL. IN values are bare comma-separated values; ARC-1 quotes/escapes them. On 758 use <>, because accepted != is sent unchanged and SAP rejects it. |
source |
string | No | SYNTAX only: proposed source to check without saving. |
objectType |
string | No | Required for SYNTAX: repository type (e.g. CLAS, PROG, DDLS). For API_STATE: SAP object type (CLAS, INTF, PROG, FUGR, FUNC, etc.) — auto-detected from name if omitted; FUNC also uses group |
version |
string | No | Object version: active, inactive, or auto. Source-bearing types default to active, except SMBC and server-driven objects, where omitted/auto uses SAP's developer view (TABL/DTI explicitly prefers pending source) and explicit active/inactive must be confirmed by metadata. TABL/DTT settings also prefer pending state and verify explicit versions. ENHO uses the developer view and refuses explicit version selection. For DTEL/ENQU metadata, omitted and auto use SAP's developer view; explicit active or inactive is passed to SAP. See Active vs Inactive Source below. |
force_refresh |
boolean | No | For source reads: bypass the cached source AND the inactive-list cache before reading. Use when you know the object changed outside ARC-1 in a way conditional GET can't catch. |
includeSignature |
boolean | No | For FUNC only. When true, response is JSON {source, signature: {importing[], exporting[], changing[], tables[], exceptions[], raising[]}, processingType?, updateTaskKind?} — each parameter parsed into {kind, name, type, byValue?, default?, optional?}; processingType reports normal/rfc/update (a metadata read, so it may add propertiesError instead if that GET fails). Default false (returns plain source body). See SAPWrite for FUNC for the round-trip. |
Read-only syntax checks¶
Prefer SAPRead(type="SYNTAX", objectType="CLAS", name="ZCL_ORDER") for a SAP syntax check.
Use version="inactive" after saving a draft, or pass source to check proposed text without
saving it. Omission checks the active version. The object must already exist; checked:false
means SAP did not validate it, even if there are no native findings. With source, ARC-1 first
reads the object's metadata and returns checked:false when SAP answers 404: for an absent
program SAP would otherwise check the text as a standalone include without program attributes
(fixed-point arithmetic off) and report false errors such as every @ host variable. This does not activate or
execute code. Results match the compatible SAPDiagnose(action="syntax", type=..., name=...) route.
Only type, objectType, name, version and source apply. name and objectType are required;
version="auto", include/method selection, diff, and non-default output formats are refused.
Harmless strict-client filler (false flags, empty arrays, format="text", maxResults=0) is ignored.
Empty or whitespace-only source is normalized as omitted, matching the legacy route; use
non-empty text for an unsaved-source check. The alias inherits the legacy type limitations:
FUNC syntax routing is unsupported, and inline JSON server-driven objects may return not-processed
instead of findings; this route adds no new backend type support.
The standard SAPRead tool advertises readOnlyHint:true; clients decide whether that affects
approval. SAPDiagnose remains mixed and hyperfocused SAP remains unannotated. Existing SAP_DENY_ACTIONS rules for SAPDiagnose or
SAPDiagnose.syntax, including hyperfocused SAP.diagnose, also block this alias. SAPRead.SYNTAX can block the alias alone.
Supported types:
| Type | Description |
|---|---|
PROG |
Program source |
CLAS |
Class source |
INTF |
Interface source |
FUNC |
Function module source |
FUGR |
Function group structure (function modules + includes). Uses /functions/groups/{g}/objectstructure, falling back to the generic /repository/objectstructure on releases that don't ship it (NW 7.50/7.51). |
INCL |
Include source |
DDLS |
CDS view source |
DCLS |
CDS access control source (authorization rules for CDS views) |
DDLX |
CDS metadata extension (UI annotations for Fiori Elements) |
BDEF |
Behavior definition |
SRVD |
Service definition |
SRVB |
Service binding (structured JSON: OData version, binding type, publish status) |
SMBC |
Business Configuration Maintenance Object: native JSON, available on 758/816 and BTP. SMBC/TYP is accepted. Omitted/auto uses SAP’s developer view; explicit versions are verified. Transport check/history are supported; SMBC source writes are not. |
SKTD / KTD |
Knowledge Transfer Document attached to an ABAP object. Returns Markdown decoded from the ADT XML envelope, one ## <node id> section per documented node when routing is needed (BDEF entities, savers, actions, functions, …). A heading that names a node — its id, or the node name the index prints — is reserved routing syntax; a colliding heading inside stored body text is reversibly shown with one leading \. Behind a reserved HTML-comment marker, the response lists populated per-node short texts and a compact index of EVERY writable node, each by the spelling that resolves back to it (the name, or the full id when only that does), with the empty ones on an empty (n): line. Add a ## <name> section above the marker to document one; use shortTexts to update its short text. Start multi-node edits from the complete SAPRead result; a standalone ## <object name> is refused when it could instead be a visible root title (use # <object name> for that title). SAPWrite ignores the marker and context below it; the writable Markdown still follows the requested active/inactive version semantics. Documented non-writable sections can pass through unchanged while attempted edits remain refused. KTD is a friendly alias; SKTD remains the canonical SAP object type. |
TABL |
DDIC TABL — covers both transparent tables (T000-style) and DDIC structures (BAPIRET2-style). Returns CDS-like source. ARC-1 auto-resolves the URL: tries /sap/bc/adt/ddic/tables/{name} first, falls back to /sap/bc/adt/ddic/structures/{name} on 404. There is no separate STRU type — TABL is the canonical short type for both, mirroring TADIR R3TR TABL and abapGit conventions. |
TABL/DTT |
Technical settings of a transparent table; name is the table name. Returns working state, editable source, and read-only storage/logging fields. See Technical table settings. |
TTYP |
DDIC table type (on-prem and BTP where discovered). Returns {name, description, rowType, rowTypeKind, rowTypeLength, rowTypeDecimals, accessType, keyKind, plainStandardTable, package}. Key components and secondary keys are not listed; plainStandardTable is false when the table type has them or is not a standard table with a non-unique standard key. Written via SAPWrite(type="TTYP") — the create POSTs a CHAR shell and a follow-up PUT sets the real row type. |
ENQU |
DDIC lock object (on-prem and BTP; ENQU/DL accepted). Returns {name, description, package, version, allowRFC, primaryTable, secondaryTables, lockParameters, lockModules} — tables carry {tableName, lockMode}, parameters {parameterName, tableName, fieldName, parameterWanted}, and lockModules lists the generated ENQUEUE_/DEQUEUE_ function modules. Omitted version returns SAP's developer view. Written via SAPWrite(type="ENQU") — see Lock object writes. |
VIEW |
DDIC view |
DOMA |
Domain metadata (structured JSON: data type, length, fixed values, value table) |
DTEL |
Data element metadata (structured JSON: type, labels and their reserved lengths, search help and its parameter, SET/GET parameter, change-document and bidi flags, and deactivateInputHistory). Omitted version and auto return SAP's developer view so pending drafts remain visible; explicit active or inactive is passed to SAP. |
AUTH |
Authorization field metadata (structured JSON: role name, check table, domain, conversion exit, org-level info) |
FEATURE_TOGGLE |
Feature toggle states (structured JSON: toggle state per system from SAP switch framework). Renamed from FTG2 in audit Plan B (docs/research/abap-types/types/ftg2.md) — FTG2 remains a deprecated alias with a stderr warning; use FEATURE_TOGGLE. |
ENHO |
Enhancement metadata; BAdI implementation classes or hook locations plus ABAP source. See enhancement reads. |
VERSIONS |
Revision history for an ABAP object. Returns JSON: { object: { name, type }, revisions: [{ id, author, timestamp, transport?, uri }] }. Optional include for CLAS and group for FUNC. On-prem only. |
VERSION_SOURCE |
Source code at a specific revision. Pass versionUri from a VERSIONS response. Returns raw source text. On-prem only. |
DESD |
CDS Logical External Schema — server-driven object (generic AFF read). Returns JSON: parsed blue:blueSource metadata (name, type, description, package, language, version, …) + the AFF JSON source. SAP_BASIS 8.16+ (ABAP Platform 2025), discovery-gated. |
EVTB |
RAP Event Binding — server-driven object. JSON metadata + AFF JSON source (boName, boOperation, events[]). Available on S/4HANA 2023 (758) and 8.16+. |
EVTO |
RAP Event Object — server-driven object. 8.16+. |
DTSC |
CDS Static Cache (table-entity buffer) — server-driven object. JSON metadata + DDL text source (define static cache …). 8.16+. |
CSNM |
Core Schema Notation Model (CSN) — server-driven object. 8.16+. |
COTA |
Communication Target — server-driven object. 8.16+. |
DSFD |
CDS Scalar Function Definition — server-driven object. JSON metadata + DDL text source (define scalar function …). Available on S/4HANA 2023 (758) and 8.16+. |
UIAD |
Launchpad App Descriptor Item (LADI) — server-driven object. Discovery-gated; available on 8.16 and supported 758 backports. The successor to the deprecated tile/target-mapping model and the unit SAP Build Work Zone content exposure v2 federates. AFF JSON source carries generalInformation (appType, catalogId, transaction), navigation (targetMappingId, semanticObject, action, form factors) and tiles[]. Find names via SAPRead type=DEVC on the owning package (listed as UIAD/TYP — pass the bare UIAD). |
DTDC |
CDS Dynamic Cache — server-driven object with its OWN metadata format (<dtdc:dtdcSource>, not blue:blueSource). JSON metadata + DDL text source (define dynamic cache …). Available on S/4HANA 2023 (758) and 8.16+. |
DRTY |
CDS Type — server-driven object. JSON metadata + DDL text source (define type …). Covers scalar types and enumerated types alike; both report DRTY/STY. |
APLO |
Application Log Object — server-driven object. AFF JSON source: header + subobjects[] (required by the AFF schema; may be empty) (name, description). Names are limited to 20 characters. Saves are active immediately. Verified on SAP_BASIS 758 and 816. |
SAJC |
Application Job Catalog Entry — server-driven object (blues v2). AFF JSON source: generalInformation.className (the class implementing IF_APJ_DT_EXEC_OBJECT/IF_APJ_RT_EXEC_OBJECT) + parameters[]. SAP derives parameters from the class; 758 does not expose that list in its AFF readback. Verified on 758 and 816. |
SAJT |
Application Job Template — server-driven object (blues v2). AFF JSON source: generalInformation.catalogName + parameters.singleValueParameters[] / valueRangesParameters[] (default values). Verified on 758 and 816. |
TRAN |
Transaction metadata (structured JSON: code, description, program) |
SOBJ |
BOR business object (list methods, or read specific method with method param) |
BSP |
BSP/UI5 filestore. List apps without name; browse or read with name="<app>" and optional case-sensitive include="<path>". name="<app>/<path>" is also accepted. |
API_STATE |
API release state (clean core compliance — contract states C0-C4, successor info) |
TABLE_CONTENTS |
Legacy table preview. Useful for an unfiltered sample; filtering and exact row caps are backend-dependent (see parameters above). Prefer TABLE_QUERY for deterministic structured projection/filtering. With experimental SAP_BLOCKED_DATA_SOURCES active, only unfiltered requests are supported — a sqlFilter returns DATA_SQL_UNSUPPORTED, so use TABLE_QUERY. |
TABLE_QUERY |
Structured table/CDS query through data preview (columns, where, maxRows); requires the data-preview gate. A configured experimental source blocklist checks direct and transitive active CDS/replacement lineage before execution. |
DEVC |
Package contents |
SYSTEM |
ADT discovery collections and configured/token-derived user ({user, collections}). It does not return SID, release, kernel, or prove the SAP login identity; use COMPONENTS for installed releases. |
COMPONENTS |
Installed software components |
MSAG |
Message class metadata (structured JSON with number, shortText, longText per message). MSAG is the canonical TADIR R3TR short type (added in audit Plan B — docs/research/abap-types/types/msag.md). |
MESSAGES |
Deprecated alias for MSAG. Still accepted with a stderr warning; use MSAG going forward. |
TEXT_ELEMENTS |
Text elements for PROG, CLAS, or FUGR, selected with objectType; see Text elements. |
VARIANTS |
Program variants |
INACTIVE_OBJECTS |
List all objects pending activation for the calling user (no name needed). Returns rich metadata: name, type, uri, description?, user, deleted, transport, parentTransport. |
For a global class declaration (INTERFACES, INHERITING FROM) or its implementation,
read MAIN: omit include or use include="main". definitions and implementations
contain local helper classes, not the global declaration and implementation split apart.
An empty local include does not mean the global class has no declarations. For a targeted
check use, for example, SAPRead(type="CLAS", name="ZCL_ORDER", grep="INTERFACES|INHERITING").
This checks source declarations; it does not enumerate subclasses or prove runtime calls.
Package listings (DEVC):
Requires SAP to advertise the packageName quick-search filter; otherwise ARC-1 refuses the listing because older search providers can return unrelated objects.
SAPRead(type="DEVC", name="ZPKG") keeps the JSON array in the first text block
and adds a second JSON text block with listing metadata. Use
format="structured" for one JSON object, {objects: [...], listing: {...}}.
Existing first-block array consumers and the public client's getPackageContents
array API retain their contracts. Consumers that concatenate text blocks before
JSON parsing should switch to the structured format.
listing reports returned, effectiveLimit (default 200, clamped to 1–1000),
limitReached, possiblyTruncated, completeness: "unknown", total: null,
coverage: "adt-search", and an explanatory note. Reaching the cap suggests
possible truncation; it does not prove additional objects exist. Below the cap,
possiblyTruncated: false only means the requested limit was not reached. ADT
search can omit repository types, so even an empty result is not proof of a
complete inventory. There is no continuation token or fabricated total. Raise
the limit up to 1000 or use targeted searches when the cap is reached.
Structured class format:
When format="structured" is used with CLAS type, the response is a JSON object with:
- metadata — class metadata (description, language, category, package, fixPointArithmetic, abapLanguageVersion)
- main — main class source code
- testclasses — test class source (or null if none)
- definitions — local definitions (or null)
- implementations — local implementations (or null)
- macros — macros (or null)
This is useful when you need to understand class structure or separate test code from production code.
Examples:
SAPRead(type="PROG", name="ZTEST_REPORT")
SAPRead(type="CLAS", name="ZCL_ORDER", include="testclasses")
SAPRead(type="CLAS", name="ZCL_ORDER", format="structured") — JSON with metadata + decomposed source
SAPRead(type="CLAS", name="ZCL_ORDER", method="*") — list all methods
SAPRead(type="CLAS", name="ZCL_ORDER", method="get_name") — read a specific method
SAPRead(type="CLAS", name="ZBP_TRAVEL", method="lhc_travel~accept") — auto-route a RAP handler to implementations
SAPRead(type="CLAS", name="ZCL_ORDER", method="setup", include="testclasses") — extract one method from an explicit include
SAPRead(type="CLAS", name="ZCL_ORDER", grep="select.*from") — matching lines only, annotated by method
SAPRead(type="CLAS", name="ZCL_ORDER", include="text_symbols") — maintained text pool (see Text elements)
SAPRead(type="PROG", name="ZTEST_REPORT", grep="WRITE") — search source, returns matches + context
SAPRead(type="PROG", name="ZTEST_REPORT", lineStart=40, lineEnd=55) — raw line window, e.g. around an ATC finding
SAPRead(type="DDLS", name="ZI_TRAVEL", include="elements") — extract CDS view elements
SAPRead(type="DCLS", name="ZI_TRAVEL_DCL") — CDS access control source
SAPRead(type="DDLX", name="ZC_TRAVEL") — metadata extension with UI annotations
SAPRead(type="SRVB", name="ZUI_TRAVEL_O4") — service binding metadata as JSON
SAPRead(type="KTD", name="ZCL_ORDER") — read the object's Knowledge Transfer Document as Markdown
SAPRead(type="FUGR", name="ZUTILS", expand_includes=true) — function group with bounded include expansion
SAPRead(type="FUGR", name="ZUTILS", grep="ENQUEUE_") — matches per include, not the whole include tree
SAPRead(type="TABL", name="BAPIRET2") — DDIC structure (auto-resolved to /structures/)
SAPRead(type="TABL", name="T000") — transparent table (auto-resolved to /tables/)
SAPRead(type="DOMA", name="BUKRS") — domain metadata with fixed values
SAPRead(type="DTEL", name="MANDT") — data element metadata with labels
SAPRead(type="AUTH", name="BUKRS") — authorization field metadata
SAPRead(type="FEATURE_TOGGLE", name="ABC_TOGGLE") — feature toggle states (FTG2 still works as deprecated alias)
SAPRead(type="MSAG", name="SY") — message class (MESSAGES still works as deprecated alias)
SAPRead(type="ENHO", name="ZMY_BADI_IMPL") — BAdI metadata; hook implementations also return source
SAPRead(type="VERSIONS", name="ZARC1_TEST_REPORT") — list object revisions with revision URIs
SAPRead(type="VERSIONS", name="ZCL_X", include="definitions") — list revisions for CLAS definitions include
SAPRead(type="VERSION_SOURCE", versionUri="/sap/bc/adt/programs/programs/ZARC1_TEST_REPORT/source/main/versions/20260410185851/00000/content") — fetch source at one revision
SAPRead(type="CLAS", name="ZCL_ORDER", action="diff") — diff active vs your inactive draft (pending changes)
SAPRead(type="CLAS", name="ZCL_ORDER", action="diff", from="00001", to="active") — diff a revision against the active version
SAPRead(type="CLAS", name="ZCL_ORDER", action="diff", from="00001", to="active", fromLabel="DNT-6-6 (DS7K900123)", toLabel="active") — readable diff headers
SAPRead(type="TRAN", name="SE38") — transaction metadata
SAPRead(type="SOBJ", name="BUS2032") — list BOR object methods
SAPRead(type="BSP") — list all BSP/UI5 apps
SAPRead(type="BSP", name="ZAPP", include="WebContent") — browse a case-sensitive repository path
SAPRead(type="BSP", name="/UI2/USHELL/chips") — browse a namespaced app with an appended path
SAPRead(type="API_STATE", name="CL_SALV_TABLE") — check if class is released for ABAP Cloud
SAPRead(type="API_STATE", name="IF_HTTP_CLIENT") — check interface release state
SAPRead(type="API_STATE", name="MARA", objectType="TABL") — check table with explicit type
SAPRead(type="API_STATE", name="Z_MY_FM", objectType="FUNC") — function module; group resolved via search, or pass group="ZFG"
SAPRead(type="TABLE_CONTENTS", name="MARA", maxRows=10) — legacy unfiltered preview; SAP may return 11 rows
SAPRead(type="TABLE_QUERY", name="MARA", columns=["MANDT","MATNR"], where=[{field:"MANDT",op:"=",value:"001"}], maxRows=10)
SAPRead(type="SYSTEM")
SAPRead(type="INACTIVE_OBJECTS") — list objects pending activation
Data-preview cells are strings and preserve SAP’s whitespace, including leading blanks and numeric
padding. SAPQuery.executedQueryString preserves SAP’s SQL echo; it is not a capture of the submitted request.
For TABLE_QUERY on 758, use op:"<>" for inequality. Although the current input schema also accepts
!=, ARC-1 sends it unchanged and that backend rejects it; normalization is tracked as a focused
follow-up.
Function-group source search¶
SAPRead(type="FUGR", name="ZUTILS", grep="ENQUEUE_|AUTHORITY-CHECK") reads the group
and its nested includes, then returns matching lines with context. expand_includes=true
is optional when using grep. Each source has its own heading and local line numbers;
the response shows up to 100 matching lines across all sources and counts all matches
in the sources searched.
Expansion stops at 80 source blocks (main included) or five include levels. The response
warns when either limit leaves includes unsearched and names includes that could not be
read. A partial search cannot establish that the whole group has no matches: large groups
can hit the limit before reaching function-module bodies. Follow up with a known include,
SAPRead(type="INCL", name="LZUTILSU01", grep="..."), or a function module,
SAPRead(type="FUNC", group="ZUTILS", name="Z_UTIL", grep="...").
Enhancement reads¶
SAPRead(type="ENHO", name="...") reads BAdI metadata and source-code plug-ins on
on-prem systems. Hook implementations additionally return source, enhancedObject
and hookImplementations (positions, program/method names, overwrite flags and
navigation links). A failed source read returns an error, not successful partial metadata.
ARC-1 resolves a different enhancement subtype through repository search only after
an unsupported BAdI read. This needs search permission as well as read permission.
Some other enhancement implementations still fail inside SAP; use SE80/SE19 or Eclipse's SAP GUI
integration when the error identifies an unavailable ADT route. Only BAdI implementations
are writable (BAdI implementation writes); ENHO source filtering
(grep, method or line selection) is not supported.
ENHO preserves SAP's unversioned developer view: omit version or use auto.
Explicit active/inactive selection is refused because its behavior is not verified
for these resources. Metadata and source are separate reads, not an atomic snapshot.
Active vs Inactive Source¶
For ordinary ABAP/CDS source reads, version chooses between the activated source and the
calling user's unactivated draft as follows. ENHO and
technical table settings have separate rules; SMBC and
server-driven types follow the developer-view rules below.
version |
Behaviour |
|---|---|
active (default) |
Reads the last activated source. If the user has an unactivated draft (created in Eclipse/SE80, not yet activated), the response is prefixed with a one-line note flagging the draft so the LLM knows there's a gap and can re-read with version='inactive' if appropriate. |
inactive |
Reads the user's draft directly. If no draft exists, SAP falls back to the active source and the response is prefixed with: "No inactive draft exists for this object on the server. Returning the active version." |
auto |
Resolves client-side via the cached inactive-objects list: returns the draft if one exists, otherwise active. No warning is prefixed (the caller explicitly opted into "show me my view"). |
SMBC and server-driven types (such as DRTY, DESD, DTDC and UIAD) preserve their developer view when
version is omitted or auto: SAP selects the draft when available, otherwise active. They bypass
source and inactive-list caches. Explicit active/inactive is sent to both metadata and source;
if metadata reports another version or no version, ARC-1 returns an error without source. This
includes an inactive-only new object requested as active, and an active-only object requested as
inactive. UIAD saves are immediately active on the verified 816 system, so use active or auto.
Version-query errors propagate; ARC-1 does not retry a different version. The two reads are not an
atomic snapshot against concurrent activation.
DTEL/ENQU metadata uses SAP's version-less developer view when version is omitted or set to auto, so a
plain read after SAPWrite returns the pending draft. Pass active to request the last activated metadata or
inactive to request the draft explicitly; SAP can return active metadata when no draft exists.
SAPRead(type="CLAS", name="ZCL_ORDER") — active source (default)
SAPRead(type="CLAS", name="ZCL_ORDER", version="inactive") — your draft
SAPRead(type="CLAS", name="ZCL_ORDER", version="auto") — draft if it exists, else active
Cache Behaviour¶
For cache-supported source reads, ARC-1 uses the SAP-emitted ETag; format="editable" bypasses this cache. On the next read, ARC-1 sends If-None-Match so the server itself confirms freshness:
304 Not Modified→ cached body is still authoritative; response is prefixed with[cached:revalidated].200 OKwith new body and ETag → cache is replaced; no prefix on the response.404/410→ cache entry is invalidated and the error is propagated.
External writes (Eclipse activations, gCTS pulls, abapGit imports) are normally caught on the next conditional GET. On instances without principal propagation, the captured draft can be served as active for up to 120 seconds after an activation without revalidation. With SAP_PP_ENABLED=true, including mixed PP/API-key instances, activations invalidate instead; see cache security. To force a fresh fetch and bypass the cache for one read, pass force_refresh: true.
The full caching architecture (per-version cache keys, conditional GET, pure parse memoization, inactive-list session cache, write invalidation) is documented in Caching System.
SAPSearch¶
Search for ABAP objects by name pattern, exact object-directory names, or ABAP source text.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
query |
string | No | Search pattern (e.g., ZCL_ORDER*, Z*TEST*), source text, or comma/whitespace-separated names for tadir_lookup |
maxResults |
number | No | Maximum results (default 100) |
searchType |
string | No | object (default, name search), tadir_lookup (exact cross-package object lookup), or source_code (text search within ABAP source) |
names |
array | No | For tadir_lookup: exact object names to resolve across packages |
objectTypes |
array | No | For tadir_lookup: optional ADT/TADIR type filters such as TABL, DDLS, BDEF, SRVB, CLAS/OC |
objectType |
string | No | For normal/object search: SAP applies this ADT type filter before maxResults; slash subtypes such as CLAS/OC stay intact. Older releases (verified on 7.50) may ignore the subtype portion. For source_code: filter by object type. For tadir_lookup: single type filter |
source |
string | No | For tadir_lookup only: adt (default), db, or both. db/both require the sql scope and SAP_ALLOW_FREE_SQL=true. See TADIR lookup source modes below. |
packageName |
string | No | For source_code search: filter by package |
Returns: Object type, name, package, and description for each match. tadir_lookup groups exact matches by requested name and includes a missing list. Source code search also returns line numbers and code snippets. When source='both' reveals divergence between the ADT and DB views, the response adds a splitBrain: [name, ...] array and a warnings: [...] array explaining each diverging name.
Examples:
SAPSearch(query="ZCL_ORDER*")
SAPSearch(query="Z*INVOICE*", maxResults=20)
SAPSearch(searchType="tadir_lookup", names=["ZDM_PROJECT_D","ZR_DM_PROJECT"], objectTypes=["TABL","BDEF"])
SAPSearch(searchType="tadir_lookup", query="ZDM_PROJECT_D ZUI_DM_PROJECTS_O4")
SAPSearch(searchType="tadir_lookup", names=["ZR_OLD_VIEW"], source="both") // detect TADIR ghosts after a failed delete
SAPSearch(query="SY-SUBRC", searchType="source_code")
SAPSearch(query="SELECT * FROM mara", searchType="source_code", objectType="CLAS", packageName="ZDEV")
Umlaut handling: Object name queries containing non-ASCII characters (ä, ö, ü, ß) are automatically transliterated to ASCII equivalents (AE, OE, UE, SS). SAP object names are ASCII-only. Source code search preserves non-ASCII characters.
Field names: If searching for a field/column name (e.g., MATNR, BUKRS), use SAPQuery against DD03L instead — SAPSearch only searches object names.
TADIR lookup: Use searchType="tadir_lookup" for reset/create preflights that need to know whether objects exist anywhere, regardless of package. The default source='adt' uses ADT repository quick search, which avoids long IN (...) parser limits and works in read/search-only configurations. The endpoint deliberately filters out TADIR rows that don't resolve to a live workbench resource, so orphan/ghost entries (left behind by aborted create/delete cycles) are invisible to the default path — see the source modes section below.
TADIR lookup source modes¶
source |
Underlying call | Scope required | When to use |
|---|---|---|---|
adt (default) |
GET /sap/bc/adt/repository/informationsystem/search?operation=quickSearch&query=... (one per name) |
read |
Default; workbench-resolvable objects only. Skips TADIR ghost rows by design. |
db |
POST /sap/bc/adt/datapreview/freestyle with SELECT pgmid, object, obj_name, devclass FROM tadir WHERE obj_name IN (…) |
sql (server-side: SAP_ALLOW_FREE_SQL=true) |
One round-trip for any number of names — much faster for large lists, and surfaces orphan TADIR rows the ADT route hides. |
both |
Parallel adt + db calls; merge by (base type, name) with dedupe |
sql |
Explicit split-brain detection. Returns splitBrain: [name, ...] and a warnings array when the two sources disagree (e.g. a TADIR ghost from an aborted create/delete). |
Every match in the result set is stamped with an _origin: 'adt' | 'db' field so callers can colour-code or filter rows by provenance. The 'db' path also covers legacy SEGW types (IWSV/IWMO/IWPR) that the ADT info-system does not return; the URL is left empty for types that aren't addressable via a single ADT base URL (e.g. function modules, which need the parent group).
Source code search availability: Not available on all SAP systems. Requires SICF service activation. If unavailable, falls back with an error suggesting SAPQuery as an alternative.
SAPWrite¶
For local files, use the Codex file workflow to send source through the existing connection without model transcription.
HTTP JSON requests default to 100 KiB. For large source writes, an administrator can set ARC1_MAX_HTTP_REQUEST_BYTES (maximum 16 MiB); see request limits. HTTP 413 reports the byte limit; HTTP 503 asks the client to retry when the shared input budget is full. Smaller batches and method/section edits reduce both payload and memory use. Data-preview response limits are separate; stdio does not use this parser.
Create or update ABAP source code. Handles lock/modify/unlock automatically.
Text-source updates require a non-blank replacement. Omitted/blank source and FUNC input reduced to nothing by SAPGUI comment stripping are refused before locking or writing. Signature-only FUNC updates read the existing body under the lock; metadata updates and explicit text-symbol clearing keep their separate behavior.
NetWeaver < 7.51: ADT writes over HTTP require a stateful session that older releases don't honor, so writes fail with
423 invalid lock handleuntil theabapfs_extensionsenhancement is installed on the SAP system. This is not SAP Note 2727890 (a separate narrow bug). See SAP trial setup → Writes fail with 423 (423 troubleshooting section). S/4HANA (≥ 7.51) is unaffected.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | create, update, delete, edit_method, edit_unit, add_unit (on-prem), edit_class_definition, add_method, edit_method_signature, delete_method, change_method_visibility, batch_create, scaffold_rap_handlers, generate_behavior_implementation, or edit_text_symbols. edit_unit replaces one FORM or MODULE in a PROG/INCL; add_unit inserts a new one; see Procedural unit surgery. The class-section surgery actions (edit_class_definition, add_method, edit_method_signature, delete_method, change_method_visibility) are token-efficient edits to a global class without re-sending /source/main. See Class-section surgery below. edit_text_symbols writes one part of a CLAS/PROG/FUGR text pool — see Text elements. |
type |
string | No | PROG, CLAS, INTF, FUNC, FUGR, INCL, DDLS, DCLS, DDLX, BDEF, SRVD, SRVB, SKTD/KTD, TABL, TTYP, TABL/DT, TABL/DS, TABL/DTT (update only), DOMA, DTEL, ENQU, ENHO (BAdI implementations), MSAG (for single object actions; availability is adapted for BTP vs. on-prem), plus the server-driven objects DESD/EVTB/DTSC/CSNM/EVTO/COTA/DSFD/DTDC/UIAD/DRTY/APLO/SAJC/SAJT/TABL/DTI (see Server-driven object writes). Slash/case aliases are auto-normalized (e.g., CLAS/OC or clas → CLAS; KTD → SKTD). |
group |
string | No | For FUNC: parent function-group name. Required for FUNC create (the FUGR must already exist — create it first via SAPWrite type=FUGR). Auto-resolved via search for FUNC update/delete if omitted. For INCL: addresses a structural include inside this function group; supported by create, update, delete, edit_unit, and add_unit. Ignored for other types. |
rowType |
string | No | TTYP create/update: the row type — a built-in ABAP type (STRING, I, …) or a DDIC type name such as BAPIRET2. Required for create. An update without it keeps the stored row type where ARC-1 can; see table type updates. |
rowTypeKind |
string | No | TTYP only: builtin or structure. Omit it and ARC-1 infers from rowType; pass it explicitly when SAP knows a built-in type ARC-1 has not enumerated. An update keeps the stored kind while the row type is unchanged. |
rowTypeLength |
integer | No | TTYP create/update: built-in row length and decimal places, including batch items. Use rowTypeKind="builtin" for DDIC built-ins such as CHAR/DEC. Each accepts 0–999999; SAP may accept a value at save, then reject or normalize it at activation; inspect activation warnings and read back the active definition. Omitted update fields keep their stored values only while both row name and kind stay unchanged. Dictionary row dimensions are resolved by SAP and cannot be set here. length/decimals remain DOMA/DTEL fields. |
rowTypeDecimals |
integer | No | TTYP built-in decimal places; same validation and update semantics as rowTypeLength. Explicit zero clears the scale. |
processingType |
string | No | On-prem FUNC create only: normal, rfc (Remote-Enabled), or update. Omit it to preserve the legacy SAP-default behavior. |
updateTaskKind |
string | No | Required when processingType="update": startImmediate (V1 restartable), immediateStartNoRestart (V1 non-restartable), or startDelayed (V2). Rejected for normal/RFC modules. |
parameters |
array | No | FUNC structured signature: {kind,name,type?,byValue?,default?,optional?} rows for importing/exporting/changing/tables/exceptions/raising. ARC-1 builds and splices the clauses; omit to send source verbatim. |
name |
string | No | Object name (for single object actions) |
expectedSourceHash |
string | No | SHA-256 from SAPRead(format="editable"); rejects changed source under the SAP lock before an update or class/procedural edit. Omitted/null/blank: no protection against stale replacements across calls. See Source preconditions. |
source |
string | No | ABAP source code. For create/update: full source body. For edit_method: new method body. For edit_unit/add_unit: the complete replacement/new FORM … ENDFORM. or MODULE … ENDMODULE. block. For edit_class_definition without include=: ONLY the new global CLASS … DEFINITION … ENDCLASS. block (~10–80 lines instead of full class). For edit_class_definition with include=: the FULL replacement body of that class-local include; for include="testclasses" this normally includes both local CLASS ltc_* DEFINITION and CLASS ltc_* IMPLEMENTATION. For edit_method_signature: ONLY the new METHODS clause for one method (~1–5 lines). Not used by add_method/delete_method/change_method_visibility — pass the method clause/name and target visibility via method/visibility instead. |
include |
string | No | For CLAS write actions update, edit_method, and edit_class_definition: write a class-local include (definitions, implementations, macros, or testclasses) instead of /source/main. Omit this parameter for main class source updates. add_method/edit_method_signature/delete_method/change_method_visibility operate on the global class /source/main only and reject include=. Include writes create an inactive draft; verify with SAPRead(version="inactive") until activation. NOTE: edit_class_definition with include= skips the symmetry refuse-policy (cross-include validation is not performed; rely on SAPActivate to catch breaks). Auto-init: whole-include writes (update and edit_class_definition with include=) create the target include automatically if it does not exist yet — notably testclasses (CCAU) on a freshly-created class. No separate init step or user-supplied lock handle is needed; the success message notes when ARC-1 initialized it. |
textPart |
string | No | For edit_text_symbols: which part of the textpool to write — symbols (default; the numbered TEXT-nnn literals), selections (a report's selection texts — the labels beside PARAMETERS/SELECT-OPTIONS), or headings (list header and column headers). A class has only symbols; PROG and FUGR have all three. On BTP, this action requires type="CLAS" and supports only symbols (or an omitted part). Read first with SAPRead(type="CLAS", include="text_symbols"). |
method |
string | No | For edit_method/edit_method_signature/delete_method/change_method_visibility: method NAME (e.g., "get_name", "zif_order~process", "lhc_project~approve_project"). For add_method: the full METHODS CLAUSE as ABAP source (e.g., "METHODS greet IMPORTING who TYPE string RETURNING VALUE(r) TYPE string."). |
unit |
string | No | For on-prem edit_unit/add_unit: existing/new case-insensitive FORM or MODULE name (for example "PROCESS_ORDERS" or "STATUS_0100"). |
visibility |
string | No | For add_method: target visibility section — public (default), protected, or private. For change_method_visibility: target visibility section (required). The section header must already exist in the DEFINITION block; if not, ARC-1 refuses with a hint to use edit_class_definition first. |
abstract |
boolean | No | For add_method: when true, only the METHODS clause is inserted into DEFINITION — no METHOD/ENDMETHOD stub is added to IMPLEMENTATION. Default false. |
bdefName |
string | No | For scaffold_rap_handlers: interface BDEF name used to derive required handler signatures. For generate_behavior_implementation: optional override; default discovery reads the class metadata's <class:rootEntityRef> to locate the BDEF automatically. |
autoApply |
boolean | No | For scaffold_rap_handlers: when true, create missing lhc_* skeletons, inject missing signatures plus empty method stubs into the behavior pool, and write back. Not used by generate_behavior_implementation (which always applies; use dryRun=true there to preview). |
targetAlias |
string | No | For scaffold_rap_handlers and generate_behavior_implementation: optional RAP entity alias filter (scaffold only one alias/handler class) |
activate |
boolean | No | For generate_behavior_implementation: when true (default), runs SAPActivate on the class after writing. When false, only the source is written. Activation failures matching the well-known Local classes of CL_ABAP_BEHAVIOR_HANDLER… stale-active coupling do not throw — they return activation.success=false with a guided recovery hint so the just-written CCDEF/CCIMP source remains useful. |
dryRun |
boolean | No | For generate_behavior_implementation: when true, runs discovery + cross-validation + scaffold planning and returns the report without writing or activating. Use this to preview what would change. For SKTD/KTD update: runs the identical validation of source and shortTexts and reports which nodes would change and which keep their text, without a PUT. |
description |
string | No | Object description for create (defaults to name if omitted, max 60 chars) |
package |
string | No | Package for new objects (default $TMP) |
transport |
string | No | Transport request number. For update and delete, if omitted ARC-1 auto-uses the correction number returned by the SAP lock (if any). Explicit value takes precedence. |
lintBeforeWrite |
boolean | No | Override server lint setting for this call (false to bypass pre-write lint) |
preflightBeforeWrite |
boolean | No | Override deterministic RAP preflight checks for this call (false to bypass TABL/BDEF/DDLX/DDLS static checks) |
checkBeforeWrite |
boolean | No | Override the server SAP-side pre-write syntax check. When true, diagnostics are appended but do not block the write; activation remains definitive. |
dataType |
string | No | DOMA/DTEL: ABAP data type (CHAR, NUMC, DEC, ...) |
length |
number | No | DOMA/DTEL: data type length |
decimals |
number | No | DOMA/DTEL: decimal places |
outputLength |
number | No | DOMA: output length |
conversionExit |
string | No | DOMA: conversion exit (e.g., ALPHA) |
signExists |
boolean | No | DOMA: whether signed values are allowed |
lowercase |
boolean | No | DOMA: whether lowercase characters are allowed |
fixedValues |
array | No | DOMA: fixed value ranges. Each entry has required low and optional high (max 10 characters each), and optional description (max 60). Oversized entries are rejected before any write, including in batch_create. |
valueTable |
string | No | DOMA: value table reference (e.g., T001) |
typeKind |
string | No | DTEL: domain or predefinedAbapType |
typeName |
string | No | DTEL: referenced domain/type name (for typeKind="domain") |
domainName |
string | No | DTEL alias for typeName when referencing a domain. |
shortLabel |
string | No | DTEL: short field label |
shortLength |
integer | No | DTEL: reserved short-label length (0–10) |
mediumLabel |
string | No | DTEL: medium field label |
mediumLength |
integer | No | DTEL: reserved medium-label length (0–20) |
longLabel |
string | No | DTEL: long field label |
longLength |
integer | No | DTEL: reserved long-label length (0–40) |
headingLabel |
string | No | DTEL: heading field label |
headingLength |
integer | No | DTEL: reserved heading length (0–55) |
searchHelp |
string | No | DTEL: search help name |
searchHelpParameter |
string | No | DTEL: search help parameter |
setGetParameter |
string | No | DTEL: SET/GET parameter ID |
defaultComponentName |
string | No | DTEL: default component name |
deactivateInputHistory |
boolean | No | DTEL: true disables SAP GUI input history for fields using the data element; false does not suppress it |
changeDocument |
boolean | No | DTEL: change document flag |
messages |
array | No | MSAG: message entries ([{number, shortText, longText?}]) — number is a 3-digit string (e.g., "001"), shortText is the message text (max 73 chars) |
serviceDefinition |
string | No | SRVB: referenced service definition name (SRVD). Required for SRVB create. |
bindingType |
string | No | SRVB: binding type (default ODATA) |
odataVersion |
string | No | SRVB OData protocol version, V2 (default) or V4; overrides the value inferred from bindingType. |
category |
string | No | SRVB: binding category (0 = UI, 1 = Web API; default 0) |
version |
string | No | SRVB: service version for binding metadata (default 0001) |
refObjectType |
string | No | Required for SKTD/KTD create: parent ADT type/subtype such as DDLS/DF, BDEF/BDO, SRVD/SRV, DEVC/K, or SMBC/TYP (Business Configuration Maintenance Object). |
refObjectName |
string | No | SKTD/KTD create: documented parent name; defaults to name. |
refObjectDescription |
string | No | SKTD/KTD create: parent description shown in ADT tooltips; required and nonempty for SMBC/TYP. |
shortTexts |
array | No | SKTD/KTD update/create: [{node, text}], where node is any name or id the SAPRead node index lists (the same resolver as ## <node> headings; an ambiguous name is refused with its candidates), text is at most 60 characters, and "" clears it. Works without source; nodes marked obligation="forbidden" are refused. |
objects |
array | No | For batch_create: ordered list of objects (see below) |
activateAtEnd |
boolean | No | For batch_create only. Default false (per-object inline activation). When true, ARC-1 writes inactive drafts for every object then issues one terminal batch-activate — SAP's activator resolves cross-references between siblings in a single pass. Use this for interdependent objects (composition-linked DDLS, RAP behavior stacks where parent references not-yet-active child). Partial-failure semantics are unchanged: a write-phase failure still breaks the loop and only the already-written subset is batch-activated. |
Unconfirmed creation: Repository-object and package creation, class-include initialization,
and transport creation do not automatically replay after HTTP 429/5xx or a lost response.
SAP may already have created the object even though ARC-1 reports an error. Inspect its identity,
package and source with SAPRead/SAPSearch (including version="inactive") before deciding
whether to resume a source update; never overwrite an unrelated existing object. For transport
requests, use SAPTransport to list and inspect the request before creating another. Batch
results retain unknown creation outcomes. Existing authentication/CSRF and MIME-rejection
recovery remains; read requests retain their retry behavior. ARC-1 does not roll back or
complete an uncertain creation automatically.
DDIC metadata writes: DOMA, DTEL, MSAG, and SRVB use structured XML payloads and do not use /source/main. On DTEL create, an omitted label length is derived from its label text, or defaults to the field's maximum when the label is absent; omitted deactivateInputHistory defaults to false. On DTEL update, omitted fields keep their stored values, including lengths, the history flag, the SET/GET parameter, the change-document and bidi flags, and the search-help parameter while the search help is unchanged. Changing a label without supplying its length derives a new length from that label. Every DTEL create sends a follow-up metadata PUT because SAP's create POST drops the description, labels, and custom lengths. MSAG writes use the /sap/bc/adt/messageclass/ endpoint and accept a messages array of {number, shortText, longText?} entries. SRVB create uses wildcard content type (application/*) and SRVB update uses vendor type (application/vnd.sap.adt.businessservices.servicebinding.v2+xml).
Source-based DDIC writes: TABL, DDLS, DCLS, BDEF, and SRVD write source via /source/main. SKTD/KTD instead GETs the complete <sktd:docu> envelope and PUTs it back with the v2 KTD media type, changing only addressed Base64 long-text bodies and existing short-text attributes. TABL covers both transparent tables (TABL/DT) and DDIC structures (TABL/DS); ARC-1 auto-resolves between /ddic/tables/ and /ddic/structures/ for read/update. SKTD writes Markdown knowledge-transfer documentation attached to one KTD-capable ABAP object; KTD is accepted as a friendly alias. Create requires refObjectType and uses name as the documented object name. ARC-1 supports KTD creates for parent types with verified ADT parent URI routing, including DDLS/DF, BDEF/BDO, SRVD/SRV, SRVB/SVB, DEVC/K, and SMBC/TYP (Business Configuration Maintenance Object). CLAS/OC, INTF/OI, and PROG/P were not registered for KTD DOCUMENTATION scope on the tested SAP_BASIS 758 and 816 systems; use ABAP Doc for those code objects. Other SAP-registered KTD parent types require ARC-1 parent URI routing before create is enabled.
To document an existing Business Configuration Maintenance Object, use its name and provide its description. Follow create or update with KTD activation:
SAPWrite(action="create", type="KTD", name="Z_MY_CONFIGURATION", package="$TMP",
refObjectType="SMBC/TYP", refObjectDescription="My business configuration",
source="Documentation for maintaining this configuration.")
SAPActivate(type="KTD", name="Z_MY_CONFIGURATION")
SAPRead(type="KTD", name="Z_MY_CONFIGURATION")
This writes the BCMO’s KTD. Read the parent’s native JSON with
SAPRead(type="SMBC", name=...); SAPTransport supports its check and history.
KTD node routing: Copy a node name from the SAPRead index into a ## <node> section or shortTexts[].node. Exact full IDs take precedence; case-insensitive IDs and names must identify one element. If several elements match, use the exact full ID printed in the error or index. An update merges only the addressed nodes. Create/update responses list changed nodes and headings kept as prose. Use dryRun=true to inspect that report before writing. Duplicate-ID documents remain readable through SAPRead, grep, and SAPContext; their read context explains that writes are unavailable because the elements cannot be addressed separately.
Keep edits above the read-only metadata marker in a complete SAPRead result. For a root-only H2 edit, keep that context so the root heading is distinguishable from a visible Markdown title. When only the root has documentation, a bare body without its routing H2 also works. Ordinary unmatched headings remain prose and are reported; a node-shaped typo aborts the update. Prefix a reserved prose heading with one backslash (\## …) to keep it inside the current node.
Metadata updates for DOMA, DTEL, MSAG, SRVB and TTYP, and node edits for SKTD/KTD,
read the current editable metadata after acquiring the SAP lock, then merge and
save in that session. Omitted supported fields are preserved. Supplied collections
(such as MSAG messages or DOMA fixed values) still replace that collection; read
first when extending one. SKTD dryRun validates without a lock and does not
reserve the previewed state. Live SKTD validation uses the locked envelope, so an
invalid node edit can briefly take a lock but never writes.
Table type updates¶
A TTYP update keeps the stored description and row type when you omit them. While the row type
is unchanged it also keeps the stored kind and omitted built-in dimensions. For example,
rowType="DEC", rowTypeKind="builtin", rowTypeLength=5, rowTypeDecimals=2 creates
a packed row; updating only rowTypeDecimals=0 keeps length 5 and clears its scale.
Changing the row name or kind drops omitted dimensions instead of carrying them to another type.
The update still replaces the rest of the definition: ARC-1 writes only a standard table with a
non-unique standard key. It therefore refuses an update without rowType when it cannot write the
stored definition back unchanged:
- a reference or range row type;
- a sorted, hashed or index table, key components, a unique key or a key alias;
- secondary keys or an initial row count.
SAPRead reports the last two groups as plainStandardTable: false. Passing rowType accepts the
rewrite and resets those settings. Use ADT or SE11 to change such a table type without losing them.
Classic secondary indexes¶
Use SAPRead(type="TABL", name="ZTABLE", include="indexes") to list native index
IDs and URIs. Read an index with SAPRead(type="TABL/DTI", name="ZTABLE~001"):
this returns metadata and JSON source, preferring the pending definition. Explicit
version="active" or "inactive" requires that version to exist.
SAPWrite supports create, update and delete with the same TABLE~INDEX name
(index ID: 1–3 letters/digits). Create inherits the table's real package; a supplied
package must match. Pass the complete index JSON as source, not the read envelope.
For example, after creating and activating ZTABLE with CLIENT and STATUS fields:
{"formatVersion":"1","header":{"description":"Status lookup","originalLanguage":"en"},"uniqueIndex":false,"bufferIndexOnly":false,"textIndex":false,"indexFields":[{"fieldName":"CLIENT"},{"fieldName":"STATUS"}]}
Updates replace the entire pending definition. Read it first and coordinate with its
author; omitted fields are not merged. SAP can label a pending index new. Set its
description on create; the tested source PUT ignores header.description changes. Activate separately with
SAPActivate(type="TABL/DTI", name="ZTABLE~001"). SAP validates fields and database
constraints. Index creation can fail on duplicate data, and changing an existing index
can require database conversion. ARC-1 does not perform that conversion. Activation
warnings mean database state is unverified, even if metadata says active; inspect
ADT before retrying. ARC-1 treats a warning without an object URI as applying to every index in the batch. A timeout likewise does not prove that activation failed.
Verified for classic transparent tables on SAP_BASIS 758, 816 and BTP ABAP 920; the collection is absent on tested 750. Listing needs read scope, not SQL/data-preview permission. Writes retain the normal write/package/transport gates. CDS table-entity index variants and XINX extension indexes are not covered.
Server-driven object writes¶
DESD, EVTB, DTSC, CSNM, EVTO, COTA, DSFD, DTDC, UIAD, DRTY, APLO, SAJC, and SAJT are server-driven objects (mostly ABAP Platform 2025 / SAP_BASIS 8.16+) — ~46 repository types that share one AFF generic-object contract. SAPWrite supports create, update, and delete for them; use SAPActivate when SAP requires activation:
createposts the type's metadata body to the type's collection (e.g./sap/bc/adt/ddic/desd), then — ifsourceis supplied — writes it. Most types are left inactive; follow withSAPActivate(type=..., name=...). Saves may contain invalid DDL until SAP activation checks them. APLO and UIAD source saves are active immediately on the verified systems; see its validation contract below.sourceformat is per-type. Most types take AFF JSON — e.g.{"formatVersion":"1","header":{"description":"…","originalLanguage":"en","abapLanguageVersion":"cloudDevelopment"}}— parse-validated (clean error on malformed JSON) and written to…/source/mainasapplication/json.DTSC,DSFD,DTDCandDRTYinstead take DDL text (define static cache …,define scalar function …,define dynamic cache …,define type …), written astext/plain; sending the wrong content type is a hard415from SAP, so the flavor is pinned per type inSDO_REGISTRY. ABAP-specific pre-write steps (lint, RAP preflight, CDS guard) do not apply.updaterequiressource(AFF JSON or DDL text, per the type). Update and delete honor theallowedPackagesceiling against the object's real package.deletechecks SAP's advertised deletion precheck under the object lock and refuses negative or inconclusive results. After an accepted DELETE, ARC-1 verifies canonical metadata absence with a fresh GET. A surviving object is reported as incomplete deletion; an unreadable result is reported as unconfirmed. Neither outcome triggers an automatic recovery DELETE. Inspect dependencies and the package entry in ADT before proceeding. If discovery is unavailable, deletion is refused; a known target without the precheck keeps its existing delete path with readback. The check does not lock dependent objects or guarantee an atomic dependency snapshot.- Availability is discovery-gated and per-type. On systems that do not expose a type, write returns an ADT-support-unavailable error. Most types need 8.16+, but
EVTB(RAP Event Binding),DSFD(CDS Scalar Function Definition),DTDC(CDS Dynamic Cache), andDRTY(CDS Type) also ship on S/4HANA 2023 (758) — their write paths are live-verified there (create/update/activate/read/delete).APLO,SAJCandSAJTare live-verified on SAP_BASIS 758 and 816 and on a BTP ABAP Environment trial. APLO saves are active immediately; job catalogs and templates require activation. NetWeaver 7.50 exposes none of them.
| Type | Object | Notes |
|---|---|---|
DESD |
CDS Logical External Schema | Creates standalone — the reference round-trip type. |
EVTB |
RAP Event Binding | Also on 758. |
EVTO |
RAP Event Object | Create uses the blues v2 content-type. |
DTSC |
CDS Static Cache (table-entity buffer) | Source is DDL text, not JSON. |
CSNM |
Core Schema Notation Model (CSN) | |
COTA |
Communication Target | |
DSFD |
CDS Scalar Function Definition | Source is DDL text, not JSON. Also on 758. |
DRTY |
CDS Type (scalar type / enum) | Source is DDL text, not JSON. One subtype DRTY/STY covers scalar types and enums, so create needs no subtype routing. |
UIAD |
Launchpad App Descriptor Item (LADI) | Manual Cloud-language items support create/update, including on-prem 816. Full-source validation and read-only configuration checks run before mutation. Generated items follow their application deployment lifecycle. See below. |
DTDC |
CDS Dynamic Cache | Non-blue metadata format (<dtdc:dtdcSource>). Source is DDL text (define dynamic cache …). Also on 758. |
APLO |
Application Log Object | AFF JSON with subobjects[] (required by the AFF schema; may be empty). Maximum name length: 20. Create/update takes effect immediately, without SAPActivate or an inactive draft. In the contributor's test, the package set the language version. |
SAJC |
Application Job Catalog Entry | Blues v2; adtcore:type is the bare SAJC (no subtype). Create requires source.generalInformation.className naming an existing active class. SAP calls its GET_PARAMETERS method to derive parameters; 758 omits parameters[] in AFF readback. Activate the catalog before creating templates. A deleted catalog left a deletion-flagged SUSH entry in one BTP ZLOCAL package and blocked package removal; see the cleanup evidence. |
SAJT |
Application Job Template | Blues v2; bare SAJT. Create requires source.generalInformation.catalogName naming an active catalog entry. Delete templates before their catalog; dependency enforcement differs by SAP release. On BTP, activating a catalog entry starts an asynchronous publishing step; deleting the catalog before it finishes returns 400 "Publishing in process". |
- Read versions: Omitted/
autoreturns SAP's developer view, including a draft when present. Explicitactive/inactiverequests return an error if SAP cannot confirm that version in metadata. See SAPRead. - Type names and other tools: Use the base code (for example
DRTY), not the search result's slash code (DRTY/STY). Generic syntax/ATC/transport helpers use the registered URL; SAP may still return incomplete ATC results.SAPDiagnose object_stateandSAPRead action="diff"refuse server-driven types; readversion="active"andversion="inactive"separately to compare them. Version verification remains required forobject_state. Surgery,batch_createand RAP scaffolding are not supported for SDOs.
Create job objects in dependency order: activate a class implementing IF_APJ_DT_EXEC_OBJECT and
IF_APJ_RT_EXEC_OBJECT, create/activate SAJC, then create/activate SAJT. Pass complete AFF JSON
in source; ARC-1 also sends the class/catalog reference in SAP's creation metadata, as required
on 758. For example, a template source starts with:
{"formatVersion":"1","header":{"description":"My job","originalLanguage":"en"},"generalInformation":{"catalogName":"ZMY_CATALOG"}}
These tools maintain repository definitions; they do not schedule or execute a job.
DRTY create/update: Use canonical type="DRTY" with plain define type source, for example:
{"action":"create","type":"DRTY","name":"Z_ORDER_STATUS","package":"$TMP","source":"define type Z_ORDER_STATUS : abap.int1 enum { unknown = initial; open = 1; closed = 2; }"}
Follow with SAPActivate(type="DRTY", name="Z_ORDER_STATUS").
Delete consumers before their CDS type and verify absence afterward. On SAP_BASIS 8.16, SAP has accepted deletion of a referenced type while leaving an orphan; see #839.
UIAD create/update: Supply complete AFF JSON in source. ARC-1 checks the target's
matching schema, then sends the exact candidate to SAP before metadata creation or locking.
Schema and semantic errors block writes; warnings remain warnings. Unsupported checks are
reported as unavailable. Authorization and transient preflight failures stop the operation.
The source header's explicit language version is honored on create; metadata-only create
remains supported. Root readonly configuration blocks updates. For generated descriptors,
change the app's manifest.json and redeploy; see SAP's lifecycle documentation.
Results retain confirmed or unknown metadata/source state, the original save failure,
and any unlock failure. Read the object before retrying. Diagnostics show at most 20 messages,
errors first, plus the total messageCount; minimalErrors hides SAP details.
Function group (FUGR) create: POSTs <group:abapFunctionGroup … adtcore:type="FUGR/F"> to /sap/bc/adt/functions/groups with content type application/vnd.sap.adt.functions.groups.v3+xml. Provide package and (for non-$TMP) transport. Delete the FUGR only after all its function modules have been deleted.
Function module (FUNC) create / update / delete (issue #250): The parent FUGR must already exist — pass group explicitly on create (or auto-resolve via search on update/delete). Create POSTs <fmodule:abapFunctionModule … adtcore:type="FUGR/FF"> with <adtcore:containerRef> to /sap/bc/adt/functions/groups/{group}/fmodules. The FM inherits its package from the parent FUGR: omit package, or supply the exact inherited package as an assertion. ARC-1 resolves and safety-checks the real FUGR package before creating the contained module, and rejects an explicit mismatch. SAPGUI-style *"…IMPORTING…"* parameter comment blocks in source are auto-stripped before PUT as defense-in-depth (SAP rejects them with FUNC_ADT028) and a warning is appended in that case.
Execution semantics are function-module metadata, not ABAP source. Set processingType="rfc" for a Remote-Enabled module. For update modules, set processingType="update" plus an explicit updateTaskKind; V1 "Start immediately" is startImmediate. ARC-1 rejects processing fields on updates and non-FUNC objects instead of silently ignoring them.
SAP's collection POST creates a normal function-module shell even when it accepts processing attributes. For an explicit processing type, ARC-1 therefore reads the new inactive root, preserves the server-provided representation, applies a locked metadata PUT with the release-negotiated media type, and reads the root back before reporting success. If that post-create step fails, the error warns that a normal shell may remain and must be reviewed or deleted before retrying. When processingType is omitted, ARC-1 keeps the pre-existing create behavior without the extra metadata round trips.
Lock object writes (ENQU)¶
SAPWrite supports create, update and delete for DDIC lock objects on on-premise and BTP systems that expose /sap/bc/adt/ddic/lockobjects/sources. source is JSON in the shape SAPRead type="ENQU" returns. Lock-object names begin with E (customer objects normally EZ… or EY…). Writable keys are primaryTable, secondaryTables, lockParameters and allowRFC. Supplied table entries require lockMode; supplied parameter entries require parameterWanted, for both create and update. Read-only keys (name, description, package, version, lockModules) are ignored; change the short text with the separate SAPWrite.description argument. Unknown keys, including those inside tables and parameters, are rejected. Lock modes are E (write, cumulative), S (read, shared), X (exclusive, non-cumulative) or "" (no lock for a table used only to link other tables). Optimistic mode O is a runtime request option; SAP rejects it as a definition default.
createneedsprimaryTable.lockParametersare optional: when omitted, SAP derives one parameter per key field of the lock tables (all passed toENQUEUE_; these may already appear after create). The object is created inactive — follow withSAPActivate(type="ENQU", name=…), which also generatesENQUEUE_<name>/DEQUEUE_<name>.updatereads the developer view under the SAP lock, then merges the supplied top-level keys. Omitted keys preserve existing inactive edits. Supplied table entries and arrays replace their corresponding values. Changing the table set requires an explicitlockParameterslist for the new tables. An explicit empty list is refused on update because SAP can re-derive every parameter withparameterWanted=false, broadening the runtime lock. Preserve the list fromSAPReadunless you intend to change it. Activate after saving.deleteuses the standard lock → DELETE → unlock path.
These operations maintain the repository definition and generate function modules on activation;
they do not call those modules or acquire locks on business data. The referenced tables must already exist.
parameterWanted=false makes that key generic when the lock is used, broadening the affected rows.
Changing allowRFC changes the generated interface; review existing callers before activation.
ABAP Cloud code uses CL_ABAP_LOCK_OBJECT_FACTORY to acquire runtime locks.
{"action":"create","type":"ENQU","name":"EZ_ORDER","package":"$TMP","description":"Order lock",
"source":"{\"primaryTable\":{\"tableName\":\"ZORDER\",\"lockMode\":\"E\"}}"}
Create, partial update, table/parameter changes, activation, batch create, concurrent edits and deletion were verified on SAP_BASIS 758/816 and a BTP 920 trial. The collection was absent on the tested 7.50 system. SAP can normalize parameters joined through foreign keys; read back the activated definition before editing it. See the wire contract and evidence.
BAdI implementation writes (ENHO)¶
SAPWrite supports create, update and delete for BAdI enhancement implementations (ENHO/XHB) on
systems that expose /sap/bc/adt/enhancements/enhoxhb. On BTP only BAdIs released for cloud development
(C1 with useInSAPCloudPlatform) can be implemented, in an ABAP Cloud package. Source-code plug-ins (XHH) and
other enhancement technologies stay read-only. source is JSON in the shape SAPRead type="ENHO"
returns. Writable keys are enhancementSpot and badiImplementations; each entry has name,
badiDefinition, implementingClass and optional shortText, active (default true) and default
(default false). Read-only keys (name, description, package, technology, switchSupported)
are ignored; change the short text with the separate SAPWrite.description argument. Unknown keys are
rejected. One enhancement implementation belongs to one enhancement spot.
createneedsenhancementSpotand the BAdI implementations. Like Eclipse, ARC-1 POSTs the empty container and then saves the implementations with a locked PUT; both carry the transport. If saving or unlocking fails, the object already exists and its resulting state is unconfirmed: read it back, then useupdateif needed; do not repeatcreate. Create and activate the implementing class first, thenSAPActivate(type="ENHO", name=…).updatereads the developer view under the SAP lock. A suppliedbadiImplementationslist replaces the stored one; within an entry that already exists, omittedshortText/active/defaultkeep their stored values. The spot cannot change.deletefirst requires metadata confirmingBADI_IMPLtechnology, then uses the standard lock → DELETE → unlock path. Other or unknown technologies and failed metadata reads stop deletion.
Filters. For filter-dependent BAdIs, each entry takes an optional filter condition in the form
SAPRead shows it, e.g. "COUNTRY = 'BE' OR COUNTRY = 'NL'" or
"(COUNTRY = 'DE' OR COUNTRY = 'AT') AND GENERIC_FILTER CP 'X*'". Comparators are =, <>, <, <=, >,
>=, CP and NP; AND binds tighter than OR; values are quoted ('' escapes a quote). Omitting filter
or passing it unchanged keeps SAP's stored filter as it is; "filter": "" removes it. ARC-1 reads the
enhancement spot first: it refuses a BAdI that is not defined in the spot and a filter name the BAdI does not
declare, and copies each filter's type and DDIC check from the BAdI definition. SAP does not store an OR of
different filters inside an AND, such as (A = '1' OR B = '2') AND C = '3'; ARC-1 refuses it and asks for
the equivalent OR of AND groups. An OR of one filter's values inside an AND is fine. A Z/Y create for an
SAP-internal spot is refused before the create, because SAP rejects it but still leaves an object directory
entry. An update also keeps the stored customizingLock and example attributes.
ARC-1 limits new filter input to 32,768 characters and 32 nested parentheses; these are parser limits,
not SAP filter semantics.
SAP checks that the class implements the BAdI interface and the filter values against their DDIC check
only at activation: such a write is saved inactive and SAPActivate reports the error. Create, update,
filters, activation and delete were verified on SAP_BASIS 816 in $TMP and in a transportable package
with a request.
{"action":"create","type":"ENHO","name":"ZMY_ENH_APPROVAL_REASON","package":"$TMP","description":"Approval Reason BAdI",
"source":"{\"enhancementSpot\":\"ES_SD_SLS_EXTEND\",\"badiImplementations\":[{\"name\":\"ZMY_BADI_APPROVAL_REASON\",\"badiDefinition\":\"SD_APM_SET_APPROVAL_REASON\",\"implementingClass\":\"ZCL_MY_APPROVAL_REASON\"}]}"}
The payload follows SAP's GET serialization and was verified on SAP_BASIS 816 on-prem. See the wire contract.
SAPWrite for FUNC: create / update with structured parameters¶
Issue #252 added structured FM parameter management. Pass a parameters array to declare the function module's signature; ARC-1 builds the ABAP-source-based IMPORTING / EXPORTING / CHANGING / TABLES / EXCEPTIONS / RAISING clause and splices it into the source body before PUT. SAP ADT exposes parameters ONLY through /source/main (verified live on a4h S/4HANA 2023 + NPL 7.50 SP02) — there is no separate metadata endpoint.
Each parameter:
| Field | Type | Description |
|---|---|---|
kind |
string | One of importing, exporting, changing, tables, exceptions, raising. |
name |
string | Parameter / exception name. Always uppercased on emit. |
type |
string | ABAP type expression (STRING, I, BAPIRET2, TYPE STANDARD TABLE OF X, LIKE DOKHL-OBJECT, …). Required for IMPORTING/EXPORTING/CHANGING/TABLES; ignored for EXCEPTIONS/RAISING. For TABLES, include the leading TYPE or LIKE keyword. |
byValue |
boolean | Emit VALUE(name) wrapper. Default false (pass-by-reference). |
default |
string | Raw ABAP literal — IMPORTING/CHANGING only. Emitted verbatim (no escaping). Examples: 'X', 0, space. |
optional |
boolean | Emit OPTIONAL keyword. |
Example — create an FM with a typed signature:
SAPWrite({
action: "create",
type: "FUNC",
name: "Z_GREET",
group: "ZARC1_FG",
description: "Greet a user",
parameters: [
{ kind: "importing", name: "IV_NAME", type: "STRING", byValue: true, default: "'World'" },
{ kind: "exporting", name: "EV_GREET", type: "STRING", byValue: true },
{ kind: "raising", name: "CX_ROOT" }
],
source: " ev_greet = |Hello { iv_name }|.\n"
})
The source value is the FM body only — ARC-1 wraps it in FUNCTION Z_GREET …. ENDFUNCTION. and emits the signature clause from parameters. Or pass full FUNCTION/ENDFUNCTION source and the splicer will replace just the signature region. Or omit source entirely to create an empty-body FM with only the signature.
Round-trip: SAPRead({type: "FUNC", name: "Z_GREET", group: "ZARC1_FG", includeSignature: true}) returns:
{
"source": "FUNCTION z_greet\n IMPORTING\n VALUE(iv_name) TYPE string DEFAULT 'World'\n EXPORTING\n VALUE(ev_greet) TYPE string\n RAISING\n cx_root.\n ev_greet = |Hello { iv_name }|.\nENDFUNCTION.",
"signature": {
"importing": [ { "kind": "importing", "name": "IV_NAME", "type": "string", "byValue": true, "default": "'World'" } ],
"exporting": [ { "kind": "exporting", "name": "EV_GREET", "type": "string", "byValue": true } ],
"changing": [],
"tables": [],
"exceptions": [],
"raising": [ { "kind": "raising", "name": "CX_ROOT" } ]
}
}
For an update with parameters but no source, ARC-1 reads the current developer-view source
under the function-module lock, changes only its signature, and preserves the body. A failed
source read, empty response or unparseable FUNCTION envelope aborts without writing. Optional
expectedSourceHash is checked against this same source.
Backward-compat: when parameters is omitted, the existing source-only PUT path runs unchanged. When includeSignature is omitted on read, the response is plain text source.
Reading the processing type back¶
SAPRead(type="FUNC", …, includeSignature=true) reports processingType and, for update modules,
updateTaskKind alongside the parsed signature — so a caller that set one can verify it took effect.
It is a metadata read, so a failure there adds propertiesError to the payload rather than breaking
the signature read. See the create-side docs above for how the attributes are written.
Function-group structural includes (type="INCL" with group=)¶
SAPWrite(type="INCL", group=<FUGR>) creates, updates and deletes a function group's structural includes (LZ<GROUP>TOP global data, F01 subroutines, O01/I01 PBO/PAI modules, T99 unit tests):
SAPWrite({ action: "create", type: "INCL", name: "LZARC1_FGF01", group: "ZARC1_FG",
description: "Subroutines", package: "$TMP" })
SAPWrite({ action: "update", type: "INCL", name: "LZARC1_FGF01", group: "ZARC1_FG",
source: "FORM do_work.\nENDFORM.\n" })
- The include name must start with
L<GROUP>, placingLafter the namespace when present: groupZARC1_FG→LZARC1_FGF01; group/ABC/NAME→/ABC/LNAMEB03. ARC-1 checks this for both create and delete before contacting SAP. - Check the main program after creation. Automatic insertion and commenting out on deletion were verified for ordinary
Zgroups on SAP 7.50 and 758. SAP 758's create path suppresses insertion for groups starting withXafter the namespace; issue #904 also reports no automatic insertion on 752 SP06, with its cause still unverified. If the line is missing, add it withSAPWrite action=update type=FUGR, preserving the existing source, then activate. ARC-1 does not explicitly request insertion. - For structural-include creation, ARC-1 trims and uppercases
groupin the XML parent reference. A lowercase parent reference can make SAP fail the create even though the request URL identifies the correct group. - The include inherits the group's package — SAP ignores
packagehere — soallowedPackagesis checked against the group's real package, and apackageargument that disagrees with it is refused. On update/delete the include itself is the lock and package-resolution target (itscontainerRefcarries the group's package). - Omitting
group=targets the standalone program-include collection instead, which still works for ordinary include names. AnL-prefixed name there is refused with a pointer togroup=— SAP reservesL*for function-group includes and answers with a 500, which would otherwise read as a transient error.
Ordinary-group create/delete verified on NW 7.50 SP02 and S/4HANA 2023 (758). Namespaced create was reported working with the prefix fix on 752 SP06; namespaced delete is covered by regression tests, but still needs live verification in a writable customer namespace.
Robust to GPT/OpenAI optional-field "overpopulation" (issue #360). GPT/OpenAI tool callers (especially under Structured Outputs / strict mode, the default for the Responses API) tend to over-populate optional fields — emitting null for every unused optional, blank strings, or stringified booleans like "false". ARC-1 normalizes these before validation: null and empty/whitespace strings are treated as omitted (across every tool), and optional booleans accept real JSON booleans and "true"/"false"/"1"/"0"/"yes"/"no" (so signExists="false" is correctly stored as false, never inverted). Practical guidance for tool authors: omit optional fields you don't need rather than sending ""/null; include is CLAS-only (for update/edit_method/edit_class_definition) and is ignored for other types/actions; delete needs only type and name (plus optional transport).
Mixed-case object names rejected on create. SAP TADIR is uppercase on every release; mixed-case names cause silent corruption (e.g., a DDLS named Zc_MyView registers as ZC_MYVIEW in TADIR but the source body keeps mixed case, confusing every downstream tool). SAPWrite(action="create"\|"batch_create") rejects mixed-case names pre-flight with an actionable error. The source code inside the object can still use mixed case (e.g., define view entity Zc_MyView); only the TADIR object name needs to be uppercase.
BDEF creation: Uses SAP's blue:blueSource XML format with content-type application/vnd.sap.adt.blues.v1+xml. BDEF objects are created with type="BDEF" and require a source parameter containing the behavior definition.
Release gates for pre-7.52 systems. Several ADT resources simply do not exist before SAP_BASIS 7.52. Rather than surfacing a raw 404 (whose generic hint wrongly suggests the object "was not found"), ARC-1 refuses these up front with a release hint once discovery has been probed:
| Operation | Missing resource | Fallback |
|---|---|---|
SAPWrite create type="TABL"/"TABL/DT" |
/sap/bc/adt/ddic/tables |
SE11. Writing the source through /ddic/structures/ instead would flip DD02L-TABCLASS to INTTAB and corrupt the table |
SAPWrite create type="DOMA" |
/sap/bc/adt/ddic/domains |
SE11. Data elements that reference a domain are blocked with it |
SAPWrite create type="TTYP" |
/sap/bc/adt/ddic/tabletypes |
SE11 |
SAPWrite create type="ENQU" |
/sap/bc/adt/ddic/lockobjects/sources |
SE11 (present on tested 758/816 systems; absent on tested 7.50) |
SAPWrite create type="ENHO" |
/sap/bc/adt/enhancements/enhoxhb |
SE19 or Eclipse ADT (advertised on 758/816; only enhoxh on 750) |
SAPManage action="create_package" |
/sap/bc/adt/packages |
SE80 / SE21 |
Endpoint absence verified on two independent NW 7.50 systems (a dev edition and an ECC EhP8 7.50 SP31 production system); all four are present on S/4HANA 2023 (758) and ABAP Platform 2025 (816). Structures (TABL/DS), data elements, function groups, function modules and includes do work on 7.50 — note that DDIC structure source there uses define type <name> { … }, not define structure.
The gates key off ADT discovery, so a session that never probed (for example a one-shot CLI call) is never blocked — it falls through to SAP's own error.
DDIC save diagnostics: On SAPWrite save failures for DDIC/RAP artifacts (TABL, DDLS, DCLS, BDEF, SRVD, SRVB, DDLX, DOMA, DTEL), ARC-1 enriches errors with structured diagnostics:
- T100 message identifiers/variables (e.g., SBD_MESSAGES/007, V1..V4)
- Line-aware details when available
- Best-effort inactive syntax-check output for source-based DDIC creates (TABL, DDLS, DCLS, BDEF, SRVD, SRVB, DDLX)
This helps pinpoint the exact failing field/annotation instead of retrying blindly.
CDS dependency-aware CRUD hints (DDLS):
- SAPWrite(action="update", type="DDLS", ...) appends downstream where-used impact buckets and a concrete re-activation order + SAPActivate(objects=[...]) template.
- SAPWrite(action="delete", type="DDLS", ...) enriches dependency-style delete failures (for example DDIC message 039) with blocking dependents and suggested delete order.
- Delete hints include cycle-break guidance for mutually-dependent projection graphs (strip redirected/composition clauses, activate stripped versions, then delete).
- If delete guidance lists dependents that were just deleted, treat it as possible stale SAP active dependency/index state and retry after a short wait before deeper cleanup.
- If SAP reports a delete dependency error but current where-used results are empty, ARC-1 now adds stale active-dependency guidance: wait/retry after recent cleanup, activate restored/stripped sources first, then re-check references/locks.
- ARC-1 combines unfiltered ADT where-used results with scoped object-type filters where available. This avoids under-reporting dependents on SAP systems that return only a shallow default usageReferences result.
- If the where-used endpoint is unavailable on the backend, ARC-1 keeps the CRUD action behavior unchanged and adds a short "impact unavailable" note instead of failing the call.
Blue framework package handling: TABL and BDEF create calls now pass package in both the XML (packageRef) and URL query (_package=<pkg>), alongside transport (corrNr) when provided.
CDS pre-write validation:
- Table entity version guard:
define table entitysyntax requires ABAP Cloud (BTP) or S/4HANA on-premise with SAP_BASIS >= 757. On older systems, ARC-1 rejects the write early with an actionable message instead of letting SAP fail with a generic error. - Reserved keyword warnings: CDS field names like
position,value,type,dataetc. may be CDS reserved keywords that cause silent DDL save failures. ARC-1 detects these and includes an advisory warning (non-blocking) suggesting renamed alternatives. - Empty DDLS source: When reading a DDLS that exists but has no stored source, ARC-1 returns an explicit warning instead of silent empty content.
ARC-1-native pre-write semantic hints (TABL):
ARC-1 layers a small set of release-aware, RAP-convention hints on top of the abaplint pass. They emit severity:'warning' only — the write is not blocked. The first hint surfaces a known draft-table anti-pattern; future hints follow the same pattern in src/lint/pre-write-hints.ts.
arc1-tabl-draft-admin-include: A TABL source containsinclude sych_bdl_draft_admin_incwithout the SAP-canonical named-include prefix"%admin" : include sych_bdl_draft_admin_inc;. The bare include activates at TABL level on most releases but is non-canonical per ABAP keyword doc ABENBDL_DRAFT_TABLE and breaks BDEF binding for some draft scenarios. SAP standard draft tables (e.g.BOTD_TAB_ROOT_D) all use the named form. Hint surfaces in the responsewarningsarray withrule: 'arc1-tabl-draft-admin-include'.
RAP deterministic preflight validation:
- Runs before
create/update/batch_createfor RAP-prone source types (TABL,BDEF,DDLX,DDLS). - Blocks writes on deterministic rule errors (for example: missing
@Semantics.amount.currencyCodeforabap.curr, invalidauthorization master ( none ), unsupported DDLX scope annotations on on-prem 7.5x). - Emits warning-only findings for non-fatal patterns (for example: explicit client in DDLS select list).
- Per-call override:
preflightBeforeWrite=false.
Batch creation:
batch_create creates and activates multiple objects in sequence via a single tool call. Objects are processed in array order — put dependencies first (e.g., domain before data element, TABL before DDLS, DCLS after DDLS, BDEF after CDS views). Each object in the array has: type (string, required), name (string, required), source (string, optional), description (string, optional), optional package and transport overrides, plus optional DOMA/DTEL metadata fields. A FUNC entry also accepts group, processingType, updateTaskKind, and structured parameters; group may instead be supplied once at the top level when all FUNC entries share it. Item-level package and transport override the top-level values for ordinary objects. A contained FUNC always inherits its FUGR package, so omit its package or use the exact inherited value as an assertion.
Batches accept at most 100 objects. A batch near the cap can take minutes. Choose smaller batches when the client has a short request timeout, and read object state before retrying a timed-out call. Before the first create, ARC-1 checks the entire batch for supported types, uppercase names, duplicate object identities, enabled source lint/RAP checks, AFF header validity, and constructible create metadata. Package checks include the actual parent package for FUNC entries; transport preflight and the MSAG request check also run before creation. A predictable failure rejects the batch with no objects created. Distinct DDLS and BDEF objects may share a name; repeated aliases for one object may not. CLAS and INTF share a name space. Function-group structural includes (INCL names beginning with L) require single-object create with group.
SAP runtime failures can still happen after preflight. Execution stops at the first failure and records creation, source/metadata writing, and activation independently. A successful create followed by a failed write or activation counts as a created object. A rejected or interrupted create without readback is reported as unknown, because an error does not prove that nothing was persisted. Verify with SAPRead, then explicitly resume the required write or activation; the batch does not overwrite existing objects or roll back earlier creations.
Successful batches retain their existing single text block. Batch preflight and execution failures return a human-readable first text block plus a second JSON block containing { "batch": { "phase", "requested", "created", "creationUnknown", "completed", "failed", "skipped", "results" } }. Each result identifies its zero-based index, type, name, effective packageName, status, creation, write, activation, and optional failedPhase/error. Creation and writing use not_attempted, confirmed, or unknown; writing may also be not_required. Activation can additionally be failed for an explicit SAP activation error. skipped entries were not attempted. Schema/scope rejections retain the normal error response.
Consumers should inspect isError and parse the second block individually when present; do not concatenate the blocks and parse them as one JSON value. ARC1_MINIMAL_ERRORS=true hides SAP-derived diagnostics in both blocks while retaining phase and count information. The human block summarizes large failures; the manifest keeps all entries with bounded diagnostics. Unassigned activation messages appear once in the human block, while per-entry errors only describe that object. Source code is not included in the result manifest.
Deferred activation for interdependent objects (activateAtEnd: true): By default, each object is created → source written → activated, in order. This works for linear dependency chains but fails when siblings cross-reference each other (e.g. composition-linked DDLS where the parent's composition [0..*] of ZR_CHILD references a not-yet-active child). Set activateAtEnd: true to write inactive drafts before one terminal activateBatch call. SAP's activator sees the supplied graph together. A runtime write failure still stops the loop, and terminal activation runs only over the already-written subset. If overall activation fails, objects without a specific error remain unknown; absence of an object-level message is not proof of activation. Confirmed and uncertain mutations invalidate affected caches even when completion fails.
RAP handler scaffolding
scaffold_rap_handlers derives required behavior-pool METHODS ... FOR ... signatures from an interface BDEF, computes missing signatures, and can optionally create missing local handler skeletons plus inject declarations and empty METHOD ... ENDMETHOD stubs into the behavior pool class:
- Scans class sections from
source/main,includes/definitions, andincludes/implementations - In
autoApply=true, creates missingCLASS lhc_<alias> DEFINITION INHERITING FROM cl_abap_behavior_handlershells inincludes/definitionsand matching implementation shells inincludes/implementations - Supports dry-run listing (
autoApply=false, default) and write-back mode (autoApply=true) - Helps recover from generic behavior-pool save errors by generating exact signatures for actions/determinations/validations/authorization handlers
Both scaffolding actions acquire the class lock before reading the editable source and deriving changes. Previews remain read-only; unchanged mutation calls and activation-only reruns still require the lock. Separate include writes are not atomic: after a save or unlock error, read the current class sections before retrying; an earlier include may already have been saved.
SAPWrite(action="batch_create", package="ZDEV", transport="K900123", objects=[
{type:"TABL", name:"ZTRAVEL", source:"define table ztravel {...}"},
{type:"DDLS", name:"ZI_TRAVEL", source:"define root view..."},
{type:"DCLS", name:"ZI_TRAVEL_DCL", source:"define role..."},
{type:"BDEF", name:"ZI_TRAVEL", source:"managed implementation..."},
{type:"SRVD", name:"ZSD_TRAVEL", source:"define service..."},
{type:"CLAS", name:"ZBP_I_TRAVEL", source:"CLASS zbp_i_travel..."},
{type:"SRVB", name:"ZSB_TRAVEL_O4", serviceDefinition:"ZSD_TRAVEL", category:"0"}
])
SAPWrite(action="batch_create", objects=[
{type:"TABL", name:"ZTRAVEL", package:"ZDEV", transport:"K900123", source:"define table ztravel {...}"},
{type:"DDLS", name:"ZI_TRAVEL", package:"ZDEV", transport:"K900123", source:"define root view..."}
])
SAPWrite(action="create", type="TABL", name="ZTRAVEL", package="$TMP",
source="@EndUserText.label : 'Travel'\ndefine table ztravel {\n key client : abap.clnt;\n key travel_id : abap.numc(8);\n description : abap.char(256);\n}")
SAPWrite(action="create", type="DOMA", name="ZSTATUS", package="$TMP",
dataType="CHAR", length=1,
fixedValues=[{low:"A",description:"Active"},{low:"I",description:"Inactive"}])
SAPWrite(action="create", type="DTEL", name="ZSTATUS", package="$TMP",
typeKind="domain", typeName="ZSTATUS",
shortLabel="Status", shortLength=10,
mediumLabel="Order Status", mediumLength=20,
longLength=40, headingLength=55,
deactivateInputHistory=true)
SAPWrite(action="create", type="SRVB", name="ZSB_TRAVEL_O4", package="$TMP",
serviceDefinition="ZSD_TRAVEL", category="0")
SAPWrite(action="update", type="CLAS", name="ZBP_I_TRAVELREQ",
include="implementations",
source="CLASS lhc_travel IMPLEMENTATION.\nENDCLASS.")
SAPWrite(action="scaffold_rap_handlers", type="CLAS", name="ZBP_I_TRAVELREQ",
bdefName="ZI_TRAVELREQ", autoApply=true)
# One-shot RAP behavior pool: discover BDEF + scaffold + activate in one call
SAPWrite(action="generate_behavior_implementation", type="CLAS", name="ZBP_DM_PROJECT")
# Same, with preview-only mode (returns the plan, does not write)
SAPWrite(action="generate_behavior_implementation", type="CLAS", name="ZBP_DM_PROJECT",
dryRun=true, activate=false)
generate_behavior_implementation is the reliable equivalent of Eclipse ADT's "Generate Behavior Implementation" Cmd+1 quickfix. Auto-discovers the BDEF via the class metadata's <class:rootEntityRef> element, cross-validates that MAIN's FOR BEHAVIOR OF <bdef> and the BDEF's managed implementation in class <class> agree, scaffolds every required handler (creating missing lhc_<alias> skeletons), writes CCDEF + CCIMP under one stateful lock, and (by default) activates the class. Uses deterministic scaffolding without depending on SAP quick-fix availability.
Transport behavior:
updateanddelete: ARC-1 automatically reuses the correction number from the SAP object lock when no explicittransportis provided. This means writes to transportable objects often succeed without manually specifying a transport.createandbatch_create: ARC-1 performs a transport pre-flight check for non-$TMPpackages when no transport is provided. This calls the SAP transport checks endpoint to determine whether a transport number is required:- If the object is already locked in a transport, ARC-1 auto-uses that transport.
- If the package is local (e.g.,
$TMP), no transport is needed — creation proceeds. - If a transport IS required but none was provided, ARC-1 returns an actionable error message listing existing transports and guiding the caller to use
SAPTransport(action="list")orSAPTransport(action="create")first. - If the pre-flight check fails (older system, permissions), ARC-1 proceeds and lets SAP handle the error.
Note: Not available by default (read-only mode). Enable with SAP_ALLOW_WRITES=true / --allow-writes=true. Write access is restricted to package $TMP by default; to write to other packages, set SAP_ALLOWED_PACKAGES='$TMP,Z*' (quote in shell so $TMP isn't expanded).
Source preconditions¶
Before editing existing text source, read SAPRead(type=..., name=..., format="editable").
This returns JSON {source, sourceHash} from a fresh, uncached developer-view read: the editable
inactive draft when one exists, otherwise active source. Omit version, method, grep and
action; this mode hashes the complete source, not a formatted or extracted result.
Omitted, null or blank hashes disable this optional protection. Pass the returned hash unchanged as expectedSourceHash on the write. ARC-1 acquires the SAP lock,
re-reads the editable source without caches, and compares its SHA-256 before writing. A mismatch
refuses the write and releases the lock. Re-read and reconcile the changed source before retrying;
do not simply obtain a new hash and resend a stale replacement.
SAPRead(type="PROG", name="ZREPORT", format="editable")
// Review source; save the returned sourceHash as H.
SAPWrite(action="edit_unit", type="PROG", name="ZREPORT", unit="process_data",
source="FORM process_data. ... ENDFORM.", expectedSourceHash=H)
Supported types: PROG, INCL, CLAS, INTF, FUNC, DDLS, DCLS, BDEF, SRVD, DDLX.
Supported actions: update, edit_unit, add_unit, and the CLAS surgery actions. For class-local methods,
read the correct include=implementations|testclasses|definitions|macros and use that same include
on the write (or the matching method prefix). The hash covers that entire include. For function-group
includes pass the same group; FUNC can resolve its group or accept it explicitly. Unsupported
metadata, server-driven, create/delete and scaffold operations reject expectedSourceHash.
Limits: the hash is optional for compatibility. Writes without it can still overwrite changes made since an earlier tool call; automatic locks alone do not prevent that. A guarded unit edit also refuses changes elsewhere in its containing source. Hashes compare exact UTF-8 content, including whitespace and line endings; they do not record edit history. A read does not hold a lock or reserve a version, and an identical source restored later has the same hash. A missing include cannot be initialized by a guarded write; its read/precondition must succeed first.
Procedural unit surgery¶
On-prem action="edit_unit" replaces one named FORM…ENDFORM or MODULE…ENDMODULE block in a PROG or INCL without making the caller re-send the full program. action="add_unit" inserts a new block using the same locked read/write lifecycle. ARC-1 checks the write/package gates, acquires the SAP lock, then reads the current editable source in that same stateful session. It uses SAP's default source version (the inactive draft when present, otherwise active source), bypassing source and inactive-list caches. It finds the block with abaplint's structure tree, validates the supplied block's kind/name and resulting source, and writes before unlocking. This preserves surrounding edits completed before the lock was acquired; validation or read failures perform no PUT, and ARC-1 always attempts to unlock.
Pass the complete replacement or new block so multi-line FORM signatures and MODULE direction (INPUT/OUTPUT) remain explicit. Both actions are case-insensitive by unit name, preserve CRLF source files, leave sibling units untouched, and do not auto-activate. Run SAPActivate afterwards. Function-group structural includes are supported with type="INCL", group="<FUGR>"; activate those with the same type, name, and group so ARC-1 addresses the structural include directly on every supported release.
{
"action": "edit_unit",
"type": "PROG",
"name": "ZPROG_ORDERS",
"unit": "PROCESS_ORDERS",
"source": "FORM process_orders USING iv_force TYPE abap_bool.\n \" new implementation\nENDFORM.",
"transport": "DEVK900001"
}
To add a block, pass its new name in unit and its complete source. ARC-1 appends
at the physical end of the selected source; it never moves trailing INCLUDE
statements or existing unit headers. Existing names and incomplete structures are
refused without a PUT. SAP_DENY_ACTIONS=SAPWrite.edit_unit does not deny add_unit;
list both actions (or SAPWrite) when both must be blocked. The write/package gates
apply to both actions.
{
"action": "add_unit",
"type": "PROG",
"name": "ZPROG_ORDERS",
"unit": "VALIDATE_ORDERS",
"source": "FORM validate_orders.\n \" validation logic\nENDFORM."
}
Name checks cover this physical source only, not its included sources. Choose an include meant
for complete processing blocks (such as an F01 or O01 include), rather than one expanded inside
another block. Adding a FORM/MODULE neither adds a PERFORM call nor changes screen flow logic.
Read back the draft and run SAPActivate to validate the whole program. Use expectedSourceHash
when the insertion depends on a previously reviewed snapshot.
Event blocks such as START-OF-SELECTION and AT SELECTION-SCREEN are intentionally unsupported: abaplint does not expose them as bounded structure nodes, so name-based replacement cannot provide the same safety guarantee. FUNC is also out of scope because each function module already has a dedicated /source/main resource containing only that function module.
Class-section surgery¶
Issue #303. Four token-efficient SAPWrite actions for editing a global ABAP class without re-sending the full /source/main body. All require type=CLAS and use SAP's existing /sap/bc/adt/oo/classes/{name}/objectstructure endpoint to locate the precise line ranges to splice — no client-side ABAP parsing of the existing source is needed.
Backing pattern for class surgery: lock the class → read fresh editable source and matching /objectstructure when needed → splice → PUT → unlock. These reads bypass source and inactive-list caches, preserving draft changes completed before the lock. No auto-activation. Caller runs SAPActivate next. For edit_class_definition include=..., ARC-1 whole-replaces the class-local include directly and auto-initializes a missing include under the same parent class lock before the PUT.
action="edit_class_definition" — replace the DEFINITION block whole¶
Without include=, send only the new global CLASS … DEFINITION … ENDCLASS. block (typical ~10–80 lines for a 20-method class). ARC-1 fetches the existing /source/main, splices the new DEFINITION over the existing one, and PUTs back. The IMPLEMENTATION block is preserved verbatim.
With include=definitions|implementations|macros|testclasses, send the full replacement body for that local include. For ABAP Unit tests, target include="testclasses" and write local ltc_* classes; ARC-1 creates the missing CCAU include automatically on first write.
Refuse-policy. Before PUT, ARC-1 diffs the new DEFINITION against the current class structure. If the diff would produce a non-activatable draft, the call is refused with a structured error pointing at the right tool:
- Added concrete method without a matching
METHOD …. ENDMETHOD.block in IMPLEMENTATION → "useadd_method". - Removed method that still has an orphan METHOD/ENDMETHOD block in IMPLEMENTATION → "use
delete_method".
Exempted from the symmetry check (no IMPL needed): ABSTRACT METHODS, EVENTS, INTERFACES, ALIASES. For include= writes (CCDEF), the refuse-policy is skipped — cross-include validation is not performed; rely on SAPActivate to catch breaks.
// Drop FINAL from a class without touching any method
{
"action": "edit_class_definition",
"type": "CLAS",
"name": "ZCL_ORDER",
"source": "CLASS zcl_order DEFINITION PUBLIC CREATE PUBLIC.\n PUBLIC SECTION.\n METHODS process RETURNING VALUE(r) TYPE abap_bool.\n PRIVATE SECTION.\n DATA mv_id TYPE string.\nENDCLASS."
}
action="add_method" — atomic DEFINITION + IMPLEMENTATION insert¶
Insert a METHODS clause AND an empty METHOD <name>. ENDMETHOD. stub in one PUT. Default target is visibility=public. The target section header must already exist; if missing, ARC-1 refuses with a hint to use edit_class_definition to add the section first.
{
"action": "add_method",
"type": "CLAS",
"name": "ZCL_ORDER",
"method": "METHODS greet IMPORTING who TYPE string RETURNING VALUE(r) TYPE string.",
"visibility": "public"
}
// → inserts METHODS greet ... in PUBLIC SECTION + empty METHOD greet. ENDMETHOD. in IMPLEMENTATION
Pass abstract: true to skip the IMPLEMENTATION stub (for METHODS x ABSTRACT. in an abstract class).
For an inherited interface method, pass a redefinition clause such as
METHODS /IWBEP/IF_MGW_APPL_SRV_RUNTIME~GET_STREAM REDEFINITION. (optionally
FINAL REDEFINITION). Keep visibility="public" and leave abstract false.
ARC-1 inserts the declaration and an empty implementation; fill the body with
edit_method, then activate. SAP checks that the superclass actually provides a
redefinable method. edit_class_definition also recognizes these qualified names
when checking for missing or orphaned implementations.
Namespaced components such as ZIF_SERVICE~/NS/RUN are also recognized, but
abaplint currently rejects that syntax. For valid source, use the per-call
lintBeforeWrite: false override and verify with SAP syntax checking and activation.
Do not use REDEFINITION for an interface the class itself implements through
INTERFACES. Add any missing bodies with a full-source SAPWrite(action="update"),
preserving existing code; edit_method can only replace a body that already exists.
action="edit_method_signature" — replace one METHODS clause¶
One range replacement on a method's declaration. The IMPLEMENTATION block is untouched — any body incompatibility surfaces at SAPActivate, same as today's edit_method contract.
{
"action": "edit_method_signature",
"type": "CLAS",
"name": "ZCL_ORDER",
"method": "process",
"source": " METHODS process IMPORTING force TYPE abap_bool DEFAULT abap_false RETURNING VALUE(r) TYPE abap_bool."
}
action="delete_method" — atomic DEFINITION + IMPLEMENTATION remove¶
Drops both the METHODS clause and the METHOD…ENDMETHOD body in one PUT. ABSTRACT methods (no IMPL) have only the DEFINITION line removed.
⚠️ Destructive — discards the method body. Do not use
delete_method+add_methodto change a method's visibility: that recreates an empty stub and loses the implementation. Usechange_method_visibilityinstead, which moves the declaration while leaving the body untouched.
action="change_method_visibility" — move a method between sections (body preserved)¶
Moves a method's METHODS clause from its current visibility section to a target section (public / protected / private). Touches the DEFINITION only — the IMPLEMENTATION block (the method body) is preserved verbatim. This is the safe, token-efficient way to change visibility: send the method name + target section instead of re-sending the whole DEFINITION (edit_class_definition), and without the data loss of delete_method + add_method.
- Interface method redefinitions must remain public; protected/private moves are refused before saving.
- Idempotent: if the method is already in the target section, it's a no-op (no write).
- Methods SAP marks as
REDEFINITIONmust retain their inherited visibility; moving them is refused before saving, even withlintBeforeWrite=false. If an existing draft has the wrong section, check the superclass declaration and repair the definition withedit_class_definition. - The target section header must already exist; if not, ARC-1 refuses with a hint to add it via
edit_class_definitionfirst.
{
"action": "change_method_visibility",
"type": "CLAS",
"name": "ZCL_ORDER",
"method": "process",
"visibility": "private"
}
// → METHODS process … clause moves from its current section to PRIVATE SECTION;
// METHOD process. … ENDMETHOD. body in IMPLEMENTATION is untouched.
Cross-release notes¶
Verified live on a4h (S/4HANA 2023, kernel 7.58) end-to-end. The underlying /objectstructure endpoint also works on NW 7.50 SP02 (reads verified); on that release methods are split across CLAS/OO (def) + CLAS/OM (impl) elements and merged by name in the parser. Writes on the un-patched NW 7.50 dev edition can trip SAP Note 2727890 "ADT: fix unstable adt lock handle" — a system-level bug affecting every ADT write, not specific to this feature; ARC-1 detects the 423 status and emits a hint.
Technical table settings¶
TABL/DTT reads and updates the separately locked settings of a transparent table.
Available on tested SAP_BASIS 758, 816 and BTP ABAP 920; unavailable on tested 750.
The table's actual package controls update and activation permission.
SAPRead(type="TABL/DTT", name="ZORDERS")
SAPWrite(action="update", type="TABL/DTT", name="ZORDERS",
source='{"dataClass":"APPL1","sizeCategory":2}')
SAPActivate(type="TABL/DTT", name="ZORDERS")
Update source is a nonempty partial JSON object. Copy selected fields from the
read result's source, not the whole result. Supported fields:
| Field | Values |
|---|---|
dataClass |
Native data class, e.g. APPL0, APPL1, APPL2; SAP validates its meaning |
sizeCategory |
Integer 0–9 |
buffering.allowed |
N forbidden, A permitted but off, X on |
buffering.type |
"" none, P single record, G generic, X full |
buffering.areaKeyFields |
Number of leading key fields for generic buffering; otherwise 0 |
Send coherent buffering settings together, e.g.
{"buffering":{"allowed":"X","type":"G","areaKeyFields":1}}.
Omitted fields, read-only fields and earlier inactive changes are preserved.
Saving does not activate or validate every SAP constraint. Activation applies the
whole pending settings document and verifies its resulting state. A new table
needs SAPActivate(type="TABL", ...) first; settings cannot be created/deleted
independently. Explicit version="active"/"inactive" reads refuse a different
version returned by SAP; omit version to prefer any pending draft, including another user's draft,
with active settings as the native fallback.
Storage type, load unit and logging remain read-only. No SQL or legacy fallback.
Text elements¶
Read and write an object's text pool via the ADT textelements service. Three subobjects, each
with its own media type: symbols (the numbered 'Text'(001) literals), selections (a report's
selection texts — the labels beside PARAMETERS/SELECT-OPTIONS) and headings (list header and
column headers). Writes support symbols for classes and all three parts for PROG and FUGR.
Selection texts require selection-screen fields in the program/function group source.
SAPRead(type="CLAS", name="ZCL_ORDER", include="text_symbols") — class text symbols
SAPRead(type="TEXT_ELEMENTS", name="ZHU_CREATE", objectType="PROG") — whole program pool
SAPRead(type="TEXT_ELEMENTS", name="ZHU_CREATE", objectType="PROG", include="selections")
SAPWrite(action="edit_text_symbols", type="CLAS", name="ZCL_ORDER",
source="@MaxLength:20\n001=Order\n\n@MaxLength:30\n002=Order created\n")
SAPWrite(action="edit_text_symbols", type="PROG", name="ZHU_CREATE", textPart="selections",
source="P_LGNUM=Warehouse\nP_WRKST=Work center\n")
- Body formats:
symbols— one@MaxLength:NNline per symbol, thenNNN=text, blank-line separated (a shared or missing@MaxLengthis rejected with406 "Text elements contain errors").selections— onePARAM=textline per field; the text after=is limited to 30 characters, including a supplied dictionary label. Keep the preceding@DDICReferenceline to retain a dictionary reference;PARAM=?...means no maintained text.headings—listHeader=pluscolumnHeader_N=lines. SAP validates these formats and lengths. - Replacement, not merge: each write replaces the complete selected part. Read it first and
retain any entries you want to keep. The result lists texts and dictionary references removed,
verified by a read under the write lock. Restore them from the previous complete part; a fresh
read cannot recover removed values. Other parts remain unchanged. An explicit
source=""clears the selected part; omitted/null source is rejected. Do not send the=== part ===markers from a whole-pool read as source — read the individual part withinclude=instead. - Writes and requests activation of the whole text pool. This also activates pending edits to
other text parts; their content is preserved. Unrelated source drafts stay inactive. If a PROG
has never been activated, finish with
SAPActivate(type="PROG", name="...")to activate its texts. If pool activation fails, the write returns an error; the saved pool may remain inactive. After an activation response, ARC-1 reads the pool metadata and reports active, still inactive, or unverified state. Inactive CLAS/FUGR pools and unverified state return an error while retaining the known save. Check the pool in ADT or involve the user before another write; part-body reads cannot establish the pool state. An exactly empty symbols write to an already-empty, explicitly active CLAS/FUGR pool is skipped under its lock: SAP can otherwise leave an empty inactive pool. Existing inactive drafts are never skipped. Defining the referenced symbols clears the ATC finding "Text symbol NNN not defined" that a bare'Text'(001)literal otherwise leaves behind; maintainingselectionsis what stops a report's selection screen from showing raw parameter names. - Deleting a PROG or FUGR with an inactive text pool: SAP can leave a separately saved
text-pool draft behind after deleting its owner; recreating the same name inherits that orphan.
SAPWrite(action="delete")locks the owner and its text pool, then checks the explicit inactive pool metadata. An inactive pool stops deletion: review it with its author and explicitly activate it before retrying. Deletion never activates drafts automatically; the caller's inactive-object list cannot establish the absence of another user's draft. A new program needs its first owner activation before deletion. If its source cannot compile and you intend to discard it, replace it withREPORT <name>., activate, then delete. If SAP leaves an empty FUGR pool inactive after activation, stop and involve the user; there is no verified automatic repair. Clean pools and source-only drafts can be deleted while both locks remain held. An unavailable discovery collection retains the legacy delete path (7.50); an advertised service error stops deletion. To recover an older PROG orphan, recreate and activate the program, then delete it. For a FUGR orphan, recovery depends on the pool state; do not assume another activation repaired it. - Discovery-gated. CLAS symbols were verified on 758, 816 and BTP ABAP; PROG/FUGR are on-prem object types. The service is absent on the tested NW 7.50 system. When discovery is loaded, ARC-1 reports an unavailable service without calling the broken legacy endpoint. Without discovery, SAP's actual error surfaces.
- Reads:
objectTypedefaults toPROG; useCLASorFUGRexplicitly for those objects. Whole-pool reads label the non-empty raw bodies of supported parts. SAP may return empty-value heading placeholders. Individual reads preserve the raw body and use the requested part's media type. Multipart output adds a reminder to read/write parts individually and omit the markers from write source. A failed part fails the read; HTTP 406 can indicate a source parsing/consistency error. - Class parts: whole-class reads fetch only
symbols. Explicitinclude=selectionsorinclude=headingsreads return SAP's raw response (empty selection bodies and heading placeholders on the verified systems). Class writes remain restricted tosymbols; attempts to writeselectionsorheadingsare refused before HTTP.
Verified live end-to-end on A4H/758: class symbols, plus disposable $TMP program and function-group
selection screens with symbols, selection texts and headings. Tests cover immediate read-back,
replacement/clearing, unchanged sibling parts, rejected malformed bodies, subsequent successful
writes and cleanup.
SAPActivate¶
Activate ABAP objects. Supports single object or batch activation.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | No | activate (default), publish_srvb, or unpublish_srvb. Publish/unpublish makes an SRVB OData binding available/unavailable. |
name |
string | No | Object name (for single activation) |
type |
string | No | Object type (PROG, CLAS, DDLS, DDLX, BDEF, SRVD, SRVB, etc.) |
group |
string | No | Parent function group for FUNC or a function-group structural INCL. May also be set per batch item. |
version |
string | No | Service version for SRVB publish/unpublish (default 0001). |
service_type |
string | No | odatav2 or odatav4 for SRVB publish/unpublish routing; auto-detected from binding metadata when omitted. |
preaudit |
boolean | No | Request pre-activation audit from SAP (default: true). Set false to skip pre-audit for faster activation. |
objects |
array | No | For batch: array of {type, name, group?} objects to activate together |
Use batch activation for RAP stacks where objects depend on each other (DDLS, BDEF, SRVD, DDLX, SRVB must be activated together). Batch responses include per-object status (active, requested, warning, error, unknown). After an overall failure, objects without their own error stay unknown; SAP may have cancelled their activation too. Messages match the object URI or its source/include path, and global messages appear separately. Read active/inactive source before selecting objects to retry.
Use type="REPT" (or the native alias PROG/PX) to activate an existing program text-pool
draft, including one listed by SAPRead(type="INACTIVE_OBJECTS"). It targets the text pool
separately from program source and supports single or batch activation. The result says
requested: if the program has never been activated, first use SAPActivate(type="PROG", name="...")
to activate its texts. The pool's actual package is checked, and systems without the ADT
text-element service are refused. Ordinary edit_text_symbols writes already request
text-pool activation automatically.
For failed DDLS activation, ARC-1 appends CDS dependency impact buckets and a concrete batch re-activation template derived from where-used results.
On a target resolved as BTP, the exact English missing-inbound-service error for an OData
V4 UI binding at version 0001 triggers one fresh active-metadata read. Explicit published
state confirms that the binding is already published; unpublished or unknown state remains
an error with guidance. The original SAP message is retained. There is no delay, automatic
second publish, activation or dependency repair. An unresolved target type does not qualify;
bearer authentication alone is not BTP evidence. Inspect an unpublished binding and its
inbound-service dependencies before deciding whether to publish again.
All publish_srvb calls (including V2/on-prem calls) avoid automatic HTTP replay after
availability or database-session errors. A 429, 5xx or network failure leaves completion
unconfirmed: use SAPRead(type="SRVB", name="…") to inspect state before another publish.
Minimal errors retain HTTP status and request-correlation guidance while hiding SAP details.
Existing authentication/CSRF/content-negotiation handling remains: a 403 on the publish POST
still refreshes the CSRF token and re-sends once, even when the 403 has another cause. Thus
one publish invocation can still contain multiple protocol sends. Unpublish and other
operations keep their existing retry policies.
Examples:
SAPActivate(type="CLAS", name="ZCL_ORDER")
SAPActivate(type="REPT", name="ZREPORT")
SAPActivate(type="INCL", name="LZFGTOP", group="ZFG")
SAPActivate(objects=[{type:"DDLS",name:"ZI_TRAVEL"},{type:"BDEF",name:"ZI_TRAVEL"},{type:"SRVD",name:"ZSD_TRAVEL"}])
SAPActivate(action="publish_srvb", type="SRVB", name="ZUI_TRAVEL_O4", service_type="odatav4")
Note: Not available by default (read-only mode). Enable with SAP_ALLOW_WRITES=true / --allow-writes=true.
SAPNavigate¶
Navigate code: find definitions, references (where-used), code completion, and class hierarchy.
An experimental relations action adds bounded live metadata
networks for qualified ABAP object types. It is listed automatically unless denied or SAP discovery
has established that the capability is absent. Invocation still requires exact discovery evidence.
The existing actions below are unchanged.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | definition, references, completion, or hierarchy |
uri |
string | No | Source URI of the object. Optional for references if type+name are provided. |
type |
string | No | Object type (PROG, CLAS, INTF, FUNC, etc.) — alternative to uri for references. |
name |
string | No | Object name — alternative to uri for references. |
objectType |
string | No | For references: keep only results of this ADT type, slash format (CLAS/OC, PROG/P, FUGR/FF). A bare prefix (CLAS) matches every subtype. Applied client-side. |
maxResults |
number | No | For references: max entries (default 100, max 1000). total counts every match of the filter. |
line |
number | No | Line number (1-based). For references, together with column: search the symbol at that position. |
column |
number | No | ADT cursor column (0-based integer) |
source |
string | No | Current source code |
Experimental relations parameters (when available):
Present automatically in single-target standard mode, unless SAP_DENY_ACTIONS or discovery
establishes that the capability is absent. These rows add to or qualify the table above; existing
actions keep their behavior. Strict-client relation-only placeholders on other actions are ignored.
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | definition, references, completion, hierarchy, or relations (when available) |
type |
string | For relations | CLAS, INTF, DDLS, DCLS, TABL, TTYP, DTEL, DOMA, PROG, INCL, FUNC, FUGR, VIEW, ENHO, ENHS, MSAG, BDEF, SRVD, TRAN, SHLP, SKTD, ENQU, TYPE, EVTB, DSFD. Only BAdI implementation/spot subtypes are qualified for ENHO/ENHS. See type-specific limits. |
name |
string | For relations | Root object name, including namespaced names such as /BOBF/CL_FRW_FACTORY. |
direction |
string | No | For relations: outgoing (default, dependencies) or incoming (usages). |
depth |
integer | No | For relations: expansion depth, 1–3 (default 1). Native edges do not establish exact call distance. |
maxResults |
integer | No | For relations: maximum returned nodes, including the root, 1–100 (default 50). |
expandPackages |
string[] | No | For relations: up to 8 exact package names controlling deeper expansion. Boundary nodes remain visible; no wildcards. |
For relations, use only action, type, name and its four optional parameters above. Other
navigation parameters (uri, objectType, line, column, source) are rejected. See the
experimental guide for coverage limits and examples.
References action (Where-Used): Uses the full scope-based Where-Used API, returning detailed results with package info. Falls back to the simpler reference lookup on older SAP systems that don't support the scope endpoint.
Returns a paged envelope — {total, countMeaning, shown, truncated, hint?, searchedFor?, warning?, references} — because where-used is
unbounded: CL_ABAP_TYPEDESCR has 6,644 references (~968K tokens, several times a context window).
total counts matching reference entries before paging, not distinct consumer objects or runtime
calls. The countMeaning field states this explicitly. Tree/container rows and multiple references
to one object can appear; even an untruncated or empty page is not proof of system-wide completeness.
If optional interface-implementer enrichment fails, native results are retained with a warning.
An absent warning does not prove that enrichment ran or that the result is complete.
Paging and objectType filtering are both client-side, and deliberately so: SAP's
usageReferences endpoint declares only {?uri} and ignores every limit or filter we can send
(verified live across nine request variants, all byte-identical). The full set therefore still
crosses the wire — this bounds what reaches the model, not what SAP computes.
Without a position, references searches the whole object. With line and column (both, as ADT
cursor coordinates: line from 1, column from 0) it searches the symbol at that position in the source
behind uri, for example one method of a class; type+name positions refer to the main source.
ARC-1 sends the cursor as the URI fragment #start=<line>,<column>, replacing any fragment already in
uri. When the cursor is not on an identifier, SAP silently searches the whole object instead. A
position search therefore returns searchedFor: SAP's result description, verbatim, which names
what was searched, for example References for: /SCWM/CL_TM - CLEANUP (Method) [SID] or, after a
fallback, References for: /SCWM/CL_TM (Class) [SID]. The wording differs by release. If SAP omits
the description (including on the older fallback endpoint), a warning says the searched symbol
could not be confirmed. URI fragments supplied directly are preserved when no coordinates are
given. Fragment-scoped searches return native references without adding whole-interface
implementers from SEOMETAREL, unless SAP explicitly reports fallback to the URI's original object
with an empty referencedObjectIdentifier. An absent or nonempty identifier keeps results
native-only: an implementation relationship does not establish a reference to a selected member
or another type mentioned in the source.
Hierarchy action: Returns the class inheritance chain via SEOMETAREL: superclass (or null), implemented interfaces, and direct subclasses. Requires name parameter (class name). It needs either table preview (SAP_ALLOW_DATA_PREVIEW=true + data scope) or freestyle SQL (SAP_ALLOW_FREE_SQL=true + sql scope). ARC-1 uses SQL when available and falls back to named table preview.
Without changing permissions, inspect the global class declaration using
SAPRead(type="CLAS", name="ZCL_ORDER", grep="INTERFACES|INHERITING"). Omit include to read MAIN:
include="definitions" is for local helper classes, not the global declaration. This fallback does
not enumerate subclasses or prove a complete inheritance/implementation list.
Examples:
SAPNavigate(action="definition", uri="/sap/bc/adt/programs/programs/ztest/source/main", line=10, column=5, source="...")
SAPNavigate(action="references", uri="/sap/bc/adt/oo/classes/zcl_order")
SAPNavigate(action="references", type="CLAS", name="ZCL_ORDER")
SAPNavigate(action="references", type="CLAS", name="ZCL_ORDER", line=12, column=12)
SAPNavigate(action="references", type="CLAS", name="ZCL_ORDER", objectType="PROG/P")
SAPNavigate(action="completion", uri="/sap/bc/adt/programs/programs/ztest/source/main", line=10, column=15, source="...")
SAPNavigate(action="hierarchy", name="ZCL_ORDER")
For definition, pass the source URI and current source text, with integer ADT cursor coordinates:
line starts at 1, column at 0. The line must exist in the posted source, and column may
reach its end but not extend beyond it. Place the cursor on the identifier. Returned target coordinates use
the same convention. Object metadata URIs and type+name are insufficient.
The source can contain unsaved changes; ARC-1 does not replace it with a backend read. A returned
target URI may include a cursor fragment; an explicit new line/column replaces that fragment.
completion takes the same inputs: the source URI (SAP rejects object metadata URIs),
the current source text and an ADT cursor (line from 1, column from 0) placed right after
the typed prefix, for example column 3 after DAT. ARC-1 sends the cursor as the URI fragment
#start=<line>,<column>, replacing any fragment already in uri. It returns
{proposals: [{text}], complete, hint?}: keywords and identifiers alike, in SAP's order. The source
can contain unsaved changes to an existing SAP object, such as a variable declared only in the
posted text; the object must already exist. The cursor must fit the posted source. complete: false
means SAP did not confirm completeness: a broad prefix may have more matches, but older backends
also signal this for empty results or invalid positions. Check the cursor/source or narrow the
prefix. The signal is not a count of undisplayed proposals; an empty list contains no returned
proposals, without proving that no matching identifier exists.
SAPQuery¶
When SAP_BLOCKED_DATA_SOURCES is non-empty, SAPQuery is restricted to one statically provable
SELECT/WITH. ARC-1 extracts every join/union/subquery/CTE source and checks live CDS plus DDIC
replacement lineage before sending the query, authorizing the whole request once even when IN-list
chunking splits it. Supported: joins, unions, nested subqueries, CTEs, parameterized CDS roots,
hierarchy sources, aggregates. Refused: ABAP comments, host expressions, FOR ALL ENTRIES, dynamic
sources, WITH PRIVILEGED ACCESS, client override, secondary connections, association/column paths,
SELECT SINGLE, caller INTO targets, multiple statements and CDS table functions.
Outcomes are four stable codes — DATA_SOURCE_BLOCKED, DATA_POLICY_UNAVAILABLE,
DATA_LINEAGE_UNRESOLVED and DATA_SQL_UNSUPPORTED — each meaning the SAP request was not
executed, each carrying executed=false and a decisionId that also appears in the server audit log.
The empty default keeps current behavior and adds no metadata calls; a non-empty list is slower by
design. This experimental blocklist is not an allowlist and not a replacement for SAP authorization or CDS DCL. See
Authorization & Roles.
Execute ABAP SQL queries against SAP tables.
Freestyle SQL uses CRLF line separators and safe wrapping at SAP’s 255-character payload-line boundary, including generated IN-list chunks. Long literals or comments that cannot be split safely are refused; this is not a total-query length cap.
Self-correcting errors. An unknown table yields a "Did you mean …?" suggestion; an unknown column (here or in
SAPRead type=TABLE_QUERY) yields the table's actual column list (Unknown column "X" on T000. Available columns: MANDT, MTEXT, …), so the agent retries in one shot. Best-effort: if column discovery is unavailable (e.g. thedatapreviewendpoint is unbound on older NW 7.50 SPs), the original error is returned unchanged.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
sql |
string | Yes | ABAP SQL SELECT statement |
maxRows |
number | No | Maximum rows (default 100, clamped to 10,000). This is a request ceiling, not a guaranteed result size: wide results can hit the server byte ceiling much earlier. |
Successful data-preview bodies share one cumulative allowance across the complete tool call,
including automatic IN-list chunks. The default is 2 MiB of decompressed transfer bytes, counted
before string conversion. Crossing the configured allowance returns DATA_RESPONSE_TOO_LARGE
without partial rows or an automatic retry. Submit a new request with lower maxRows, fewer
selected columns, or a restrictive, non-overlapping key-range WHERE clause.
Important: Uses the ADT freestyle SQL endpoint (/sap/bc/adt/datapreview/freestyle) with ABAP SQL syntax, NOT standard SQL:
- Use alias~field for qualified fields (not alias.field; a dot ends the ABAP statement)
- Use ASCENDING/DESCENDING (not ASC/DESC)
- Use maxRows parameter (not LIMIT)
- GROUP BY, COUNT(*), WHERE are supported. Some ADT backends (verified on 7.58 and 8.16) fail with a generated TRY/CATCH or missing-ENDSELECT nesting error when COUNT(*) is the only selected expression alongside GROUP BY. Select the grouping columns too, for example SELECT carrid, COUNT(*) AS cnt FROM sflight GROUP BY carrid; this adds result columns without changing the groups. ARC-1 explains this failure without rewriting or retrying the query.
- ABAP SQL aggregate rule applies: non-aggregated selected fields must be listed in GROUP BY
JOINs, aggregates, and subqueries are supported. For a plain projection SELECT, ARC-1 automatically chunks the longest literal IN (...) list—even when the query has several IN clauses—and merges the rows. Queries with ORDER BY, GROUP BY, HAVING, DISTINCT, UNION, or aggregates are sent whole because concatenating per-chunk results would change their semantics. If a backend rejects a long list in one of those queries, split the list manually, union the results, and re-sort client-side when needed.
See: SAPQuery Freestyle Capability Matrix
Examples:
SAPQuery(sql="SELECT carrid, COUNT(*) as cnt FROM sflight GROUP BY carrid ORDER BY cnt DESCENDING")
SAPQuery(sql="SELECT * FROM mara WHERE matnr LIKE 'Z%'", maxRows=50)
Note: Not available by default (free SQL blocked). Enable with SAP_ALLOW_FREE_SQL=true / --allow-free-sql=true. User also needs the sql scope (or API-key profile viewer-sql/developer-sql/admin).
SAPTransport¶
Manage CTS transport requests (SE09/SE10 equivalent): list, get details, diff (review what a transport changed), create, release, delete, reassign owner, recursive release, check transport requirements, and inspect an object's current lock/assignment status. The legacy action name for that status lookup is history, but it is not complete transport history. create uses the ADT CreateCorrectionRequest endpoint, which works on both NetWeaver 7.50+ and S/4HANA.
In multi-target v1, only the read-only list, get, check, and history actions are listed and
accepted. Transport mutations and topology actions remain structurally unavailable; diff is also
excluded there because it fans out many source reads per call.
action="diff" — reviewing what a transport changed¶
Returns, per object, a unified diff between the revision written under the transport and the one immediately before it. LIMU entries (methods, class includes) are rolled up to their owning class, and a class is diffed across the includes the transport actually touched.
Every part carries the evidence behind its diff — read baselineStatus before summarising:
baselineStatus |
Meaning |
|---|---|
prior-revision |
The diff is what this transport changed. |
prior-revision-unverified |
A predecessor exists, but the "after" side was only guessed — it may belong to another change. |
no-prior-snapshot |
Created in this transport. |
baseline-ambiguous |
No usable baseline. An all-additions block is not proof of creation. |
baseline-unavailable |
The read failed. Never report this as unchanged. |
Objects with no source revision feed (domains, data elements, function-group sources, …) are returned
with an inventoryReason instead of parts: they are in scope, just not diffable. Long diffs are
truncated per part with diffTruncated: true; added/removed still reflect the full change.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | list, get, diff, create, release, delete, remove_object, reassign, release_recursive, check, history, layers, or targets (the last two are advertised only when transport support is enabled) |
id |
string | No | Transport request ID, e.g. A4HK900123 (for get/diff/release/delete/remove_object/reassign/release_recursive) |
offset |
number | No | For diff: index of the first object to diff (default 0). Page with limit. |
limit |
number | No | For diff: objects per call (default 20, max 40 — the same ceiling SAP's own transport-diff tool uses). |
description |
string | No | Transport description text (required for create) |
name |
string | No | Object name (for check/history/remove_object actions, e.g. ZCL_ORDER) |
package |
string | No | Package name. For create: optional — defaults to $TMP; an explicit package influences the route/target while the request remains Workbench type K. For check: required. |
target |
string | No | Explicit create target (C11, C11.021, or /TRG/). SAP validates it; system.client/group forms require extended transport control, and 7.50 does not support the target-setting ADT action. Discover valid values with action="targets"; never invent one. |
transportLayer |
string | No | Advanced create override for SAP's consolidation-route resolution. Omit normally so the package chooses the route; discover valid values with action="layers". |
user |
string | No | SAP username to filter by (for list). Defaults to the current SAP user. Use * to list all users. |
status |
string | No | Transport status filter (for list). D=modifiable (default), L=modifiable/protected, O=release started, P=release preparation, R=released, N=released with import protection, *=all statuses. |
type |
string | No | Object type for check/history/remove_object actions (PROG, CLAS, DDLS, etc.). For remove_object it is the CTS/E071 object type exactly as shown by get (e.g. PROG, DEVC). Not used by create, which creates a Workbench (K) request. |
group |
string | No | Parent function group for FUNC or a group-scoped INCL in check/history. Existing FUNC resolves its group through search when omitted; a new FUNC needs an explicit group. Pass the group for structural includes; omit it for standalone INCL. |
operation |
string | No | For check: create (default, sends ADT operation I) or modify (sends the empty modify operation). |
pgmid |
string | No | Program ID for remove_object: R3TR (whole object) or LIMU (sub-object). Required for remove_object — the object type alone does not determine pgmid. |
owner |
string | No | New owner SAP username (required for reassign) |
recursive |
boolean | No | Apply recursively to child tasks (for delete/reassign). release_recursive always recurses. |
removeLockedObjects |
boolean | No | For delete: remove locked object entries from each task before deleting when SAP would otherwise reject the request as containing locked objects. This mutates request contents. |
summary |
boolean | No | For list only. Default true — headers-only: omits each transport's (and task's) objects[], keeping id/description/owner/status/target plus an objectCount. Pass false for full object lists (~5x larger). |
maxResults |
number | No | Maximum list rows or check/history assignment candidates (defaults: list/history 50, check 10; max 1000). |
resultFormat |
string | No | For release/release_recursive: legacy text (default) or structured JSON with outcome, per-ID confirmation evidence, polls, elapsed time, and SAP reports. |
timeoutSeconds |
number | No | For release/release_recursive: terminal-state verification budget; default 300, range 1..1800. |
Actions:
list— List transport requests. Defaults to current user, modifiable (status D), all types (Workbench, Customizing, Transport of Copies). Returns a paged envelope{total, shown, truncated, transports}—totalis the full backlog, so a capped page still reports it. Summarised by default (object lists dropped,objectCountkept): scan cheaply, thengetthe one you want in full; passsummary=falsefor the object lists. Paged atmaxResults(default 50, max 1000). Live: 55 requests went 104 KB / ~26K tokens → 23 KB / ~5.7K tokens.get— Get transport details including tasks and objects.create— Create a new Workbench (K) transport request. Requiresdescription. Optionalpackage(defaults to$TMP— pass an explicit package to influence the transport route/target, not the request category). Uses the ADTCreateCorrectionRequestendpoint (POST /sap/bc/adt/cts/transports); legacy NW 7.50 systems are supported.release— Release a single request or task, then verify terminal CTS evidence. Requests are read back inRorN; released tasks may disappear from SAP's organizer tree and are then confirmed only after an accepted release report. Timeout, unknown state, or unexplained disappearance is an error. UseresultFormat="structured"for convergence evidence.delete— Delete a transport. Userecursive=trueto delete tasks first.removeLockedObjects=truefirst strips locked entries from each task when necessary; it is not a dry-run option.remove_object— Remove a single object from a request while keeping the request (the SE09/SE10 "remove from request" operation). Requires the full CTS object keypgmid+type+name(the object type alone does not determinepgmid— e.g.COMMis valid under bothR3OBandLIMU). ARC-1 resolves the entry from the request's object list and removes it via the ADTremoveobjectoperation; the object itself is not deleted. Functional on SAP_BASIS 7.58/8.16; on NW 7.5x the backend ignoresremoveobject(HTTP 400) — clean such requests in SE09/SE10.reassign— Change transport owner. Requiresowner. Userecursive=truefor tasks too.release_recursive— Freeze the original parent/task tree, release its unreleased tasks first and then the parent, and verify every frozen ID. Requests must be read back in terminalRorN; released tasks that SAP folds out of the tree are confirmed by an accepted task release or the terminal parent. An unexplained disappearance, timeout, or unknown state is an error. This action is refused under restrictive exact/prefixSAP_ALLOWED_TRANSPORTS; only the legacy empty allowlist or explicit*can authorize a live subtree that may gain a concurrent child. Use either only when every current/concurrent child is intended to be released.check— Check whether a transport is required for creating or modifying an object in a specific package. Requirestype,name, andpackage;operationdefaults tocreate. Returns whether a transport is required, whether a new assignment is required, local-package status, bounded candidate requests, SAP diagnostics, and any existing lock with owner/task details. Does NOT require--allow-transport-writes— this is a read-only pre-flight check.history— Legacy action name for current object transport status. Giventype+name, it returns at most the request currently holding the object lock inrelatedTransports, plus boundedcandidateTransportsthe object could be assigned to. Candidates do not contain the object and are not historical/conflict evidence. Complete history requires an authorized E071/E070 data workflow because the standard ADT endpoints expose only current assignment state. Read-only; does NOT require--allow-transport-writes.layers— List the transport layers and their resolved targets where available. Read-only value help forcreate.transportLayer; release-dependent.targets— List valid transport targets (Transportziel / TR_TARGET). Read-only value help forcreate.target; release-dependent.
Check action output:
{
"operation": "create",
"package": "ZDEV",
"transportRequired": true,
"transportAssignmentRequired": true,
"isLocal": false,
"deliveryUnit": "HOME",
"result": "S",
"existingTransportTotal": 1,
"existingTransportsShown": 1,
"existingTransports": [
{ "id": "A4HK900123", "description": "My transport", "owner": "DEVELOPER" }
],
"existingTransportsTruncated": false,
"summary": "Package \"ZDEV\" requires a transport assignment for object creation."
}
Current object transport status output (history legacy action name):
{
"object": { "type": "CLAS", "name": "ZCL_ORDER", "uri": "/sap/bc/adt/oo/classes/zcl_order" },
"relatedTransports": [],
"candidateTransports": [
{ "id": "A4HK900124", "description": "Refactor", "owner": "DEVELOPER" }
],
"candidateTotal": 1,
"candidateTruncated": false,
"summary": "Object ZCL_ORDER has no active lock; 1 transport(s) available for assignment."
}
When an object is currently locked, lockedTransport is present, relatedTransports contains that
one parent request, and candidateTransports is empty.
List defaults: Without parameters, list returns modifiable transports (status D) for the current SAP user, across all transport types (Workbench, Customizing, Transport of Copies). Query params follow sapcli's workbench_params() pattern (requestType=KWT, requestStatus).
Protocol compatibility: ARC-1 uses startup ADT service discovery (/sap/bc/adt/discovery) to proactively select endpoint MIME types, with endpoint-specific CTS media types and a one-retry 406/415 fallback as defense-in-depth.
Note: Transport mutations (create, release, release_recursive, reassign, delete, remove_object) require write + transports scopes and both SAP_ALLOW_WRITES=true and SAP_ALLOW_TRANSPORT_WRITES=true. list, get, diff, check, history, layers, and targets are read actions and work without --allow-transport-writes.
SAPGit¶
Git-based ABAP repository workflows with backend auto-selection: gCTS is preferred when available, otherwise ARC-1 uses the abapGit ADT bridge. gCTS is currently read-only in ARC-1; its mutation actions fail closed before any mutating HTTP request.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | list_repos, whoami, config, branches, external_info, history, objects, check, stage, clone, pull, push, switch_branch, create_branch, unlink |
backend |
string | No | Optional backend override: gcts or abapgit |
repoId |
string | No | Repository ID/key (required by most repo-scoped actions) |
url |
string | No | Remote Git URL (required for clone, and for abapGit external_info) |
branch |
string | No | Branch name (for switch/create branch) |
package |
string | No | ABAP package (required for clone/create on package-bound backends) |
transport |
string | No | Transport request (backend-dependent) |
commit |
string | No | Commit SHA (for gCTS pull by commit) |
message |
string | Yes for push |
Commit message for abapGit push |
objects |
array | No | For abapGit push, the changed objects to commit ([{type,name}]); omit to push every local change |
user |
string | No | Remote Git username |
password |
string | No | Remote Git password |
token |
string | No | abapGit remote token, sent as basic auth with user x-access-token (GitHub convention) unless user is also given. gCTS mutations, including credential-bearing repository creation, are quarantined. |
limit |
number | No | Limit for history queries (gCTS) |
Backend support matrix:
- Both backends:
list_repos - gCTS reads:
whoami,config,branches,history,objects - abapGit only:
external_info,check,stage,clone,pull,push,switch_branch,create_branch,unlink - gCTS mutation names, currently quarantined:
clone,pull,switch_branch,create_branch,unlink
Safety and scope rules:
- Repository/configuration reads require
readscope (HTTP auth mode). - abapGit mutations (
clone,pull,push,stage,switch_branch,create_branch,unlink) requiregitscope,SAP_ALLOW_WRITES=true, andSAP_ALLOW_GIT_WRITES=true. external_infoalso requires those mutation gates. Although it returns metadata, SAP performs outbound network access to a caller-selected remote URL. All remote URLs must be absolute HTTPS without userinfo;external_infoadditionally rejects localhost and literal private/link-local addresses. DNS-aware resolution/hostname allowlisting remains a follow-up.- Package-bound clone and repository actions that import, export, change branch, or unlink enforce the
configured allowlist against the real server-side package. A caller-supplied package cannot widen
that boundary. The allowlist must contain the exact repository subtree pattern (
<ROOT>/**) or*; an exact root entry or a broad prefix such asZ*is not sufficient for these subtree-wide operations. - Every gCTS mutation is additionally quarantined and returns an error before HTTP mutation, even when the write gates are enabled. Safe support is deferred until ARC-1 can stage without import, inventory affected objects, preflight authorization, deploy explicitly, confirm terminal state, and roll back.
abapGit private repositories: pass user + password, or just token. ARC-1 forwards them to the
bridge on every remote-touching call — external_info, clone, pull, check, stage, push,
switch_branch, create_branch — as the Username / base64 Password headers the abapGit ADT backend
reads. They are request-scoped: never stored, never logged (the Password header is redacted). In CLI
automation, load them from a protected JSON input or secret-backed workflow rather than literal argv.
Mutation evidence and retry contract:
- abapGit
clone/pullresponses report bridge object rows and repository readback, not complete import/activation reconciliation. Non-empty rows are returned withverified:false; an empty wrapper is an incomplete/error result, never proof that an import succeeded. pushwith no selected local changes is a verified no-op. After a selected push is accepted, ARC-1 returns error/incomplete (accepted:true,verified:false) because the bridge exposes no authoritative remote-commit postcondition.switch_branchandcreate_branchlikewise return error/incomplete after acceptance: repository readback does not prove imported objects or activation.unlinksucceeds only after repository absence is read back. A failed readback or still-present repository is error/incomplete.
For the latter incomplete outcomes, the mutation may already have happened. Do not retry blindly; inspect the remote/repository state first. The latest postcondition hardening is adversarially unit tested, but the final A4H pass sent no Git mutation and is not presented as final live verification.
abapGit push stages first, then commits the objects you select: ARC-1 calls the stage endpoint, keeps
the objects (with their file lists) that match objects, and sends them back with your message. Author
and committer come from the git user abapGit has stored for the repo, so no identity parameters are needed.
A push with no matching local change is reported as a no-op instead of an empty commit; a selected push
uses the accepted-but-incomplete contract above.
Examples:
SAPGit(action="list_repos")
SAPGit(action="whoami", backend="gcts")
SAPGit(action="config", backend="gcts")
SAPGit(action="history", backend="gcts", repoId="ZARC1", limit=20)
SAPGit(action="external_info", backend="abapgit", url="https://github.com/abapGit-tests/CLAS.git")
SAPGit(action="switch_branch", repoId="000000000006", branch="main", backend="abapgit")
SAPGit(action="clone", backend="abapgit", package="$TMP", url="https://github.com/org/repo.git")
SAPGit(action="clone", backend="abapgit", package="$TMP", url="https://github.com/org/private.git", token="ghp_…")
SAPGit(action="stage", backend="abapgit", repoId="000000000001")
SAPGit(action="push", backend="abapgit", repoId="000000000001", message="Add order validation")
SAPContext¶
Get dependency API contracts, CDS impact, DDIC structure, or live where-used evidence.
action="deps" prepends the object's Knowledge Transfer Document (SKTD/KTD) when one exists, then returns compressed, source-derived dependency contracts. For business purpose, reviews or test design, start here, then verify implementation with SAPRead. Base specification-test expectations on requirements: a boundary test should fail on a mismatch, not preserve a bug as intended behavior. Requirements may also come from the user or other documentation; without them, intent is unverified. For exact behavior or a known reference, targeted SAPRead alone may suffice; contracts are not implementation.
SAPContext has four modes controlled by the action parameter:
Quick decision rule:
- "What breaks if I change
<CDS view>?" / "Who consumesI_*?" / "Impact of<DDLS>" →action="impact" - "Which dependency APIs do I need for this change?" →
action="deps"(default) - "Who calls
<object>?" →action="usages"(live SAP where-used) - "Which includes/appends extend this table?" →
action="structure"
Do not hand-roll CDS impact analysis by querying
DDDDLSRC,ACMDCLSRC,DDLXSRC_SRC, orSRVDSRC_SRCviaSAPQuery. Those text-scans produce substring-match noise and package group nodes.action="impact"uses SAP's where-used index and returns deduplicated, RAP-classified results.
action="deps" (default) — Dependency context¶
Returns the target object's KTD first when available, followed by public API contracts (method signatures, interface definitions, type declarations) for a bounded selection of source-derived dependencies. It is not a complete SAP-native relationship inventory or proof of runtime calls. Token savings depend on the source and selected contracts.
What gets extracted per dependency:
- Classes: CLASS DEFINITION with PUBLIC SECTION only. PROTECTED, PRIVATE sections and CLASS IMPLEMENTATION are stripped.
- Interfaces: Full interface definition (interfaces are already public contracts).
- Function modules: FUNCTION signature block only (IMPORTING/EXPORTING parameters). Function body is stripped.
Filtering: SAP standard objects (CL_ABAP_*, IF_ABAP_*, CX_SY_*) are excluded by default. Custom objects (Z*, Y*) are prioritized in the output.
Dependency detection: Uses @abaplint/core AST parsing to find TYPE REF TO, NEW, CAST, INHERITING FROM, INTERFACES, CALL FUNCTION, RAISING, CATCH, and static method calls (=>).
Function-module bodies support classic and ADT inline signatures; parameter types in the signature
are not dependency candidates. DDIC types referenced in a body may still be tried as classes and
fail, consuming maxDeps before later candidates. Failed lookups do not prove those objects are absent.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | No | "deps" (default), "usages", "impact", or "structure" |
type |
string | Yes for deps/structure, even with source; optional for impact/usages | Object type: CLAS, INTF, PROG, FUNC, DDLS, TABL |
name |
string | Yes, even with source | Object name (e.g., ZCL_ORDER) |
source |
string | No | Provide source directly instead of fetching from SAP |
includeKtd |
boolean | No | Only for action="deps". Defaults to true; prepends the object's KTD (SKTD/KTD) when one exists. Set false to skip the KTD lookup. Ignored when source is supplied. |
group |
string | No | Required for FUNC type. The function group name. |
maxResults |
number | No | For usages: maximum entries (default 100); for impact: maximum per downstream bucket (default 50), hard max 1000. Totals remain uncapped counts. |
maxDeps |
number | No | Maximum dependencies to resolve (default 20) |
depth |
number | No | Dependency depth: 1 = direct only (default), 2 = deps of deps, 3 = max |
includeIndirect |
boolean | No | Only for action="impact" (DDLS): include indirect downstream where-used entries (default false) |
siblingCheck |
boolean | No | Only for action="impact": run sibling metadata-extension consistency analysis (default true) |
siblingMaxCandidates |
number | No | Only for action="impact": max sibling DDLS candidates to compare (default 4, hard cap 10) |
Examples:
SAPContext(type="CLAS", name="ZCL_ORDER")
SAPContext(type="CLAS", name="ZCL_ORDER", depth=2, maxDeps=10)
SAPContext(type="INTF", name="ZIF_ORDER", source="<already fetched source>")
SAPContext(action="deps", type="CLAS", name="ZCL_ORDER")
SAPContext(action="structure", type="TABL", name="BAPIRET2")
Output format:
* === Knowledge Transfer Document for ZCL_ORDER ===
# ZCL_ORDER
Business intent and object notes from the KTD.
* === Dependency context for ZCL_ORDER (3 deps resolved) ===
* Source-derived dependency contracts; not complete dependency coverage or runtime evidence.
* --- ZIF_ORDER (intf, 4 methods) ---
INTERFACE zif_order PUBLIC.
METHODS create IMPORTING order TYPE t_order.
...
ENDINTERFACE.
* --- ZCL_ITEM (clas, 3 methods) ---
CLASS zcl_item DEFINITION PUBLIC.
PUBLIC SECTION.
METHODS get_price RETURNING VALUE(result) TYPE p.
...
ENDCLASS.
* Coverage is not complete: source-derived, filtered and depth/count-limited; deeper unexpanded work is not counted.
* Stats: 5 root candidates after filtering; 2 root candidates not fetched; across explored levels: 3 resolved, 0 failed.
Root candidates and recursive attempts have different scopes: do not subtract the all-level
resolved/failed totals from the root total. "Not fetched" counts unattempted root names only;
deeper unexpanded work is unknown. A failed dependency read does not establish that the name is
absent as another SAP object type. Resolve its type with SAPSearch before retrying a different
reader. For ordinary DDIC reads, omit format or use "text"; "structured" is CLAS-only.
If the object has no KTD or the backend returns 404/410 for the KTD document, ARC-1 silently omits the KTD section and still returns the dependency context. Other KTD read errors are surfaced normally.
Dependency context is recomputed on each call; a root hash cannot validate changed dependencies.
Normal ETag-validated source caching remains, so unchanged dependency bodies can still use 304
responses. Pure contract/dependency parsing is reused by content hash after source retrieval;
principal-propagation dependency calls bypass that memoization. The old aggregate [cached]
shortcut is no longer used. See
Caching System → Dependency context.
action="structure" — DDIC includes + append structures (TABL only)¶
Returns a JSON tree for a DDIC structure or transparent table. ARC-1 parses embedded includes from the TABL source (include <name>;, named includes, and classic .INCLUDE) and resolves append/extension structures through ADT where-used. Append candidates are only returned after ARC-1 reads the candidate source and confirms it contains extend type <base> with; .APPEND is not parsed from the base source because ADT does not emit append structures there.
Example:
{
"name": "ZMCP_SHR_STRU",
"type": "TABL",
"includeExtensions": true,
"tree": {
"structure": "ZMCP_SHR_STRU",
"attribute": null,
"kind": "root",
"children": [
{ "structure": "ZMCP_SHR_STRU_INC", "attribute": null, "kind": "include", "children": [] },
{ "structure": "ZOK_S_APPEND", "attribute": null, "kind": "append", "children": [] }
]
},
"summary": {
"totalNodes": 3,
"includes": 1,
"appends": 1,
"cyclic": 0,
"unresolved": 0,
"truncated": 0
}
}
action="impact" — CDS upstream + downstream impact (DDLS only)¶
Returns a single JSON payload with:
- upstream dependencies from CDS AST extraction (tables, views, associations, compositions)
- downstream where-used consumers classified into RAP-relevant buckets (projectionViews, bdefs, serviceDefinitions, serviceBindings, accessControls, metadataExtensions, abapConsumers, documentation, etc.)
- consistencyHints (additive): human-readable hints when sibling DDLS variants in the same package have asymmetric DDLX coverage
- siblingExtensionAnalysis (additive): structured details about sibling candidate filtering and metadata-extension counts
Use this to answer: "If I change this CDS view, what breaks?"
Example:
SAPContext(action="impact", type="DDLS", name="ZI_ARC1_I33_ROOT")
SAPContext(action="impact", type="DDLS", name="ZI_ARC1_I33_ROOT", includeIndirect=true)
SAPContext(action="impact", type="DDLS", name="ZI_ARC1_I33_ROOT", siblingCheck=false)
SAPContext(action="impact", type="DDLS", name="ZI_ARC1_I33_ROOT", siblingMaxCandidates=6)
Output (shape):
{
"name": "ZI_ARC1_I33_ROOT",
"type": "DDLS",
"upstream": {
"tables": [{ "name": "ZTABL_ARC1_I33" }],
"views": [],
"associations": [],
"compositions": []
},
"downstream": {
"projectionViews": [{ "name": "ZI_ARC1_I33_PROJ", "type": "DDLS/DF" }],
"bdefs": [],
"serviceDefinitions": [],
"serviceBindings": [],
"accessControls": [],
"metadataExtensions": [],
"abapConsumers": [],
"tables": [],
"documentation": [],
"other": [],
"summary": { "total": 1, "direct": 1, "indirect": 0, "byBucket": { "projectionViews": 1 } }
},
"summary": { "upstreamCount": 1, "downstreamTotal": 1, "downstreamDirect": 1 },
"consistencyHints": [
"Possible sibling metadata-extension inconsistency: ..."
],
"siblingExtensionAnalysis": {
"stem": "ZI_ARC1_I33_ROOT",
"maxCandidates": 4,
"consideredCandidates": 2,
"checkedCandidates": [
{ "name": "ZI_ARC1_I33_ROOT2", "packageName": "ZARC1", "metadataExtensions": 1, "downstreamTotal": 3 }
]
}
}
Sibling analysis is best-effort and bounded. Any sibling-search or sibling where-used failures are returned as warnings while the primary impact result still succeeds.
action="usages" — Reverse dependency lookup¶
Queries SAP's live where-used index for objects that depend on the target (i.e., "who calls/uses this?"). The lookup uses the current caller's SAP identity and works with memory, SQLite, or no cache. SAPNavigate(action="references") uses the same live lookup but returns the navigation-oriented result directly.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | "usages" |
name |
string | Yes | Object name to look up (e.g., ZCL_ORDER, ZIF_ORDER) |
type |
string | No | Object type. Recommended when known; otherwise ARC-1 performs exact-name resolution and continues only for one unambiguous match. |
Example:
Output:
{
"name": "ZIF_ORDER",
"resolvedObject": {
"type": "INTF",
"name": "ZIF_ORDER",
"uri": "/sap/bc/adt/oo/interfaces/zif_order"
},
"usageCount": 2,
"countMeaning": "Reference entries, not distinct objects or runtime calls; not a complete inventory.",
"shown": 2,
"truncated": false,
"usages": [
{ "name": "ZCL_ORDER", "type": "CLAS/OC", "uri": "/sap/bc/adt/oo/classes/zcl_order" },
{ "name": "ZCL_ORDER_EXTENDED", "type": "CLAS/OC", "uri": "/sap/bc/adt/oo/classes/zcl_order_extended" }
],
"source": "live",
"fallbackUsed": false
}
usages is paged (maxResults, default 100, max 1000) because a where-used lookup on a common
object is unbounded — CL_ABAP_TYPEDESCR returns 6,644 references. usageCount counts reference
entries before paging, not distinct objects or runtime calls (shown is the page length).
countMeaning explains the count; an optional warning reports failed interface-implementer
enrichment without discarding native results. No warning is not proof of complete coverage.
For class-only results use SAPNavigate(action="references", objectType="CLAS/OC", type=..., name=...);
SAPContext.usages has no result-type filter. Navigation uses total and references instead of
usageCount and usages. SAPContext(action="impact") caps each downstream bucket while summary
keeps the unsliced bucket counts, not a guarantee of every system dependency.
If exact name resolution finds multiple object types, ARC-1 returns a bounded candidate list and asks for type instead of guessing.
SAPLint¶
Run local abaplint rules on ABAP source code. System-aware: auto-selects cloud or on-prem rules based on detected system type. For SAP syntax checks use SAPRead(type="SYNTAX"); for ATC or unit tests use SAPDiagnose.
In multi-target v1, only the offline lint, lint_and_fix, and list_rules actions are listed and
accepted. format and formatter-settings actions contact or modify SAP and remain unavailable.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | lint, lint_and_fix, list_rules, format, get_formatter_settings, or set_formatter_settings |
source |
string | No | ABAP source code (for lint, lint_and_fix, and format) |
name |
string | No | Object name (used for filename detection) |
indentation |
boolean | No | PrettyPrinter indentation toggle (for set_formatter_settings) |
style |
string | No | PrettyPrinter keyword style: keywordUpper, keywordLower, keywordAuto, or none (for set_formatter_settings) |
rules |
object | No | Rule overrides: { "rule_name": false } to disable, { "rule_name": { "severity": "Warning" } } to configure |
Actions:
lint— Check ABAP source for issues. Returns errors and warnings with line/column positions.lint_and_fix— Lint + auto-fix all fixable issues (keyword case, obsolete statements, etc.). Returns the fixed source code alongside remaining unfixable issues.list_rules— List all available rules with current config (preset, enabled/disabled status, severity). No source needed.format— Pretty-print ABAP source via SAP ADT PrettyPrinter using the SAP system's global formatter settings. Returns formatted source text.get_formatter_settings— Read SAP global PrettyPrinter settings (indentation + keyword style).set_formatter_settings— Update SAP global PrettyPrinter settings. Provide at least one ofindentationorstyle. Requireswritescope andSAP_ALLOW_WRITES=true.
System-Aware Presets:
The lint rules auto-configure based on the detected SAP system:
- BTP/Cloud: cloud_types (Error), strict_sql (Error), obsolete_statement (Error) — enforces ABAP Cloud constraints
- On-premise: cloud_types (disabled), obsolete_statement (Warning) — more relaxed, allows classic ABAP
Use SAPLint(action="list_rules") to inspect the effective configuration:
presetSource:probe,config, ordefault(on-prem assumed).abapVersion: the SAP release, orunknown;abapVersionSourceisprobe,config, orunknown.syntaxVersion: the actual parser setting after custom configuration, such asv758or{ "release": "Newest", "language": "Cloud" }. This is distinct from the SAP release.warnings: explains unknown-release findings using that effective syntax. Without a detected or configured release, standalone on-prem lint defaults to v702; Cloud and custom syntax settings can differ.
Cached probe settings take precedence over lint's configuration fallback. The probe itself honors
an explicit SAP_SYSTEM_TYPE override and preserves its config origin. A custom
SAP_ABAPLINT_CONFIG can override lint syntax without changing the reported SAP release.
Pre-Write Validation:
When --lint-before-write is enabled (default: true), SAPWrite automatically runs a strict subset of lint rules before writing to SAP. Parser errors and cloud violations block the write. Style issues (keyword case, indentation) never block writes. A blocked-write error includes the actual abaplint syntax used for that check, including custom syntax overrides.
edit_unit and add_unit validate the resulting whole source, including unchanged FORMs. When neither probe
nor configuration supplies a release, this action uses the on-prem parser ceiling (currently v758)
for unit lookup and pre-write validation. This is an operation-specific grammar fallback, not a
detected SAP release; standalone SAPLint list_rules still reports its own v702 fallback in that
case. Known probe/config releases and custom lint syntax overrides retain precedence. Configure
SAP_ABAP_RELEASE to the verified target release when detection is unavailable. If SAP accepts a
statement that local lint rejects, verify these settings before changing valid source; malformed
replacements still block, and lint should stay enabled while diagnosing the mismatch.
Execution mode note:
lint, lint_and_fix, and list_rules run locally in ARC-1. format and *_formatter_settings actions call the SAP system (ADT PrettyPrinter endpoints).
Custom Configuration:
Use --abaplint-config /path/to/abaplint.jsonc to load custom rules. The file uses the abaplint config format:
{
// Override specific rules
"rules": {
"line_length": { "severity": "Error", "length": 80 },
"abapdoc": true, // re-enable a disabled rule
"obsolete_statement": false // disable a rule
},
// Optional: override syntax version
"syntax": { "version": "v757" }
}
Rules from the config file are merged on top of the auto-detected preset (cloud/on-prem). Per-call overrides via the rules parameter take precedence over the config file.
Response shapes:
lintreturns:[{ rule, message, line, column, endLine, endColumn, severity }]lint_and_fixreturns:{ fixedSource, appliedFixes, fixedRules, remainingIssues }— usefixedSourceas the corrected codelist_rulesreturns:{ preset, presetSource, abapVersion, abapVersionSource, syntaxVersion, enabledRules, disabledRules, rules, disabledRuleNames, warnings }— effective configuration and provenance, as described aboveformatreturns: plain text (formatted ABAP source)get_formatter_settingsreturns:{ indentation, style }set_formatter_settingsreturns:{ indentation, style }(effective merged settings)
Examples:
SAPLint(action="lint", source="DATA lv_test TYPE string.\nlv_test = 'hello'.")
SAPLint(action="lint_and_fix", source="data lv_x type i.\nadd 1 to lv_x.", name="ZCL_TEST")
SAPLint(action="list_rules")
SAPLint(action="format", source="report ztest. data lv type string.")
SAPLint(action="get_formatter_settings")
SAPLint(action="set_formatter_settings", style="keywordLower")
SAPLint(action="lint", source="...", rules={"line_length": {"severity": "Error", "length": 80}})
SAPDiagnose¶
Server-side code analysis and runtime diagnostics: syntax check, ABAP unit tests, ATC checks, CDS
test-case scaffolding, active/inactive object state, short dumps (ST22), ABAP profiler trace
arming/list/analysis, SM02 messages, Gateway errors, the on-prem STUSERTRACE authorization trace, an
OData performance probe (sap-statistics), CDS Show-SQL, and ST05 trace control.
Multi-target v1 includes atc and unittest under the existing read scope. They do not mutate
repository objects, but they execute SAP workloads and may create transient worklists/results;
administrators can disable them with SAP_DENY_ACTIONS.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | syntax, unittest, unittest_ci, atc, atc_ci, atc_variants, cds_testcases, dumps, traces, trace_start, trace_requests, trace_cancel, system_messages, gateway_errors, object_state, quickfix, apply_quickfix, odata_perf, cds_sql, sql_trace_state, set_sql_trace_state, sql_trace_directory, or authorization_trace |
name |
string | No | Object or package name (required for syntax/unittest/object_state/quickfix/apply_quickfix, and atc without objects; the CDS entity / DDLS source name for cds_testcases and cds_sql) |
objects |
array | No | ATC only: 1–20 {type,name} entries instead of top-level name, type, or url. Supported: CLAS, INTF, PROG, FUGR, DDLS, DCLS, BDEF, DDLX, SRVD, SRVB, TABL, DTEL, DOMA. TABL includes tables and structures (TABL/DT and TABL/DS aliases). Names and type aliases are normalized; duplicates execute once. No package expansion or per-item system selection. PROG is on-premises only. |
url |
string | No | For odata_perf: the host-relative OData path to probe (from the Fiori app's Network tab), e.g. /sap/opu/odata4/sap/.../Entity?$filter=.... Must be a path on the SAP system ARC-1 connects to — absolute URLs are rejected. |
type |
string | No | Object type. unittest supports CLAS, PROG, FUGR, and DEVC (package); other actions accept their documented ADT types. |
sourceUri |
string | No | Exact ADT source URI for quickfix/apply_quickfix; defaults to the type/name main source. Use it for class-local includes. |
version |
string | No | For syntax: active (default) or inactive. |
coverage |
boolean | No | For unittest: also return statement/branch/procedure coverage for the object, plus methodsBelowFull (methods under 100% statement coverage, worst first), in one extra round-trip. Default false. |
includeSubpackages |
boolean | No | For unittest with type="DEVC": include the package subtree. Default false selects only objects whose actual package is name. Rejected for other types/actions. |
resultFormat |
string | No | For unittest: legacy (default), structured, or junit; JUnit uses SAP's public asynchronous AUnit endpoint when available and otherwise generates JUnit from the legacy result. For atc: legacy or structured; junit is rejected because ATC JUnit output is not implemented. Other actions reject this parameter. Dedicated CLI checks choose their required format automatically. |
timeoutSeconds |
number | No | For unittest or atc: execution and verification budget; default 300, range 1..3600. Timeout is incomplete evidence, never a pass. For atc_ci / unittest_ci: overall budget, default 600, range 1..3600. |
source |
string | No | Current source code (required for quickfix and apply_quickfix) |
line |
number | No | Source line number (required for quickfix and apply_quickfix) |
column |
number | No | Source column number (optional for quickfix and apply_quickfix, default 0) |
proposalUri |
string | No | Quickfix proposal URI from quickfix response (required for apply_quickfix) |
proposalUserContent |
string | No | Opaque proposal state from quickfix response (required for apply_quickfix) |
proposalAffectedObjects |
array | No | Optional affected-object rows returned by quickfix. Preserve each URI and include current content when applying a multi-object proposal. |
id |
string | No | Dump ID, profiler trace ID, or armed trace-request ID to cancel. Omit for list actions. |
detailUrl |
string | No | For Gateway-error detail: canonical host-relative /sap/bc/adt/gw/errorlog/... path. Absolute URLs, traversal, encoded separators, and non-canonical encodings are rejected. |
errorType |
string | No | Gateway error type required when requesting detail by id rather than detailUrl, e.g. Frontend Error. |
user |
string | No | SAP-user filter for dumps, runtime feeds, or authorization_trace |
authObject |
string | No | For authorization_trace: filter to one authorization object, for example S_TCODE |
from |
string | No | Lower time boundary for system_messages/gateway_errors. |
to |
string | No | Upper time boundary for system_messages/gateway_errors. |
onlyFailures |
boolean | No | For authorization_trace: return only denied checks (RC <> 0) |
maxResults |
number | No | Maximum results (default 50 for dumps/feeds, 100 for authorization_trace; safely capped) |
sections |
array | No | Dump chapter IDs for detail mode, e.g. ["kap0","kap3","kap8"]; omit for focused defaults. |
includeFullText |
boolean | No | Dump detail only: include the full formatted text blob. Default false to limit tokens. |
variant |
string | No | ATC check variant name (atc / atc_ci; name filter for atc_variants) |
packages |
array | No | Object set for atc_ci / unittest_ci: explicit package names (1..40 characters). Up to 50 total entries across both lists. |
packageTrees |
array | No | Object set for atc_ci / unittest_ci: packages plus their subpackages. |
configuration |
string | No | atc_ci: optional ATC configuration name. |
includeReportXml |
boolean | No | CI actions: include XML reports up to a combined 256 KiB cap (default false). |
failOnSeverity |
string | No | atc_ci: error (default), warning, or info |
sqlOn |
boolean | No | For set_sql_trace_state: true arms the ST05 SQL trace, false disarms it (combine with user to filter to one SAP user) |
analysis |
string | No | For trace detail: hitlist, statements, or dbAccesses |
traceUser |
string | No | For trace_start/trace_requests: SAP user whose matching execution is traced/listed; defaults to the connected user. |
processType |
string | No | For trace_start: any, http (default), dialog, batch, or rfc. |
objectType |
string | No | For trace_start: any, url, transaction, report, or functionModule; inferred from processType when omitted. |
maxExecutions |
number | No | For trace_start: number of matching executions to capture (default 1). |
expiresHours |
number | No | For trace_start: hours until the armed request expires (default 24). |
sqlTrace |
boolean | No | For trace_start: capture SQL/DB accesses (default true; needed for dbAccesses analysis). |
aggregate |
boolean | No | For trace_start: aggregate the captured trace (default true). |
description |
string | No | Optional label for an armed trace request. |
Actions:
syntax— Compatibility route; prefer SAPRead syntax checks.versiondefaults to active; inactive checks a saved draft. Optionalsourcechecks unsaved text without writing. Returns errors/warnings with line, column, and message;checked:falsemeans no validation occurred.unittest— Run ABAP unit tests for oneCLAS,PROG, orFUGR, or for a wholeDEVCpackage, with the maximum risk fixed to harmless (dangerous=false,critical=false) and all three duration categories enabled. Package scope is exact by default;includeSubpackages=trueexplicitly includes the subtree. Native JUnit uses SAP's package object set; legacy, coverage, and corroboration runs use the resolved executable roots. ARC-1 reads package membership and active source before and after the run. Changed membership/source, unreadable source, invalid object URIs, and the 1,000-row package-search bound are incomplete evidence, never a pass. Returns results per test class/method with status, alert messages, and execution time. Risk-level refusals are skipped/incomplete evidence, not passing tests. Passcoverage=trueto also return statement / branch / procedure coverage ({executed, total, percent}each) plusmethodsBelowFull— the methods under 100% statement coverage, worst first — via a second ADT round-trip to the coverage-measurement endpoint; the output becomes{tests, coverage}. Best-effort — if the coverage endpoint is unavailable the tests still return with acoverageNote. UseresultFormat="structured"for explicit outcome/completeness evidence orresultFormat="junit"for native/generated JUnit; the latter still reconciles public-endpoint results with a harmless legacy run so missing risk alerts cannot turn the result green.-
unittest_ci— Single-target CI adapter for explicit packages/package trees. Runs the existing harmless-only native AUnit API plus legacy and active-source reconciliation for each package under one deadline. Empty, all-skipped, omitted-test or otherwise incomplete evidence setsfail:trueandstatus:"incomplete"; failures also setfail:true. Returns totals and per-package outcomes. No risky test or failure-bypass controls. Requires API availability and normal ADT source access. Uses the configured SAP identity; BTP API authorization may requireSAP_COM_0735. -
atc— Run ATC (ABAP Test Cockpit) checks. Returns findings with priority, check title, message, URI, line number, plus quickfix metadata (quickfixInfo,hasQuickfix). Optionalvariantparameter for custom check variants. Omit it and ARC-1 binds the system's configured check variant (systemCheckVariantfrom ATC customizing) — SAP itself maps an emptycheckVariantto the Code Inspector variant literally namedDEFAULT, which is usually not what the system is configured for. An unknownvariantname is rejected rather than silently substituted (SAP would runDEFAULTand still return HTTP 200).resultFormat="structured"reports the variant actually bound plusvariantSource(requested|systemDefault|sapFallback, the last meaning/atc/customizingwas unavailable). On systems that expose asynchronous ATC runs, ARC-1 follows SAP's run-status resource toCompletedbefore retrieving the worklist; unrecognized non-failure statuses keep polling rather than being mistaken for terminal failures. Older synchronous systems fall back to a ten-second quiet interval over the complete worklist response, excluding SAP's volatile root timestamp, so successful fallback settlement adds roughly ten seconds. Unsafe or missing asynchronous status locations are never followed; ARC-1 instead preserves any settled worklist findings but keeps the result incomplete. Failure and deadline paths make one best-effort final worklist read for the same reason. Structured results identify successful lifecycle evidence ascompletionEvidence(asyncRunCompleted|legacyWorklistSettled) and exposerunStatus. A synchronous<worklistRun>body can supply named informationalfindingStatistics(errors,warnings,infos,total) plusrunInfos; modern asynchronous HTTP 201 responses have an empty body, so those fields arenulland[]. The deprecatedexpectedFindingCountfield remains an alias offindingStatistics.totalfor response compatibility, but does not drivetruncatedorcomplete.truncatedis retained for compatibility and isfalseuntil SAP exposes a separate reliable truncation signal.variantSourcemay also be"requestedUnverified", meaning you named a variant but the variant listing was unreachable, so ARC-1 could not confirm SAP honoured it. The default (non-structured) payload carriesfindings,variantandvariantSource; incomplete default results are errors whose JSON body still contains any recovered findings. UseresultFormat="structured"when automation must distinguish a complete run from a missing/false object-set completeness marker, a zero-object result, malformed object/finding evidence, a cancelled/timed-out run, or a legacy worklist that has not settled. atc_ci— Single-target ATC CI API (/sap/bc/adt/api/atc/runs). Probes availability and verifies every selected package plus a nonempty selection before starting. Default variantABAP_CLOUD_DEVELOPMENT_DEFAULT; set a variant available on the target. Evaluates all Checkstyle findings atfailOnSeverity(default error), returns at most 200 findings withtruncated. Empty valid Checkstyle passes only after selection verification. Local deadlines return incomplete evidence with run path and last status/progress; inspect the existing run before retrying. A reachable API does not prove the background job can start. BTP authorization may requireSAP_COM_0901.
Both CI actions are excluded from multi-target mode. Software-component selection is deferred until its scope and completeness can be verified. includeReportXml=true includes XML only within a combined 256 KiB cap (default false): atc_ci.reportXml or unittest_ci.results[].reportXml; larger reports are explicitly omitted, with result paths retained. These actions use normal ARC-1 authentication/discovery/CSRF, and do not provide a communication-user bypass. BTP communication-arrangement completion has not been verified for this implementation.
- ATC object batches —
objectsuses one native worklist for the selected objects. If a completed run omits some objects, ARC-1 attempts one additional batch containing only those objects, under the same confirmed variant, SAP identity, and original timeout. On legacy systems it skips verification when the remaining time cannot cover the minimum ten-second settlement window. Failed, malformed, timed-out or unconfirmed-variant runs do not trigger this verification. The initial findings survive a verification failure. No per-object retries or automatic chunking occur. The 20-entry limit applies before deduplication; larger selections must be divided explicitly. DDICTABL,DTELandDOMAuse ATC R3TR object references, so table and structure selection needs no editor/subtype lookup and does not depend on/ddic/tablesavailability. SAP can still omit active DDIC objects under a given check variant; these remain unknown/incomplete.FUNCandINCLremain outside the batch contract;DEVCremains available through the existing single/package call.
Batch responses always include complete, ordered coverage, flat findings, and separate runs metadata. Each coverage entry has canonical type, name, input uri, status (reported or notReported), nullable findingCount, and worklistId. A missing record means unknown, not clean and not proof that the object does not exist. Zero is reported only from a unique object record in a complete run. Findings carry their enclosing object (type and name) and worklistId, including findings located in class includes. The finding's uri remains its actual source location; requested object root URIs are available in coverage. Findings for other supported root identities, including repeated first-run objects, are excluded from that run's batch contribution. Records outside the supported root types (such as function modules and includes) may belong to a requested container: ARC-1 retains their findings and marks the run incomplete with unknown coverage counts, rather than guessing parentage or reporting the container clean. Per-run totals describe the entire returned worklist, and excludedFindingCount records only the findings actually excluded. Unassigned, unowned or contradictory evidence remains incomplete. requestedObjectCount includes duplicates; uniqueObjectCount and reportedObjectCount do not. verificationAttempted records whether the second run was attempted. Two runs observe separate execution instants, so keep source stable while checking; this is not an atomic snapshot. Default/legacy incomplete batches return a tool error; structured callers must check complete === true before evaluating finding priorities. Existing single-object output stays unchanged. The generic CLI accepts the same JSON through arc1-cli call SAPDiagnose --json batch.json.
atc_variants— List the ATC check variants this system offers, plus the system default variant (the oneatcbinds when novariantis passed). Read-only. Thevariantparameter doubles as an optional name filter (*= all; e.g.variant="ABAP_CLOUD*"). Returns{ systemDefault, filter, count, variants: [{ name, description }] }. Use it to discover the exactvariantstring to pass toaction="atc".-
cds_testcases— Get SAP-suggested ABAP Unit test cases for a CDS entity (CDS Test Double Framework). Requiresname(the CDS entity / DDLS source name; notype). Returns one suggestion per testable semantic — the whole view (semanticType: "NONE"), each calculated field ("CALCULATION"+calculatedField), and"CAST"/"JOIN"/"CASE"expressions — each with a suggestedtestMethodname +description, plus ahintfor scaffolding acl_cds_test_environmenttest class. Read-only. Available on SAP_BASIS 8.16+ (ABAP Platform 2025 / S/4HANA 2025) only — discovery-gated, so older releases return a clear "needs 8.16+" message. The AI-backed test-data / test-method generation (Joule for Developers) is intentionally not exposed. -
Server-driven types: Syntax/ATC and transport check/history use the registered URL; ATC may remain incomplete. ABAP Unit and ATC batches reject these types.
object_staterefuses them until version identity can be verified. -
object_state— Compare active and inactive source versions for one object. ForCLAS, ARC-1 checks main, definitions, implementations, macros, and testclasses includes (up to 10 parallel reads per class; sequence calls when sweeping many classes). Returns ETags, byte lengths, SHA-256 hashes, and divergence flags without returning full source. Useful for diagnosing activation failures where active and inactive class includes disagree. Server-driven types are refused because SAP may substitute one version for another; matching hashes alone cannot prove version identity. UseSAPReadwith an explicitversionfor those types. quickfix— Get SAP quickfix proposals for a specific source position (name,type,source,line, optionalcolumn). Classes/interfaces must already exist in SAP; activation and saving the supplied edits are not required. Returns proposal entries withuri,type,name,description,userContent.apply_quickfix— Apply one proposal (proposalUri+proposalUserContent) and return text deltas (range + replacement content). The class/interface must still exist. Preserve the returned whitespace, review affected objects, and syntax-check the edited buffer: SAP can suggest incomplete types. This does not write source; useSAPWriteto persist.dumps— List short dumps (ST22). Withoutid: returns recent dumps (filterable byuser,maxResults). Withid: returns full dump detail including error type, exception, program, stack trace, and formatted output.traces— List ABAP profiler traces. Withoutid: returns trace list. Withid+analysis: returns trace analysis (hitlist= call hierarchy with hit counts and timings,statements= executed statements,dbAccesses= database access details).trace_start— Arm an ABAP profiler request for the next matching execution. Defaults to the next HTTP request by the connected user, with SQL capture on. This changes SAP trace-request state and needswritescope plusSAP_ALLOW_WRITES=true; reproduce the workload, then read it throughtraces.trace_requests— List armed profiler requests, optionally filtered bytraceUser. Read-only.trace_cancel— Cancel one armed profiler request byid. Mutating; needswritescope plusSAP_ALLOW_WRITES=true.system_messages— List SM02 system messages, with optionalfrom/to,user, andmaxResultsfeed filters. Read-only.gateway_errors— List on-prem/IWFND/ERROR_LOGentries; request detail with the returned canonicaldetailUrl, or withidpluserrorType. Read-only.odata_perf— Diagnose why a Fiori/OData request is slow. Passurl(the host-relative OData path from the app's Network tab); ARC-1 GETs it with?sap-statistics=trueand a wall-clock timer, then returns the server-side timing split (gwtotal,gwapp,gwappdb= DB time,gwfw/gwhub= framework,icfauth= auth) plus averdictrouting you to the dominant cost (db→ check the CDS query /cds_sql/ ST05;app→ ABAP profilertraces;framework→ metadata/first-call;auth→ ICF/DCL). Read-only GET; gated like data preview (SAP_ALLOW_DATA_PREVIEW). The OData service must be on the same SAP host ARC-1 connects to. Older releases (e.g. NW 7.50) may report only agwhubtotal without a per-component split → the verdict says so rather than guessing.authorization_trace— Read the long-term, on-prem STUSERTRACE trace fromSUAUTHVALTRC, decode positional field values throughTOBJ, and return the user, application, authorization object, result code, checked values, ABAP code location, and first-seen timestamp. Optionaluser,authObject,onlyFailures, andmaxResultsnarrow the read; entries are sorted newest-first within the capped result set. Requires thedatascope,SAP_ALLOW_DATA_PREVIEW=true, and SAP table-read authorization forSUAUTHVALTRCandTOBJ; it never needs free SQL. This is not SU53's live last-failure buffer: it contains only checks recorded whileauth/auth_user_tracewas enabled, and ARC-1 cannot toggle that profile parameter. Every response therefore reportstraceState.status="unknown"and warns that persisted rows do not prove the trace is currently active; empty responses additionally include RZ11/profile activation guidance. Verify the current value in RZ11:Nis inactive,Frecords only filters maintained in STUSERTRACE (recommended; at least one filter is required), andYrecords all users/application types. A dynamic RZ11 change lasts until restart; select Change on All Servers when all application-server instances must participate, and maintainDEFAULT.PFLthrough the approved Basis profile workflow for a persistent setting. ABAP Cloud users should use the Display Authorization Trace Fiori app.cds_sql— Show the native SQL a CDS view compiles to (ADT "Show SQL Create Statement"). Passname(the CDS DDL source / DDLS, e.g.I_CURRENCY). Returns theCREATE VIEWstatement(s) — the joins/scans behind a slow entity. Read-only. Verified on NW 7.50, S/4HANA 2023 (758), and ABAP Platform 2025 (816); on 7.50 the statement is a classic DBVIEW.sql_trace_state— Read the current ST05 trace state (SQL/buffer/enqueue/RFC/HTTP/APC/AMC/auth on-off per application server, plus the active filter). Read-only.set_sql_trace_state— Arm or disarm the ST05 SQL trace. RequiressqlOn(true= arm,false= disarm); optionaluserfilters the trace to one SAP user. Mutates server trace state → needsSAP_ALLOW_WRITES. Workflow: arm → reproduce the slow request →sql_trace_directoryfor the record-viewer link.sql_trace_directory— Return where the recorded SQL is read. ADT has no SQL-record endpoint; SAP answers/st05/trace/directorywith the Technical Monitoring Cockpit "SQL Trace Analysis" deep-link — ARC-1 returns that URL (open it in a browser; needs the/sap/bc/stmcSICF service active). Read-only. (The richer ADT-native record reader is the ABAP Cross Trace API — a planned follow-up.)
Examples:
SAPDiagnose(action="syntax", type="CLAS", name="ZCL_ORDER")
SAPDiagnose(action="unittest", type="CLAS", name="ZCL_ORDER")
SAPDiagnose(action="unittest", type="CLAS", name="ZCL_ORDER", coverage=true, resultFormat="structured")
SAPDiagnose(action="unittest", type="DEVC", name="ZORDER", resultFormat="structured")
SAPDiagnose(action="unittest", type="DEVC", name="ZORDER", includeSubpackages=true, resultFormat="junit")
SAPDiagnose(action="unittest_ci", packages=["ZFOO"], includeReportXml=true)
SAPDiagnose(action="atc", type="PROG", name="ZTEST_REPORT", variant="DEFAULT", resultFormat="structured")
SAPDiagnose(action="atc", objects=[{type:"CLAS",name:"ZCL_ORDER"},{type:"INTF",name:"ZIF_ORDER"}])
// DDIC selection example: choose an applicable variant and inspect complete/coverage; omitted objects stay unknown.
SAPDiagnose(action="atc", objects=[{type:"TABL",name:"ZORDER"},{type:"DTEL",name:"ZORDER_ID"},{type:"DOMA",name:"ZORDER_ID"}], resultFormat="structured")
SAPDiagnose(action="atc_ci", packages=["ZFOO"], failOnSeverity="error", timeoutSeconds=600)
SAPDiagnose(action="cds_testcases", name="I_CURRENCY") — SAP-suggested unit-test cases for a CDS view (8.16+)
SAPDiagnose(action="object_state", type="CLAS", name="ZBP_DM_PROJECT")
SAPDiagnose(action="quickfix", type="CLAS", name="ZCL_ORDER", source="<current_source>", line=42, column=1)
SAPDiagnose(action="apply_quickfix", type="CLAS", name="ZCL_ORDER", source="<current_source>", line=42, column=1, proposalUri="/sap/bc/adt/quickfixes/...", proposalUserContent="<opaque_state>")
SAPDiagnose(action="dumps")
SAPDiagnose(action="dumps", user="DEVELOPER", maxResults=10)
SAPDiagnose(action="dumps", from="2026-09-15", to="2026-09-20T23:59:59Z")
SAPDiagnose(action="dumps", maxResults=500) # SAP serves 100 per request; ARC-1 pages the rest
SAPDiagnose(action="dumps", id="20260409_123456_DUMP_ID")
SAPDiagnose(action="traces")
SAPDiagnose(action="traces", id="TRACE123", analysis="hitlist")
SAPDiagnose(action="traces", id="TRACE123", analysis="dbAccesses")
SAPDiagnose(action="trace_start", processType="http", objectType="url", maxExecutions=1, description="Reproduce slow OData")
SAPDiagnose(action="trace_requests", traceUser="DEVELOPER")
SAPDiagnose(action="trace_cancel", id="REQUEST123")
SAPDiagnose(action="system_messages", maxResults=20)
SAPDiagnose(action="gateway_errors", maxResults=20)
SAPDiagnose(action="odata_perf", url="/sap/opu/odata4/sap/zui_mup/.../SerialNumbers?$filter=...") — where did the time go (DB vs ABAP vs framework)
SAPDiagnose(action="authorization_trace", user="AUTH_TEST", onlyFailures=true, maxResults=20) — denied STUSERTRACE checks (on-prem; data-preview gated)
SAPDiagnose(action="cds_sql", name="I_CURRENCY") — the native SQL CREATE VIEW behind a CDS entity
SAPDiagnose(action="sql_trace_state") — is the ST05 SQL trace on? for whom?
SAPDiagnose(action="set_sql_trace_state", sqlOn=true, user="DEVELOPER") — arm the SQL trace for one user (needs SAP_ALLOW_WRITES)
SAPDiagnose(action="sql_trace_directory") — get SAP's SQL Trace Analysis deep-link to read the records
Quickfix Workflow¶
- Run
SAPDiagnose(action="atc" ...)orSAPDiagnose(action="syntax" ...). - For ATC findings, check
hasQuickfix: true. - Call
SAPDiagnose(action="quickfix", ...)for the relevant line/column. - Select a proposal and call
SAPDiagnose(action="apply_quickfix", ...)to receive deltas. - Apply the exact deltas to the original buffer, preserving whitespace. Review every affected
object and syntax-check the edited source before saving via
SAPWrite(action="update" | "edit_method", ...).
SAPManage¶
Probe and report SAP system capabilities, inspect the object cache state, manage package (DEVC) and classic FLP lifecycle operations, and set an object's API release contract.
Actions:
- probe — Re-probe the SAP system now (feature probes + auth checks + ADT discovery refresh). Detects optional features.
- features — Get cached feature status from last probe (fast, no SAP round-trip).
- cache_stats — Return request-driven cache statistics: cached sources, legacy dependency-graph rows, released APIs, and the per-username inactive-list session cache (inactiveListCache.userCount, inactiveListCache.totalEntries).
- create_package — Create a package (DEVC) via /sap/bc/adt/packages.
- delete_package — Delete a package via lock/delete/unlock.
- change_package — Move an existing object into a different package (DEVC reassignment).
- set_api_state — Set one supported API release contract to RELEASED or NOT_RELEASED. ARC-1
reads the contract, transforms only its writable subset, writes it, then reads it back. Supported
contracts and visibility defaults come from SAP and are not broadened by ARC-1. For objectType="FUNC"
with name, ARC-1 resolves the function group through search; pass objectUri when it cannot.
- flp_list_catalogs — List FLP designer catalogs. The flp_* actions target the classic tile/target-mapping model, deprecated as of S/4HANA 2023 and not federated by Work Zone content exposure v2 — the successor is the Launchpad App Descriptor Item (SAPRead type=UIAD). Business catalogs are a separate model (/UI2/FLPCM_CUST) and are not managed here.
- flp_list_groups — List FLP groups (Pages) from /UI2/FLPD_CATALOG.
- flp_list_tiles — List tiles/target mappings in a catalog.
- flp_create_catalog — Create an FLP designer catalog.
- flp_create_group — Create an FLP group.
- flp_create_tile — Create a tile in an FLP catalog.
- flp_add_tile_to_group — Assign a catalog tile instance into a group.
- flp_delete_catalog — Delete an FLP designer catalog.
Unconfirmed FLP creation: Catalog/group/tile creation and tile assignment do not
replay after HTTP 429/5xx or response loss. SAP may already have created the entry;
inspect it before another create. Use flp_list_catalogs, flp_list_groups and
flp_list_tiles for catalogs, groups and catalog tiles. These actions do not list
group membership; inspect a group's tiles in SAP Fiori Launchpad Designer.
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
action |
string | Yes | probe, features, cache_stats, create_package, delete_package, change_package, set_api_state, flp_list_catalogs, flp_list_groups, flp_list_tiles, flp_create_catalog, flp_create_group, flp_create_tile, flp_add_tile_to_group, flp_delete_catalog |
name |
string | No | Required for create_package and delete_package (package name) |
description |
string | No | Required for create_package (package description) |
superPackage |
string | No | Optional parent package for create_package (use $TMP for local packages) |
softwareComponent |
string | No | Optional software component for create_package (default: LOCAL) |
responsible |
string | No | Package-responsible ABAP user (XUBNAME, max 12 characters). Defaults to the connection user; pass explicitly under principal propagation. SAP rejects email identities here. |
transportLayer |
string | No | Optional transport layer for create_package |
recordChanges |
boolean | No | Whether the new package records object changes in transports. The default follows software-component/transport-layer context; literal LOCAL packages default false. |
packageType |
string | No | Optional package type for create_package: development, structure, main (default: development) |
transport |
string | No | Optional transport request ID (corrNr) for create_package/delete_package/change_package |
objectName |
string | No | Required for change_package — name of the object to move (e.g., ZCL_MY_CLASS) |
objectType |
string | No | Required for change_package — ADT object type (e.g., CLAS/OC, DDLS/DF, PROG/P) |
objectUri |
string | No | Optional for change_package — ADT URI of the object. Auto-resolved from objectName + objectType if not provided |
oldPackage |
string | No | Required for change_package — current package of the object |
newPackage |
string | No | Required for change_package — target package to move the object to |
apiState |
string | No | For set_api_state: RELEASED (default) or NOT_RELEASED; visibility follows SAP's contract defaults. |
apiVisibility |
string[] | No | set_api_state with RELEASED: complete explicit selection of cloudDevelopment and/or keyUserApps. [] selects neither; SAP decides whether the contract permits it. Omit for the contract defaults. Native read-only flags are respected; exact visibility is verified even on a no-op. |
contract |
string | No | For set_api_state: C0–C4 (default C1). Support varies by type/release; inspect SAPRead(type="API_STATE") and SAP's supported-contract response. |
catalogId |
string | No | Required for flp_list_tiles, flp_create_tile, flp_add_tile_to_group |
groupId |
string | No | Required for flp_create_group, flp_add_tile_to_group |
domainId |
string | No | Required for flp_create_catalog |
title |
string | No | Required for flp_create_catalog, flp_create_group |
tileInstanceId |
string | No | Required for flp_add_tile_to_group |
tile |
object | No | Required for flp_create_tile. Fields: id, title, semanticObject, semanticAction, optional icon, url, subtitle, info |
Probed features: hana, abapGit, rap, amdp, ui5, transport, ui5repo, flp. Each returns available (bool), mode (auto/on/off), message, and probedAt timestamp.
cache_stats output:
{
"enabled": true,
"sourceCount": 42,
"contractCount": 38,
"apiCount": 0,
"inactiveListCache": {
"userCount": 1,
"totalEntries": 3
}
}
| Field | Description |
|---|---|
enabled |
Whether caching is active (false if ARC1_CACHE=none) |
sourceCount |
Cached source code entries (grows as objects are read) |
contractCount |
Legacy dependency-graph rows; current SAPContext(deps) neither reads nor populates them. Does not count memory-only parse memoization. |
apiCount |
Released API metadata entries populated by requests |
inactiveListCache |
Aggregate user/session draft-list cache counts |
Examples:
SAPManage(action="probe") → discover system capabilities
SAPManage(action="features") → get cached results (no SAP call)
SAPManage(action="cache_stats") → check request-driven cache state
SAPManage(action="create_package", name="ZRAP_TRAVEL", description="RAP Travel Demo")
SAPManage(action="create_package", name="ZRAP_TRAVEL", description="RAP Travel Demo", superPackage="ZRAP", softwareComponent="HOME", transportLayer="HOME", packageType="development", transport="K900123")
SAPManage(action="delete_package", name="ZRAP_TRAVEL")
SAPManage(action="change_package", objectName="ZCL_MY_CLASS", objectType="CLAS/OC", oldPackage="$TMP", newPackage="Z_PRODUCTION", transport="K900123")
SAPManage(action="set_api_state", name="ZCL_MY_CLASS", objectType="CLAS", contract="C1", apiState="RELEASED")
SAPManage(action="flp_list_catalogs")
SAPManage(action="flp_list_groups")
SAPManage(action="flp_list_tiles", catalogId="ZARC1_SALES")
SAPManage(action="flp_create_catalog", domainId="ZARC1_SALES", title="Sales Catalog")
SAPManage(action="flp_create_group", groupId="ZARC1_SALES_GRP", title="Sales Group")
SAPManage(action="flp_create_tile", catalogId="ZARC1_SALES", tile={"id":"tile_sales","title":"Sales","semanticObject":"SalesOrder","semanticAction":"display"})
SAPManage(action="flp_add_tile_to_group", groupId="ZARC1_SALES_GRP", catalogId="ZARC1_SALES", tileInstanceId="00O2TO3741QLWH4GV74AHMWQE")
Note: The probe, features, and cache_stats actions are read operations that work without --allow-writes and require only read scope in HTTP auth mode. Mutating SAPManage actions require write scope and writable safety config.