From ARC-1 — SAP ABAP for Claude
Generates a production-quality RAP OData service through deep system research, best-practice analysis, and iterative planning with user approval before writing code.
How this skill is triggered — by the user, by Claude, or both
Slash command
/arc-1:generate-rap-service-researchedThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate a production-quality RAP OData service through deep system research, best-practice analysis, and iterative planning before writing a single line of code.
Generate a production-quality RAP OData service through deep system research, best-practice analysis, and iterative planning before writing a single line of code.
This skill produces an implementation plan informed by the target SAP system's actual capabilities, existing code patterns, SAP documentation, and user requirements — then executes it only after explicit user approval.
| Setting | Default | Rationale |
|---|---|---|
| Package | User's Z* package with transport | Production-ready; only use $TMP if user explicitly asks |
| Key strategy | UUID (sysuuid_x16), managed numbering | Simplest, no collision risk |
| Behavior scenario | Managed | Framework handles CRUD, most common |
| OData version | V4 | Current SAP standard |
| Draft | Prefer for transactional Fiori Elements UI services; verify against system release and BO constraints | Best default for editable FE apps, but not every RAP service needs draft |
| Strict mode | strict ( 2 ) unless system patterns or SAP constraints justify otherwise | Current RAP best practice, but not universal |
| Naming | SAP standard (see reference section) | Overridden by existing system patterns if found |
| Admin fields | System-appropriate (syuname/timestampl or abp_*) | Detected from system type |
| Service exposure | OData V4 UI provider contract by default | Best fit for Fiori Elements unless the use case is an API-first service |
These defaults are starting points — research in Phase 1 may override them based on existing system patterns.
The user provides a natural language description of the business requirement. This can range from vague ("I need something to track maintenance orders") to detailed ("REST API for plant maintenance with equipment hierarchy, work orders, and time recording").
Only the business requirement is required. Gather initial context — do NOT over-interview at this stage. Research will surface the right questions later.
Optionally, the user may specify:
$TMP if user explicitly says so)$TMP packages — resolved in Phase 1-pre)If the user provides just a description, proceed directly to research. Questions come AFTER research, when you know enough to ask the right ones.
Ask the user for their target package if not provided. Then resolve the transport request (skip only if package is $TMP):
SAPTransport(action="check", objectType="DDLS", objectName="<placeholder_name>", package="<package>")
This checks if a transport is required and returns existing transports for the package. If a transport is required:
SAPTransport(action="create", description="RAP Service: <Entity>", package="<package>")
If transport is required but unavailable, STOP — all write operations will fail without a valid transport for non-$TMP packages.
Research the target system thoroughly before designing anything. Every finding informs the plan.
Detect what the system supports — this determines available RAP features, syntax, naming, and safe defaults.
If ./system-info.md already exists from bootstrap-system-context, use it as input. Otherwise, reproduce the critical reads inline:
SAPRead(type="SYSTEM")
SAPRead(type="COMPONENTS")
SAPManage(action="probe")
SAPLint(action="list_rules")
Note: rap.available in the probe response is informational — it indicates whether the DDL source endpoint was detected, but RAP may still be available. Proceed with creation and handle errors if they occur.
Extract and note:
flp feature is available, the service can be registered in the Fiori Launchpad after creationSearch for existing RAP artifacts to understand the system's established patterns. This is critical for consistency.
SAPSearch(query="BDEF Z*", maxResults=20)
SAPSearch(query="SRVD Z*", maxResults=20)
SAPSearch(query="SRVB Z*", maxResults=20)
SAPSearch(query="DCLS Z*", maxResults=20)
SAPSearch(query="DDLX Z*", maxResults=20)
If NO Z BDEFs are found*, you MUST still ground yourself in at least one real system example before writing any code. Use this deterministic fallback:
SAPRead(type="TABL", name="SCARR")
This shows you the system's actual TABL annotation pattern (enhancement category, delivery class, data maintenance, client handling). Then read one activated CDS view:
SAPSearch(query="DDLS I_*", maxResults=5)
SAPRead(type="DDLS", name="<first_result>")
This shows CDS conventions (client field handling, alias style, annotation patterns). Do NOT proceed to Phase 4 until at least one real system table and one CDS view are in context. Writing from memory of documentation alone is the #1 cause of wasted retries.
If results are found, read 2-3 representative RAP stacks to extract the team's patterns:
SAPRead(type="BDEF", name="<found_bdef>")
SAPRead(type="DDLS", name="<found_interface_view>")
SAPRead(type="DDLS", name="<found_projection_view>")
SAPRead(type="DDLX", name="<found_metadata_ext>")
SAPRead(type="SRVB", name="<found_service_binding>")
SAPContext(type="DDLS", name="<found_interface_view>", action="impact")
SAPRead(type="VERSIONS", name="<found_interface_view>", objectType="DDLS")
SAPRead(type="SKTD", name="<found_interface_view>")
From these, extract:
ZI_/ZC_/ZR_? Entity suffix patterns? Table naming?strict ( 2 ) or strict?@UI annotation style? Header info pattern? Facet structure?syuname vs abp_creation_user, timestampl vs abp_creation_tstmpl)sysuuid_x16)? Semantic keys? Number ranges?with draft present? Draft table naming? Draft actions included?If SAPManage(action="probe") shows abapGit or gCTS support and the target package may already belong to a repo-backed workflow, inspect that context before creating new artifacts:
SAPGit(action="list_repos")
SAPGit(action="objects", repoId="<repo_id>")
SAPGit(action="history", repoId="<repo_id>", limit=20)
Use this to learn:
If the user mentioned existing tables or business objects, read them:
SAPSearch(query="<mentioned_table_or_object>")
SAPRead(type="TABL", name="<found_table>")
SAPContext(type="TABL", name="<found_table>")
Also search for related SAP standard objects in the domain:
SAPSearch(query="<domain_keyword>", maxResults=10)
Check if there are existing CDS views or tables the new service should build on rather than duplicating data.
If building on existing objects on a BTP system, check their API release state for Clean Core compliance:
SAPRead(type="API_STATE", name="<found_table_or_view>", objectType="TABL")
If an object is deprecated (C2) or not released, avoid building on it — search for its released successor instead.
To understand what already depends on a found CDS object, use CDS-specific impact instead of generic where-used:
SAPContext(type="DDLS", name="<found_view>", action="impact")
Use generic reverse dependencies only for non-DDLS objects:
SAPContext(type="CLAS", name="<found_class>", action="usages")
Check if the system has ATC configuration or custom check variants that indicate code quality standards:
SAPDiagnose(action="atc", type="CLAS", name="<any_existing_class>", variant="DEFAULT")
If existing RAP classes were found in 1b, read one and run lint + formatter discovery to understand the baseline:
SAPRead(type="CLAS", name="<found_bp_class>")
SAPLint(action="lint", source="<class_source>", name="<found_bp_class>")
SAPLint(action="get_formatter_settings")
This reveals what lint rules, strictness levels, and keyword/indentation preferences are enforced.
Use the SAP documentation MCP server deliberately, not as a generic keyword dump.
includeSamples=falseabapFlavor="cloud" on BTP / ABAP Cloud systemsabapFlavor="standard" on classic on-prem systems when relevantincludeSamples=truefetch(...) on the top hits you actually rely on.sap_community_search(...) only for edge cases, undocumented errors, or workaround hunting after official docs are insufficient.The search terms below are starting suggestions — adapt them based on the user's specific business requirement and the architecture decisions that need to be made. Craft search queries that target the gaps in your knowledge for this particular service.
Architecture and layering:
search(query="RAP projection BO vs RAP BO interface", includeSamples=false, abapFlavor="<cloud|standard>")
search(query="RAP service definition provider contracts odata_v4_ui odata_v4_webapi", includeSamples=false, abapFlavor="<cloud|standard>")
Domain-specific — tailor to the user's business domain:
search(query="<business_domain> RAP example SAP", includeSamples=true, abapFlavor="<cloud|standard>")
For example, if the user wants a travel app: search("RAP travel booking managed scenario example")
Architecture decisions — search only for topics relevant to this service:
search(query="RAP managed vs unmanaged scenario when to use", includeSamples=false, abapFlavor="<cloud|standard>")
search(query="RAP draft handling total etag draft-enabled associations", includeSamples=false, abapFlavor="<cloud|standard>")
search(query="RAP compositions parent child entity", includeSamples=true, abapFlavor="<cloud|standard>")
UI / service behavior — search if the service is UI-facing:
search(query="RAP value help metadata extension additional binding OData V4", includeSamples=false, abapFlavor="<cloud|standard>")
search(query="RAP feature control side effects authorization control", includeSamples=false, abapFlavor="<cloud|standard>")
search(query="metadata-driven UI metadata extension RAP Fiori Elements", includeSamples=false, abapFlavor="<cloud|standard>")
Clean core / released APIs — for BTP or released-object reuse:
search(query="ABAP API release RAP business object interface C1 C0", includeSamples=false, abapFlavor="cloud")
Edge cases / troubleshooting only after official docs fail:
sap_community_search(query="<exact error text or obscure RAP symptom>")
Important: Don't just run these searches verbatim. Analyze the user's spec and craft targeted queries that fill specific knowledge gaps. If the user asks for something unusual (for example, integration with a specific SAP module, specific field types, custom numbering, collaborative draft, or released BO interface consumption), search for those specifics.
No need to research naming conventions at runtime — the official SAP naming schema is documented below in the "SAP Official Naming Conventions" reference section. Use it directly as the default.
Before proceeding, compile a structured research summary. Present this to the user:
## System Research Summary
### System Profile
- Type: [BTP / On-Prem S/4HANA 20XX / ECC with ABAP Platform]
- ABAP Version: [Cloud / Standard ABAP 7.5X]
- RAP Support: [Full managed+draft / Managed only / Basic]
### Existing Code Patterns Found
- Naming: [e.g., "ZI_ prefix for interface views, ZC_ for projections, Z prefix + _D suffix for tables"]
- Architecture: [e.g., "All existing BOs use managed with draft, strict(2), UUID keys"]
- Field Style: [e.g., "CamelCase aliases, abp_ admin field types on BTP"]
- Annotation Style: [e.g., "Metadata extensions for all UI annotations, facet-based layout"]
- Service exposure: [e.g., "projection view + OData V4 UI binding, provider contract aligned"]
- N existing RAP services found: [list names]
### Domain Research
- Related existing objects: [tables, views, classes found]
- SAP standard objects in domain: [relevant standard CDS views, BAPIs]
- Clean core posture: [released APIs confirmed / successor required / custom tables only]
- Best practices from docs: [key findings]
### Quality Baseline
- ATC variant: [DEFAULT / custom]
- Lint findings: [clean / N issues on existing code]
- Strictness: [strict(2) / strict / none]
- Formatter settings: [keywordUpper / keywordLower / keywordAuto, indentation on/off]
Based on research findings, ask targeted questions. Only ask what research couldn't answer. Group questions by category and provide recommendations based on findings.
For each question, lead with a concrete recommendation based on the user's spec and research, explain why, then list alternatives with upsides/downsides. These are foundational decisions — changing them after creation requires rebuilding most artifacts. Make sure the user understands the trade-offs.
1. Implementation scenario
Based on your spec [quote relevant part], I would suggest managed because [reason — e.g., "this is a new greenfield BO with no existing persistence logic to wrap"].
Your options:
Option Upside Downside Managed Framework handles CRUD automatically, less code, faster to build Less control over persistence, must follow RAP conventions Unmanaged Full control over persistence, can wrap existing BAPIs/FMs You must implement all CRUD yourself, significantly more code Managed with unmanaged save Managed convenience + custom save (e.g., call BAPI in save phase) More complex, need to understand save sequence Does managed fit, or do you need to wrap existing logic?
2. Entity structure
Based on your spec [quote relevant part], I would suggest [single entity / compositions] because [reason — e.g., "your description mentions line items which is a classic parent-child pattern"].
Your options:
Option Upside Downside Single root entity Simplest, one table, one CDS stack Cannot model hierarchies Compositions (parent → child) Models real business hierarchies (Order → Items), draft cascades to children Each child entity needs its own table + draft table + CDS stack Associations Lightweight references to related entities (e.g., lookup to Customer) No lifecycle dependency, no cascade delete How many entities do you need and what are their relationships?
3. Key strategy
Based on your spec, I would suggest UUID (internal early numbering) because [reason — e.g., "there's no mention of a user-visible business key, and UUID is the simplest and most reliable approach"].
Your options:
Option Upside Downside UUID (internal early numbering) Auto-generated, no user input, no collision risk, simplest Keys are not human-readable Semantic key User-provided meaningful key (e.g., OrderNumber) Needs uniqueness validation, user must know the key upfront Number range Server-assigned sequential numbers, human-readable Needs number range object configuration, more setup Which key strategy fits your use case?
4. Service exposure / provider contract
I recommend OData V4 UI if this is a Fiori Elements-facing service, or OData V4 Web API if it is primarily for programmatic consumers. The service definition provider contract and the service binding type must match.
Important context on service exposure:
- OData V4 UI: Best default for Fiori Elements List Report / Object Page apps.
- OData V4 Web API: Better when the primary consumer is integration code, tests, or external apps.
- OData V2: Use only if there is a hard legacy/UI client requirement.
Which consumer is primary: Fiori UI or API/integration?
4b. Draft model
I recommend draft for transactional Fiori Elements applications unless your use case is explicitly non-draft, API-only, or constrained by system/version realities.
Important constraints from SAP docs:
- Draft requires a dedicated draft table and total ETag.
- Every child in a draft-enabled composition hierarchy must be represented in the BDEF.
- Some OData/Fiori behaviors differ between V2 and V4.
Should this service be draft-enabled?
4c. Authorization model
I recommend
@AccessControl.authorizationCheck: #MANDATORY+ DCLS so the service has explicit row-level authorization from day one. SAP's RAP docs recommend#MANDATORYinstead of#CHECKfor RAP BOs.Your options:
Option Upside Downside #MANDATORY + DCLS Correct RAP baseline, production-ready authorization model Requires access-control design decisions #NOT_ALLOWED / #NOT_REQUIRED Faster prototyping Not suitable for production authorization Should I generate a strict baseline DCLS now (with inheriting conditions) and mark domain-specific rules as follow-up?
5. Fields and types
Based on your description, I've identified these business fields:
Field Proposed Type Notes ... ... ... Are these correct? Any fields to add, remove, or change types?
6. Value helps / fixed values
Which fields need dropdowns or value helps?
- Status field → fixed values (e.g., New/Open/Completed)?
- Reference fields → value help from other CDS views?
7. Existing data sources
[If tables/views were found in research] Should this service read from existing table
<TABLE>or create a new table?
7b. Proper DDIC typing (production services)
For production-quality services, I can create proper domains (DOMA) and data elements (DTEL) instead of using inline types. This enables:
- Reusable field types across multiple tables/views
- Fixed value lists on domains (e.g., status domain with A=Active, I=Inactive)
- Consistent field labels (short/medium/long/heading) across all UIs
- Search help attachments on data elements
For
$TMPprototypes, inline types are fine. For transportable packages, proper DOMA/DTEL is recommended. Want me to create dedicated domains and data elements for the business fields?
8. Entity naming
I'm using the official SAP naming conventions (see reference section below). For an entity named e.g.
Travel:
Artifact SAP Convention Proposed Name Active persistence table A_prefixZA_TRAVELDraft table D_prefixZD_TRAVELBase/interface CDS view R_orI_prefix,TPsuffixZR_TravelTPProjection CDS view C_prefixZC_TravelInterface BDEF Same as root entity ZR_TravelTPProjection BDEF Same as projection view ZC_TravelMetadata extension Same as CDS entity it annotates ZC_TravelService definition UI_prefix (if UI service)ZUI_TravelService binding UI_prefix,_O4suffixZUI_Travel_O4Behavior pool class BP_prefixZBP_R_TravelTP[If different patterns were found on the system]: Note: I found existing RAP projects on your system using a different convention (
<pattern found>). I'm defaulting to SAP standard naming, but if you prefer to match the existing system-wide convention, or use a completely different one, let me know.Any name changes?
9. Fiori Elements frontend
Will this service be consumed by a Fiori Elements app (auto-generated UI from annotations)?
If yes, the metadata extension (DDLX) and UI annotations in the plan will be optimized for Fiori Elements List Report + Object Page (the most common pattern).
Note: ARC-1 currently does not generate the Fiori Elements frontend application itself — only the backend OData service with proper annotations. The Fiori app can be generated from ADT ("Create Fiori Project..." on the service binding) or via the SAP Fiori tools in VS Code. The plan will include guidance on this as a follow-up step.
If no (freestyle UI5 app or non-UI consumer), we can simplify the annotations.
9b. Backend-driven UI features
If this is a Fiori Elements app, should I plan any of these from the start?
- Field-level read-only / mandatory behavior
- Value helps
- Side effects
- Feature control for actions or updates
Note: feature control and side effects are RAP concepts, but they are primarily consumable by Fiori Elements UIs.
10. Searchable fields
Which fields should be searchable (appear in the search bar)?
12. Validations needed
Which business rules should be enforced?
- Mandatory fields?
- Cross-field validations (e.g., start date < end date)?
- Status transition rules?
13. Determinations needed
Which values should be auto-calculated?
- Default values on create?
- Derived fields (e.g., total = price × quantity)?
14. Custom actions
Beyond standard CRUD, do you need actions like "Approve", "Release", "Cancel"?
Important: Don't ask all 14 questions. Research should have answered many of them. Only ask what's genuinely needed. Group remaining questions and present them concisely. Provide your recommendations for each.
Wait for the user to answer before proceeding.
Based on research + user answers, create a detailed implementation plan.
Create a comprehensive design table:
## RAP Service Implementation Plan: <Service Name>
### Architecture Decisions
| Decision | Choice | Rationale |
|----------|--------|-----------|
| Scenario | Managed / Unmanaged | [why] |
| Service exposure | OData V4 UI / OData V4 Web API / OData V2 | [why] |
| Draft | Yes / No | [why] |
| Key strategy | UUID / Semantic / NumberRange | [why] |
| Provider contract | `odata_v4_ui` / `odata_v4_webapi` / `odata_v2_*` | [why] |
| Strict mode | strict(2) / strict | [system dependent] |
| Admin fields | syuname+timestampl / abp_* types | [system dependent] |
| Authorization | `#MANDATORY + DCLS` / prototype-only | [why] |
| Build engine | ARC-1 (manual stack) / SAP `abap-mcp` generator (single-root seed) | [generator only if it's connected AND the model is a single root, managed+draft] |
### Entity Model
| Entity | Role | Key Fields | Business Fields |
|--------|------|-----------|-----------------|
| <Root> | Root entity | key_uuid | field1, field2, ... |
| <Child> | Composition of Root | key_uuid, parent_uuid | field_a, field_b, ... |
### Artifact Stack
| # | Type | Name | Description | Dependencies |
|---|------|------|-------------|-------------|
| 1 | DDLS | <table> | Database table entity | — |
| 2 | DDLS | <draft_table> | Draft table (if draft) | — |
| 3 | DDLS | ZI_<Entity> | Interface CDS view | #1 |
| 4 | DCLS | ZI_<Entity>_DCL | Access control for interface CDS view | #3 |
| 5 | CLAS | ZBP_I_<Entity> | Behavior pool class | #3 |
| 6 | BDEF | ZI_<Entity> | Interface behavior definition | #3, #5 |
| 7 | DDLS | ZC_<Entity> | Projection CDS view | #3 |
| 8 | BDEF | ZC_<Entity> | Projection behavior definition | #6, #7 |
| 9 | DDLX | ZC_<Entity> | Metadata extension | #7 |
| 10 | SRVD | ZSD_<Entity> | Service definition | #7 |
| 11 | SRVB | ZSB_<Entity>_V4 | Service binding | #10 |
### Field Definitions
| Field | DB Column | CDS Alias | Type | Annotations | Notes |
|-------|-----------|-----------|------|-------------|-------|
| Key | key_uuid | KeyUuid | sysuuid_x16 | @Semantics | Internal numbering |
| ... | ... | ... | ... | ... | ... |
### Behavior Definition Spec
- Scenario: managed
- Draft: with draft / without draft
- ETag: LocalLastChangedAt
- Lock: master [total etag LastChangedAt]
- Numbering: managed (KeyUuid)
- Read-only fields: KeyUuid, CreatedBy, CreatedAt, LastChangedBy, LastChangedAt, LocalLastChangedAt
- Draft actions: Resume, Edit, Activate (optimized), Discard, Prepare
- Determinations (Phase 1): [list with triggers]
- Validations (Phase 1): [list with triggers]
- Custom actions (Phase 1): [list or "none — add later"]
### UI Annotations Spec
- Header: typeName="<Entity>", title=<MainField>, description=<SecondaryField>
- Facets: [list facet structure]
- List columns: [ordered list with position, importance]
- Selection fields: [filter bar fields]
- Search fields: [searchable fields]
### Naming Convention Used
<Document which convention was followed and why — matches existing code / SAP standard / user preference>
### Quality Checks Planned
- Lint validation before each write (automatic via arc-1)
- PrettyPrint of ABAP sources using SAP formatter settings before CLAS writes
- Syntax check after each activation
- ATC check after full stack activation
- Revision/history readback if iterating on pre-existing artifacts
- [If behavior logic]: Unit test skeleton
Present the plan clearly and ask. Emphasize that changes after creation are significantly harder:
Implementation Plan Ready
I've designed a [managed/unmanaged] RAP service with [N] entities, [with/without] draft, using [naming convention].
[Show the Artifact Stack table and Field Definitions table]
⚠️ Important: Please review carefully before approving. Once the artifacts are created on the SAP system, changing fundamental decisions (managed vs. unmanaged, key strategy, entity structure, draft yes/no) requires deleting and recreating most artifacts. It is much easier to change the plan now than to restructure after creation. If anything is unclear or you're unsure about a decision, ask now.
Please review:
- Are the artifact names correct?
- Are the fields complete and correctly typed?
- Is the architecture (managed/draft/keys) what you need?
- Any questions about the design decisions?
- Any changes before I start creating?
Say "approve" to proceed, or ask questions / tell me what to change.
Do NOT proceed until the user explicitly approves.
After approval, create the artifacts. Use batch creation when possible.
Fail fast: If the first DDLS/BDEF write fails with 415 or 500, stop all further CDS writes immediately. Do not retry with different types — the underlying issue is system-level, not object-specific. Run SAPManage(action="probe") to verify rap.available status.
On ANY save failure (400, 007, syntax error) — follow this protocol, no exceptions:
SBD... message IDs, V1..V4 variables, and line-aware details; for source-based DDIC creates it may also append inactive syntax-check results). Use these details to identify the exact failing field/annotation.SAPRead(type=X, name=Y)Key principle: The problem is almost always your source content, never the object's state. Deleting and recreating with the same source will produce the same error. Fix the source first.
ALWAYS try batch_create first. Do not start with sequential creates. batch_create creates all objects in one call — put dependencies first in the array (tables → views → DCLS → class → BDEFs → service definition).
SAPWrite(action="batch_create", objects=[...], package="<package>", transport="<transport>")
For composition-linked DDLS or other interdependent siblings (parent's composition [0..*] of ZR_CHILD where the child is also in the same batch), pass activateAtEnd: true so ARC-1 writes inactive drafts for every object first and then issues ONE terminal activateBatch. SAP's activator sees the whole graph at once and resolves cross-references between siblings. Per-object inline activation would fail on the parent with "data source ZR_CHILD does not exist or is not active" because the child is still inactive when the parent gets activated.
SAPWrite(action="batch_create", activateAtEnd: true, objects=[...], package="<package>", transport="<transport>")
If some generated objects need explicit per-item routing, put package and transport on the individual objects. Item-level values override the top-level batch values and are required when a recovered plan mixes packages:
SAPWrite(action="batch_create", objects=[
{type: "TABL", name: "<table>", package: "<package>", transport: "<transport>", source: "<ddl>"},
{type: "DDLS", name: "ZI_<entity>", package: "<package>", transport: "<transport>", source: "<ddl>"}
])
Only fall back to sequential creation (Phase 4b) if batch_create returns an error. If batch fails: read the error, fix the SPECIFIC failing object's source, and retry batch_create. Do NOT switch to sequential mode after one batch failure.
Before creating artifacts, optionally check for lingering inactive objects that might cause conflicts:
SAPRead(type="INACTIVE_OBJECTS")
Note: This may return 404 on some systems where the /sap/bc/adt/activation/inactive endpoint is not available. If so, skip this check and proceed — it's a convenience check, not a requirement.
If inactive objects with conflicting names exist, resolve them first (activate or delete).
For reset/create preflights that need to know whether target names exist anywhere in the repository, use exact object-directory lookup instead of a long SAPQuery against TADIR:
SAPSearch(searchType="tadir_lookup",
names=["<table>","ZI_<entity>","ZC_<entity>","ZSB_<entity>_V4"],
objectTypes=["TABL","DDLS","BDEF","SRVD","SRVB","CLAS"])
The lookup groups exact matches by requested name and returns missing; do not build large WHERE OBJ_NAME IN (...) SQL lists for this check.
After cleanup, verify the names are truly gone — the default ADT info-system endpoint filters out TADIR rows that don't resolve to a workbench resource, so an orphan "ghost" (TADIR row left behind by an aborted create/delete) is invisible. Re-run the lookup with source: "both" to detect ghosts. This requires sql scope (admin must have SAP_ALLOW_FREE_SQL=true):
SAPSearch(searchType="tadir_lookup",
names=["<table>","ZI_<entity>","ZC_<entity>","ZSB_<entity>_V4"],
source: "both")
If the response contains a splitBrain array, the listed names exist in TADIR but ADT can't resolve them — clean up via SE03 / RS_DD_TADIR_CLEANUP before retrying create.
If the user opted for proper DDIC typing, create domains and data elements before the table entity:
SAPWrite(action="create", type="DOMA", name="Z<DOMAIN>", package="<package>", transport="<transport>",
dataType="CHAR", length=1, fixedValues=[{low:"A", description:"Active"}, {low:"I", description:"Inactive"}])
SAPWrite(action="create", type="DTEL", name="Z<DATAELEMENT>", package="<package>", transport="<transport>",
typeKind="domain", dataType="Z<DOMAIN>", labels={short:"Status", medium:"Object Status", long:"Object Status", heading:"Status"})
SAPActivate(objects=[{type:"DOMA", name:"Z<DOMAIN>"}, {type:"DTEL", name:"Z<DATAELEMENT>"}])
Then reference the data elements in the table entity DDL instead of inline types (e.g., status : z<dataelement> instead of status : abap.char(1)).
If the official SAP ABAP MCP server is connected alongside ARC-1 (the abap-mcp server bundled with ABAP Development Tools for VS Code / Eclipse ADT 3.60+) and the approved plan's Build engine is the generator, hand the single-root build to SAP's Generate ABAP Repository Objects framework, then return here for everything it can't do. Only valid for a single root entity (the generator does "a maximum of one entity, no compositions") that is managed+draft on a table with last_changed : abp_lastchange_tstmpl + local_last_changed : abp_locinst_lastchange_tstmpl (or use the from-scratch variant that generates the table). It is one-shot — not for post-generation. Anything else → use 4a/4b.
abap_generators-list_generators tool → use 4a/4b. Else call it and match "OData UI Service" (or "OData Web API Service") by display name, use the returned id (uiservice/webapiservice on SAP_BASIS 758; ui-service/webapi-service/x-ui-service on 816).abap_generators-get_schema(generatorId, packageName, referencedObjectType="TABL", referencedObjectName="<table>") → fill every required field from the returned schema → abap_generators-generate_objects(generatorId, …) into the planned package + transport (a mutation — same guardrails as 4a).If the system supports it and the artifact stack is straightforward:
SAPWrite(action="batch_create", objects=[
{type: "TABL", name: "<table>", description: "<desc>", source: "<ddl>"},
{type: "DDLS", name: "ZI_<entity>", description: "<desc>", source: "<ddl>"},
{type: "DCLS", name: "ZI_<entity>_DCL", description: "<desc>", source: "<dcl>"},
{type: "DDLS", name: "ZC_<entity>", description: "<desc>", source: "<ddl>"},
{type: "BDEF", name: "ZI_<entity>", description: "<desc>", source: "<bdef>"},
{type: "BDEF", name: "ZC_<entity>", description: "<desc>", source: "<bdef>"},
{type: "DDLX", name: "ZC_<entity>", description: "<desc>", source: "<ddlx>"},
{type: "SRVD", name: "ZSD_<entity>", description: "<desc>", source: "<srvd>"},
{type: "CLAS", name: "ZBP_I_<entity>", description: "<desc>", source: "<class>"},
{type: "SRVB", name: "ZSB_<entity>_V4", description: "<desc>", serviceDefinition: "ZSD_<entity>", bindingType: "ODataV4-UI"}
], package="<package>", transport="<transport>")
Objects are created in array order — put dependencies first.
If batch creation fails or the stack is complex (compositions, multiple entities), create sequentially in two passes. This avoids BDEF↔behavior-pool deadlocks and reduces retries on on-prem 7.5x.
Pass 1 — minimal working BO (CRUD + compositions):
composition [0..*]) → Create + Activate.METHODS ... FOR ... declarations) → Create + Activate.projection; header only, use-clauses only) → Create + Activate.At this point the service is previewable and stable.
Pass 2 — business logic + hardening:
SAPWrite(action="scaffold_rap_handlers", type="CLAS", name="ZBP_I_<entity>", bdefName="ZI_<entity>") to list missing signatures.autoApply=true to inject declarations plus empty implementation stubs into class sections (main, definitions, implementations) when possible.SAPDiagnose(action="quickfix", ...) + SAPDiagnose(action="apply_quickfix", ...) if proposals are available.SAPWrite(action="edit_method", ...) (avoid full-class rewrites when behavior pools are unstable).strict ( 2 ) and authorization handlers only after signatures and method bodies are active.After pass 2 changes, batch activate interdependent objects:
SAPActivate(objects=[
{type: "CLAS", name: "ZBP_I_<entity>"},
{type: "BDEF", name: "ZI_<entity>"},
{type: "BDEF", name: "ZC_<entity>"}
])
Note: Activation returns structured responses with detailed error/warning messages including line numbers and URIs. Errors block activation; warnings allow it but should be reviewed. Use this information to pinpoint exact issues rather than re-reading full source.
Use the source code templates from the plan. Adapt them based on research findings:
abp_* admin field types, ABAP Cloud syntax, strict ( 2 )syuname/timestampl types, classic or Cloud syntax depending on what existing code usesuse draft in projection BDEFSAPLint(action="format", source="<abap_source>", name="<class_name>") on generated ABAP classes before writing them if you want SAP-native keyword case/indentationAfter all artifacts are created and activated:
Syntax check the behavior pool:
SAPDiagnose(action="syntax", type="CLAS", name="ZBP_I_<entity>")
ATC check the full stack (if ATC is available):
SAPDiagnose(action="atc", type="BDEF", name="ZI_<entity>")
Verify no inactive objects remain (may return 404 on some systems — skip if so):
SAPRead(type="INACTIVE_OBJECTS")
Read back key artifacts to confirm they're correct:
SAPRead(type="BDEF", name="ZI_<entity>")
SAPRead(type="DDLS", name="ZI_<entity>")
SAPRead(type="SRVD", name="ZSD_<entity>")
Lint + formatter check the behavior pool:
SAPRead(type="CLAS", name="ZBP_I_<entity>")
SAPLint(action="lint", source="<behavior_pool_source>", name="ZBP_I_<entity>")
SAPLint(action="get_formatter_settings")
Fix any issues found. Re-activate if needed.
Create the service binding:
SAPWrite(action="create", type="SRVB", name="ZSB_<entity>_V4", package="<package>", transport="<transport>",
serviceDefinition="ZSD_<entity>", bindingType="ODataV4-UI", description="<Entity> OData V4 Service")
Activate the service binding:
SAPActivate(type="SRVB", name="ZSB_<entity>_V4")
Publish the service binding (makes the OData service available):
SAPActivate(action="publish_srvb", name="ZSB_<entity>_V4")
Verify the publish status and service URL:
SAPRead(type="SRVB", name="ZSB_<entity>_V4")
⚠️ CHECKPOINT: Verify the SRVB read shows published: true, the expected binding type, and a service URL. For OData V4 bindings, publish/unpublish applies to the whole binding, not per service version.
After the service binding is published, the RAP service can be previewed directly. In ADT, the user can open the service binding, select an entity (e.g., "Root"), and click "Preview..." to launch the Fiori Elements preview in a browser. This generates a preview URL via the ADT business services endpoint.
Inform the user:
Your service is live! Open the service binding
ZSB_<ENTITY>_V4in ADT, select the root entity, and click "Preview..." to see the auto-generated Fiori Elements List Report + Object Page.
RAP Service Generation Complete!
## Architecture
- Scenario: [managed/unmanaged]
- Draft: [enabled/disabled]
- Key strategy: [UUID/semantic/number range]
- OData version: [V4/V2]
- Followed conventions from: [existing code / SAP standard]
## Created Artifacts
[x] Database table entity: <table_name>
[x] Draft table entity: <draft_table> (if applicable)
[x] Interface CDS view: ZI_<Entity>
[x] Interface behavior definition: ZI_<Entity>
[x] Projection CDS view: ZC_<Entity>
[x] Projection behavior definition: ZC_<Entity>
[x] Metadata extension: ZC_<Entity>
[x] Service definition: ZSD_<Entity>
[x] Behavior pool class: ZBP_I_<Entity>
[x] Service binding: ZSB_<Entity>_V4
[x] Service binding published
## Quality Checks
[x] All artifacts activated successfully
[x] Syntax check: clean
[x] Lint check: clean
[x] ATC check: [clean / N findings noted]
## Consistency with Existing Code
[x] Naming matches existing convention: [pattern]
[x] Annotation style matches: [pattern]
[x] Admin fields match: [pattern]
Offer follow-up actions based on the plan:
## Recommended Next Steps
1. **Preview the service** in Fiori Elements (ADT → Service Binding → select entity → Preview...)
2. **Add business logic** → use `generate-rap-logic` skill:
- Determinations: [list from plan]
- Validations: [list from plan]
3. **Add value helps** for reference fields
4. **Add custom actions** if needed (e.g., Approve, Release)
5. **Generate unit tests** → use `generate-abap-unit-test` skill
6. **Add compositions** for child entities (if multi-entity scenario planned for Phase 2)
7. **Register in FLP** (if FLP feature available) → use SAPManage:
- `SAPManage(action="flp_create_catalog", catalogId="Z_<ENTITY>_C", title="<Entity> Catalog")`
- `SAPManage(action="flp_create_tile", catalogId="Z_<ENTITY>_C", tile={id:"Z_<ENTITY>_T", title:"<Entity>", semanticObject:"<Entity>", semanticAction:"manage"})`
- `SAPManage(action="flp_create_group", groupId="Z_<ENTITY>_G", title="<Entity>")`
- `SAPManage(action="flp_add_tile_to_group", groupId="Z_<ENTITY>_G", catalogId="Z_<ENTITY>_C", tileId="Z_<ENTITY>_T")`
8. **Create DOMA/DTEL** (if not done in Phase 4) for proper reusable typing
9. **Release transport** (if transportable package) → use `SAPTransport(action="release_recursive", transport="<TR>")` to release tasks and parent in one step
10. **Attach generated documentation** (optional) → use `SAPWrite(action="create", type="SKTD", refObjectType="SRVD", name="<service_doc_name>", source="<architecture_summary_markdown>")`
11. **Review transport + revision context on later iterations** → use `SAPTransport(action="history", objectType="SRVD", objectName="ZSD_<ENTITY>")` and `SAPRead(type="VERSIONS", name="ZSD_<ENTITY>", objectType="SRVD")`
12. **If the package is repo-managed** → use `SAPGit` (`list_repos`, `objects`, `history`) before changing naming or branch conventions
This section covers common pitfalls that cause repeated save failures on on-prem ABAP 7.5x systems. Every rule here was learned from real failures — violating any one often returns SBD_MESSAGES 007 save errors. ARC-1 surfaces more detail now, but these pitfalls remain the root causes.
Without ALL of these annotations, the table save always fails with 007:
@EndUserText.label : '<description>'
@AbapCatalog.enhancement.category : #NOT_EXTENSIBLE
@AbapCatalog.tableCategory : #TRANSPARENT
@AbapCatalog.deliveryClass : #A
@AbapCatalog.dataMaintenance : #RESTRICTED
define table <name> {
key client : abap.clnt not null;
key <uuid_key> : sysuuid_x16 not null;
...
}
| Correct | Wrong (causes 007 / activation failure) |
|---|---|
abap.int4 | int4 |
abap.char(N) | char(N) |
abap.numc(N) | numc(N) |
abap.dec(N,M) | dec(N,M) |
abap.clnt | clnt |
sysuuid_x16 | raw(16) for UUID |
timestampl | abap.utclong in TABL |
syuname | abap.uname in TABL |
abap.cuky | cuky |
abap.curr(N,M) | curr(N,M) without reference annotation |
abap.char(1) (X/space booleans) | abap.boolean in TABL |
key client : abap.clnt not null; as the first key field@ClientHandling annotation — it is rejected on view entities.on clause. Write composition [0..*] of ChildView as _Child — the framework resolves by key automatically. Adding on causes "On conditions are not allowed in compositions."on conditions: Use CamelCase aliases from the select list, NOT the DB column name. Write $projection.ClubUuid = _Club.ClubUuid, NOT $projection.club_uuid. Using the DB column name causes "The referenced select list name is obscured by an alias."foreign key clauses in the TABL definition — keep tables simple.Activate the child view entity first, then the root. The root's composition references the child, so the child must be active. Use batch activation with both: SAPActivate(objects=[{type:"DDLS",name:"<child>"},{type:"DDLS",name:"<root>"}]) — the activation engine resolves the order.
Pre-write lint runs by default for ABAP sources and DDLS. BDEF/SRVD/SRVB/DDLX/TABL/DOMA/DTEL still need activation or RAP preflight validation for most semantic checks. Keep RAP preflight enabled by default; only use preflightBeforeWrite: false for narrowly-scoped recovery when you understand the specific rule being bypassed. If lint blocks a known-valid case, use lintBeforeWrite: false for that specific write and keep the override local.
This is fine — the system may be new to RAP. Fall back to SAP standard naming conventions and best practices from documentation. Note this in the plan:
"No existing RAP projects found on system. Using SAP standard naming conventions and current best practices from documentation."
If research reveals the system lacks a feature the user needs (e.g., draft on old on-prem, table entities pre-7.55):
Fall back to sequential creation (Phase 4b). Report which objects succeeded and which failed. Fix the failing object and retry.
| 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. |
Resource X does already exist on create | Prior stub or name collision | Switch immediately to SAPWrite(action="update", ...) and resend the full source. Do not retry create with the same payload. |
| Feature not supported | System version too old | Adapt plan to available features |
| Activation error | Dependency order wrong | Use batch activation or sequential in dependency order |
| Lint blocks write | Code doesn't match lint rules | Adjust generated code to pass lint, or check if lint config is too strict |
| BDEF syntax error | Wrong field aliases or entity references | Cross-check CDS aliases with BDEF field references |
| Transport required | Non-$TMP package without transport | Use SAPTransport(action="check") to find or create a transport — see Phase 1-pre |
| Lock conflict on create | Object locked by another user/transport | Wait or use a different name; check SAPTransport(action="list") for conflicting transports |
Annotation with reference to currency code for field X is missing | abap.curr field has no currency reference | Add @Semantics.amount.currencyCode directly above each amount field; pair with abap.cuky field. |
"global or instance" was expected, not "none" | Invalid BDEF auth enum on 7.5x | Use ( global ) or ( instance ), or defer auth until handler exists. |
dependent entity cannot have the identically named field ... as the etag master entity | Root and child etag names collide | Use different etag field names for root vs dependent entities. |
"draft or side" was expected, not "etag" in projection BDEF | use etag header is invalid on 7.5x | Keep projection header as projection; only. |
not a suitable draft persistency ... there is no "X" field | Hand-written draft table column naming mismatch | Generate draft table via quick-fix (preferred), or follow CDS-name derivation exactly. |
Annotation 'UI.headerInfo.X' used at wrong position in DDLX | Unsupported annotation scope in DDLX on 7.5x | Move @UI.headerInfo, @Search.searchable, @ObjectModel.* to projection DDLS source. |
Multiple entries with same name 'X' not allowed in DDLX | Duplicate annotation blocks on same field | Consolidate field annotations into one block. |
[?/011] while updating behavior pool class | Full-class behavior-pool write path unstable for METHODS ... FOR ... | Use SAPWrite(action="scaffold_rap_handlers", ...) first (optionally autoApply=true), then quick-fix fallback, then patch bodies with SAPWrite(action="edit_method", ...). |
This skill prioritizes correctness and consistency over speed. The extra research time (5-10 minutes) pays off by:
| Skill | Relationship |
|---|---|
generate-rap-service | Vibe code version — faster, less thorough, good for prototypes |
generate-rap-logic | Natural follow-up — implement determinations/validations identified in the plan |
generate-abap-unit-test | Follow-up — generate tests for the behavior pool |
explain-abap-code | Can be used during research to understand existing RAP projects found on the system |
implement-feature | For implementing non-RAP features in the arc-1 codebase itself |
Source: SAP Help — Naming Conventions for Development Objects
[/<namespace>/][<prefix>]_<object_name>_[<suffix>]
/DMO/ namespace is reserved for SAP demo purposes only — never use it in productive development| Object | Convention | Example (customer namespace) |
|---|---|---|
| Active persistence table | A_ prefix | ZA_TRAVEL |
| Draft table | D_ prefix | ZD_TRAVEL |
| Object | Convention | Notes | Example |
|---|---|---|---|
| Base/Root CDS view entity | R_ prefix | The base BO entity. Use TP suffix to indicate transactional processing relevance | ZR_TravelTP |
| Interface CDS view | I_ prefix | Reusable interface view layer (alternative to R_ in some patterns) | ZI_Travel |
| Projection CDS view | C_ prefix | C = consumption layer. If multiple projections exist, the name should represent the projection role | ZC_Travel |
| Extension include view | E_ prefix | For extensibility | ZE_Travel |
| Behavior definition | Same name as root entity | BDEF always shares the name of the CDS view it belongs to | ZR_TravelTP (interface), ZC_Travel (projection) |
| Metadata extension | Same name as CDS entity | If multiple extensions for one entity, add numbered suffix | ZC_Travel, ZC_Travel_2 |
| Object | Convention | Notes | Example |
|---|---|---|---|
| Service definition | No mandatory prefix | If not reused across UI/API, may use UI_ or API_ prefix | ZUI_Travel or Z_Travel |
| Service binding (UI) | UI_ prefix | For Fiori Elements / UI consumption | ZUI_Travel_O4 |
| Service binding (Web API) | API_ prefix | For programmatic / integration consumption | ZAPI_Travel_O4 |
| OData V2 suffix | _O2 | ZUI_Travel_O2 | |
| OData V4 suffix | _O4 | ZUI_Travel_O4 |
| Object | Convention | Notes | Example |
|---|---|---|---|
| Behavior pool class | BP_ prefix | Global class implementing BO behavior | ZBP_R_TravelTP |
| Local handler class | LHC_ prefix | Local class within behavior pool | LHC_Travel_Create |
| Local saver class | LSC_ prefix | Local class within behavior pool | LSC_Travel |
| # | Object Type | SAP Naming | Name |
|---|---|---|---|
| 1 | Database table (active) | A_ prefix | ZA_TRAVEL |
| 2 | Database table (draft) | D_ prefix | ZD_TRAVEL |
| 3 | Base CDS view entity | R_ prefix + TP suffix | ZR_TravelTP |
| 4 | Projection CDS view | C_ prefix | ZC_Travel |
| 5 | Interface BDEF | = root entity name | ZR_TravelTP |
| 6 | Projection BDEF | = projection view name | ZC_Travel |
| 7 | Metadata extension | = projection view name | ZC_Travel |
| 8 | Service definition | UI_ prefix (optional) | ZUI_Travel |
| 9 | Service binding | UI_ prefix + _O4 suffix | ZUI_Travel_O4 |
| 10 | Behavior pool class | BP_ prefix | ZBP_R_TravelTP |
R_ (base/root view entity): Used in the SAP standard RAP development guides (managed, unmanaged, draft). This is the current SAP recommendation for new RAP development.I_ (interface view): Historically used and still common. Represents a reusable interface layer. Many existing tutorials and older projects use I_ instead of R_.R_ for new projects following SAP's latest guides. If existing code on the system uses I_, match that for consistency.A_ and D_ prefixes for active and draft tables respectively_D suffix for the table and _DD for draft — this is not the official SAP convention but is widely seen in practicenpx claudepluginhub arc-mcp/arc-1 --plugin arc-1Generates 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.
Guides 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.
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.