From ARC-1 — SAP ABAP for Claude
Generates RAP determination, validation, and custom action implementations by reading the RAP stack and filling empty method stubs in the behavior pool. Use when asked to implement RAP logic or generate custom action code.
How this skill is triggered — by the user, by Claude, or both
Slash command
/arc-1:generate-rap-logicThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate RAP determination, validation, and custom action implementations for an existing behavior definition. Reads the RAP stack, identifies empty method stubs (or missing handler signatures) in the behavior pool, and generates ABAP Cloud implementation code.
Generate RAP determination, validation, and custom action implementations for an existing behavior definition. Reads the RAP stack, identifies empty method stubs (or missing handler signatures) in the behavior pool, and generates ABAP Cloud implementation code.
This skill replicates SAP Joule's "RAP Logic Prediction" capability by combining ARC-1 (SAP system access) with mcp-sap-docs (documentation & best practices).
| Setting | Default | Rationale |
|---|---|---|
| Entity access | IN LOCAL MODE always | Inside behavior pool, no auth check needed |
| Message style | Hardcoded text via new_message_with_text() | Simplest for prototyping; use MSAG for production (see Notes) |
| Scope | All empty methods | User can narrow after seeing the list |
| Error handling | FAILED + REPORTED structures | Standard RAP error propagation |
The user provides a behavior definition name (e.g., ZI_TRAVEL).
Only the behavior definition name is required. If the user provides just a BDEF name, apply Smart Defaults and proceed to read the stack and present available methods.
Optionally, the user may specify:
Read the behavior definition, CDS view, and behavior pool to understand the complete RAP context.
SAPRead(type="BDEF", name="<bdef_name>")
⚠️ FAIL-FAST GATE: If the BDEF read fails with 404, the object may not exist — verify the name via SAPSearch. If it fails with 415, check SAPManage(action="probe") for system info and inform the user about the issue.
Parse the BDEF source to identify:
determination <Name> on (modify|save) { ... }validation <Name> on save { ... }action <Name> ...with draft present or notalias <Alias>persistent table <table_name>implementation in class <class_name> uniqueSAPRead(type="DDLS", name="<interface_view>")
Understand the data model: field names, types, aliases, associations. This is needed to generate correct READ ENTITIES and MODIFY ENTITIES statements.
If access control exists, also read it to understand CDS-level authorization constraints:
SAPRead(type="DCLS", name="<interface_view>_DCL")
SAPContext(type="DDLS", name="<interface_view>", action="deps")
Understand underlying tables, associations, and related entities. Useful for cross-entity validations or determinations that read associated data.
Find the behavior pool class name from the BDEF source (implementation in class <name>), then:
SAPRead(type="CLAS", name="<bp_class>", format="structured")
Use the structured read as the default because it returns metadata, includes, and existing test classes in one response. If you need a concise method catalog afterward, add:
SAPRead(type="CLAS", name="<bp_class>", method="*")
Identify which methods are empty stubs (body is just comments, RETURN, or blank) and which BDEF-declared handlers are missing entirely from the class signature.
If this is an existing RAP BO that has already been modified by others, inspect recent changes and any attached documentation before overwriting logic:
SAPRead(type="VERSIONS", name="<bp_class>", objectType="CLAS")
SAPRead(type="SKTD", name="<bp_class>")
Parse the BDEF for determination and validation declarations. Present a summary table:
Methods in behavior pool ZBP_I_TRAVEL:
| # | Type | Name | Trigger | Fields | Status |
|---|---------------|-----------------------|--------------------|-----------------|-------------|
| 1 | Determination | calculateTotalPrice | on modify | Price, Quantity | empty |
| 2 | Determination | setDefaultStatus | on modify | %create | empty |
| 3 | Validation | validateStatus | on save | Status | implemented |
| 4 | Validation | validateDates | on save | BeginDate | empty |
| 5 | Validation | validateCustomer | on save | CustomerID | empty |
Ask the user: "Which methods should I implement? (all empty / specific numbers / skip any?)"
If the user provided a natural language description, map it to the appropriate method(s).
If the BDEF declares action/determination/validation handlers that do not exist in the class definition:
SAPWrite(action="scaffold_rap_handlers", type="CLAS", name="<bp_class>", bdefName="<bdef_name>") to list missing signatures.autoApply=true to inject declarations plus empty method stubs into class sections when possible.SAPDiagnose(action="quickfix", ...)SAPDiagnose(action="apply_quickfix", ...)METHODS ... FOR ... signature.SAPRead(type="CLAS", name="<bp_class>", method="*") before writing bodies.Use mcp-sap-docs to fetch current RAP implementation patterns. Start with reference-style queries (includeSamples=false) and then fetch examples (includeSamples=true) only when you need executable patterns:
search(query="RAP validation implementation ABAP example", includeSamples=true, abapFlavor="<cloud|standard>")
search(query="RAP determination on save trigger", includeSamples=false, abapFlavor="<cloud|standard>")
For specific logic patterns:
search(query="RAP calculate total price determination", includeSamples=true, abapFlavor="<cloud|standard>")
search(query="RAP status validation transition", includeSamples=true, abapFlavor="<cloud|standard>")
For backend-driven UI behavior that frequently accompanies logic changes:
search(query="RAP feature control side effects authorization control", includeSamples=false, abapFlavor="<cloud|standard>")
Use documentation to inform correct ABAP Cloud patterns:
READ ENTITIES OF <entity> IN LOCAL MODE for reading entity dataMODIFY ENTITIES OF <entity> IN LOCAL MODE for updating entity dataFAILED / REPORTED structure handlingIN LOCAL MODEFor each selected method, generate ABAP Cloud implementation code.
METHOD <determination_name>.
" Read relevant fields of all affected entities
READ ENTITIES OF <interface_view> IN LOCAL MODE
ENTITY <alias>
FIELDS ( <trigger_fields> )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_entities).
" Calculate derived values
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" --- Business logic here ---
" Example: <entity>-TotalPrice = <entity>-Price * <entity>-Quantity.
ENDLOOP.
" Write back modified fields
MODIFY ENTITIES OF <interface_view> IN LOCAL MODE
ENTITY <alias>
UPDATE FIELDS ( <modified_fields> )
WITH VALUE #( FOR entity IN lt_entities
( %tky = entity-%tky
<field> = entity-<field> ) )
REPORTED DATA(lt_update_reported).
reported = CORRESPONDING #( DEEP lt_update_reported ).
ENDMETHOD.
METHOD <validation_name>.
" Read relevant fields of all affected entities
READ ENTITIES OF <interface_view> IN LOCAL MODE
ENTITY <alias>
FIELDS ( <validated_fields> )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_entities).
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" --- Validation logic here ---
" Example: check field is not initial
IF <entity>-<Field> IS INITIAL.
APPEND VALUE #( %tky = <entity>-%tky ) TO failed-<alias>.
APPEND VALUE #(
%tky = <entity>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = '<Error message>' )
%element-<Field> = if_abap_behv=>mk-on
) TO reported-<alias>.
ENDIF.
ENDLOOP.
ENDMETHOD.
METHOD <action_name>.
READ ENTITIES OF <interface_view> IN LOCAL MODE
ENTITY <alias>
FIELDS ( <action_input_fields> )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_entities).
LOOP AT lt_entities ASSIGNING FIELD-SYMBOL(<entity>).
" --- Action logic here ---
ENDLOOP.
MODIFY ENTITIES OF <interface_view> IN LOCAL MODE
ENTITY <alias>
UPDATE FIELDS ( <action_output_fields> )
WITH VALUE #( FOR entity IN lt_entities
( %tky = entity-%tky
<field> = entity-<field> ) )
REPORTED DATA(lt_reported)
FAILED DATA(lt_failed).
reported = CORRESPONDING #( DEEP lt_reported ).
failed = CORRESPONDING #( DEEP lt_failed ).
ENDMETHOD.
Show the generated code for each method and ask:
"Here's the generated implementation. Should I write it to the SAP system? (yes / edit first / cancel)"
If the user wants edits, incorporate them before proceeding.
Before writing, optionally lint-check the generated code to catch issues before acquiring SAP locks:
SAPLint(action="lint", source="<generated_method_code>", name="<bp_class>")
If you want the generated method body to follow SAP's formatter settings before it is written back:
SAPLint(action="format", source="<generated_method_code>", name="<bp_class>")
Before calling edit_method, confirm the target method exists in SAPRead(..., method="*"). If it does not exist yet, run scaffold_rap_handlers first, then quick-fix flow (quickfix + apply_quickfix) or ADT quick-fix fallback.
Write each method implementation using method-level surgery:
SAPWrite(action="edit_method", type="CLAS", name="<bp_class>", method="<method_name>", source="<generated_code>", transport="<transport>")
Note: The transport parameter is recommended but not always required for edit_method. ARC-1 auto-propagates the lock-provided corrNr when no explicit transport is supplied. Pre-write lint validation runs automatically when enabled (default: on). Prefer edit_method over full-class rewrites for behavior pools.
After writing all methods, run a syntax check:
SAPDiagnose(action="syntax", type="CLAS", name="<bp_class>")
If syntax errors occur, try SAP quickfix proposals first before manual edits:
SAPDiagnose(action="quickfix", type="CLAS", name="<bp_class>", source="<current_source>", line=<error_line>, column=<error_col>)
SAP quickfixes can automatically resolve common issues like missing declarations or straightforward syntax corrections.
If syntax errors occur:
READ ENTITIES, incorrect field alias, missing IN LOCAL MODEActivate the behavior pool and behavior definition together:
SAPActivate(objects=[{type:"BDEF", name:"<bdef>"}, {type:"CLAS", name:"<bp_class>"}])
Note: Activation returns structured responses with detailed error/warning messages including line numbers and URIs. Use this to pinpoint exact issues rather than re-reading full source.
Optionally, if a test class exists, run the unit tests:
SAPDiagnose(action="unittest", type="CLAS", name="<bp_class>")
If ATC is available and the change is non-trivial, run it too:
SAPDiagnose(action="atc", type="CLAS", name="<bp_class>")
Present a summary:
RAP Logic Generation Complete!
Implemented methods:
[x] Determination: calculateTotalPrice — calculates total from price * quantity
[x] Determination: setDefaultStatus — sets status to 'N' (New) on create
[x] Validation: validateDates — ensures begin_date < end_date
[x] Validation: validateCustomer — checks customer_id is not empty
[ ] Validation: validateStatus — already implemented, skipped
Next steps:
- Test the logic via the Fiori Elements preview
- Add unit tests (use generate-abap-unit-test skill)
- Add more validations/determinations to the BDEF as needed
Calculate a derived field from other fields (e.g., total price = price * quantity):
METHOD calculateTotalPrice.
READ ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
FIELDS ( Price Quantity )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_orders).
LOOP AT lt_orders ASSIGNING FIELD-SYMBOL(<order>).
<order>-TotalPrice = <order>-Price * <order>-Quantity.
ENDLOOP.
MODIFY ENTITIES OF zi_order IN LOCAL MODE
ENTITY Order
UPDATE FIELDS ( TotalPrice )
WITH VALUE #( FOR order IN lt_orders
( %tky = order-%tky
TotalPrice = order-TotalPrice ) )
REPORTED DATA(lt_reported).
reported = CORRESPONDING #( DEEP lt_reported ).
ENDMETHOD.
Set default values when an entity is created:
METHOD setDefaultStatus.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travels).
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( Status )
WITH VALUE #( FOR travel IN lt_travels
WHERE ( Status IS INITIAL )
( %tky = travel-%tky
Status = 'N' ) )
REPORTED DATA(lt_reported).
reported = CORRESPONDING #( DEEP lt_reported ).
ENDMETHOD.
Check that a required field is not empty:
METHOD validateCustomer.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( CustomerID )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travels).
LOOP AT lt_travels ASSIGNING FIELD-SYMBOL(<travel>).
IF <travel>-CustomerID IS INITIAL.
APPEND VALUE #( %tky = <travel>-%tky ) TO failed-travel.
APPEND VALUE #(
%tky = <travel>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Customer must be specified' )
%element-CustomerID = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
Validate that related fields are consistent (e.g., begin date before end date):
METHOD validateDates.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( BeginDate EndDate )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travels).
LOOP AT lt_travels ASSIGNING FIELD-SYMBOL(<travel>).
IF <travel>-BeginDate IS NOT INITIAL
AND <travel>-EndDate IS NOT INITIAL
AND <travel>-BeginDate > <travel>-EndDate.
APPEND VALUE #( %tky = <travel>-%tky ) TO failed-travel.
APPEND VALUE #(
%tky = <travel>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = 'Begin date must be before end date' )
%element-BeginDate = if_abap_behv=>mk-on
%element-EndDate = if_abap_behv=>mk-on
) TO reported-travel.
ENDIF.
ENDLOOP.
ENDMETHOD.
Validate that status changes follow allowed transitions:
METHOD validateStatus.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( Status )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travels).
LOOP AT lt_travels ASSIGNING FIELD-SYMBOL(<travel>).
CASE <travel>-Status.
WHEN 'N' OR 'O' OR 'A' OR 'X'.
" Valid statuses: New, Open, Accepted, Cancelled
WHEN OTHERS.
APPEND VALUE #( %tky = <travel>-%tky ) TO failed-travel.
APPEND VALUE #(
%tky = <travel>-%tky
%msg = new_message_with_text(
severity = if_abap_behv_message=>severity-error
text = |Invalid status: { <travel>-Status }| )
%element-Status = if_abap_behv=>mk-on
) TO reported-travel.
ENDCASE.
ENDLOOP.
ENDMETHOD.
Assign sequential numbers for non-UUID key scenarios:
METHOD setTravelID.
READ ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
FIELDS ( TravelID )
WITH CORRESPONDING #( keys )
RESULT DATA(lt_travels).
" Get next number from number range or max+1
SELECT MAX( travel_id ) FROM ztravel_d INTO @DATA(lv_max_id).
DATA(lv_next_id) = lv_max_id + 1.
LOOP AT lt_travels ASSIGNING FIELD-SYMBOL(<travel>)
WHERE TravelID IS INITIAL.
<travel>-TravelID = lv_next_id.
lv_next_id += 1.
ENDLOOP.
MODIFY ENTITIES OF zi_travel IN LOCAL MODE
ENTITY Travel
UPDATE FIELDS ( TravelID )
WITH VALUE #( FOR travel IN lt_travels
WHERE ( TravelID IS NOT INITIAL )
( %tky = travel-%tky
TravelID = travel-TravelID ) )
REPORTED DATA(lt_reported).
reported = CORRESPONDING #( DEEP lt_reported ).
ENDMETHOD.
| Error | Cause | Fix |
|---|---|---|
| 415 Unsupported Media Type on DDLS/BDEF | RAP/CDS endpoint not responding as expected | Check SAPManage(action="probe") for system info. Verify ICF service activation. Try creating the object in ADT to confirm system capability. |
| Method not found in behavior pool | Class name in BDEF doesn't match actual class | Check implementation in class in BDEF source, verify class exists |
Missing METHODS ... FOR ... handler signature | BDEF declaration exists but class signature not generated yet | Run SAPWrite(action="scaffold_rap_handlers", ...) first (optionally autoApply=true), then SAPDiagnose(action="quickfix") + apply_quickfix or ADT quick-fix, then retry edit_method |
Syntax error: <entity> unknown in READ ENTITIES | Wrong entity name or alias | Use the exact alias from the BDEF define behavior for ... alias <Alias> |
Syntax error: field <Field> unknown | Field alias doesn't match CDS view | Check CDS view field aliases — BDEF uses CDS aliases, not table field names |
| Activation fails | BDEF and class are incompatible | Activate BDEF and class together: SAPActivate(objects=[...]) |
FAILED / REPORTED structure mismatch | Wrong alias used in failed-<alias> or reported-<alias> | Use the lowercase entity alias from BDEF (e.g., failed-travel, not failed-Travel) |
IN LOCAL MODE missing | Missing clause causes authorization check | Always use IN LOCAL MODE for internal reads/writes within the behavior pool |
%tky not available | Method signature doesn't provide transactional key | Check method signature — determinations use keys, validations use keys |
Runtime error on MODIFY ENTITIES | Trying to modify read-only fields | Don't modify fields marked field ( readonly ) in BDEF |
Generic save error [?/011] on full class write | Behavior-pool full-class update path is unstable on some systems | Use scaffold_rap_handlers + quickfix path for signatures, then patch method bodies via edit_method only |
READ ENTITIES / MODIFY ENTITIES — no SELECT from database tables directly. All APIs must be released. strict ( 2 ) in BDEF.SELECT directly), but READ ENTITIES / MODIFY ENTITIES is strongly recommended for consistency and future compatibility.DCLS enforces CDS row-level access, while BDEF authorization (authorization master) governs behavior operations. Consider both when debugging authorization-related logic.side effects implementation (UI refresh triggers). Add manually if needed.instance_features / global_features). Add manually, especially when the UI should disable actions or updates.authorization master implementation. Add authorization checks manually.SAPWrite(action="create", type="MSAG", name="Z<MSG_CLASS>", ...) and replace new_message_with_text() with new_message() referencing the message class.npx claudepluginhub arc-mcp/arc-1 --plugin arc-1Guides RAP (RESTful ABAP Programming Model) development: behavior definitions, EML, managed/unmanaged BOs, draft, actions, validations, determinations, side effects, and business events for ABAP Cloud Fiori apps.
Generates a complete RAP OData UI service stack from a natural-language business object description — table, CDS views, behavior definitions, metadata extension, service definition, and behavior pool class.
Creates new ABAP programs (Report, CRUD, ALV, Batch) with Main+Include structure supporting OOP or Procedural paradigms using a multi-phase coding and QA pipeline.