Building SAP CAP & Fiori Apps with AI Agents Using Markdown Files
This guide covers a Markdown-based AI agent architecture for SAP CAP and Fiori Elements development. The approach uses 5 specialized agents that work across Claude, Cursor, Windsurf, and other AI tools that support context files.
Repository: sap-cap-fiori-ai-agents
Get the agents: Download Free SAP AI Agents
Why Markdown Agents vs MCP
| Aspect | Markdown Agents | MCP Server |
|---|---|---|
| Portability | Works in any AI tool with context files | Tool-specific implementation |
| Version Control | Plain text, easy Git diffs | Server code requires deployment |
| Iteration Speed | Edit text mid-session | Requires server restart |
| Best For | Development workflows, local files | Production integrations, external APIs |
Agent Architecture
The system consists of 5 Markdown files in the .ai/ directory:
1. Full Stack Orchestrator (sap-full-stack-orchestrator.md)
Purpose: Requirements decomposition and phase coordination
Key responsibilities:
- Gather requirements before code generation
- Break tasks into implementation phases
- Coordinate handoffs between specialized agents
2. SAP CAP Developer (sap-cap-developer.md)
Purpose: Backend development
Handles:
db/schema.cds- Entity definitions with associationssrv/*.cds- Service definitions and projectionssrv/*.js- Service handlers and business logicdb/data/*.csv- Mock data generation- Authorization patterns (
@requires,@restrict)
3. SAP Fiori Designer (sap-fiori-designer.md)
Purpose: Floorplan selection and UI architecture
Decision matrix:
| Use Case | Floorplan |
|---|---|
| Data tables with filters | List Report |
| Detail views with sections | Object Page |
| Task-based workflows | Worklist |
| Simple forms | Form Entry |
4. SAP Fiori Scaffolder (sap-fiori-scaffolder.md)
Purpose: App generation using official SAP tooling
Critical rule: Never create Fiori file structures manually. Uses @sap-ux/fiori-elements-writer for:
- Correct
manifest.jsonconfiguration - Proper component initialization
- i18n setup
5. Fiori Elements Developer (sap-fiori-elements-developer.md)
Purpose: CDS UI annotations
Annotation types:
@UI.LineItem- Table columns@UI.SelectionField- Filter bar fields@UI.FieldGroup- Form sections@UI.HeaderFacets- Object page header@UI.Criticality- Semantic coloring
Implementation Workflow
Phase 1: Requirements
@.ai/sap-full-stack-orchestrator.md
Build a customer complaint management system with:
- Customer self-service portal
- Support staff workbench
- Admin configuration console
The orchestrator will request clarification on:
- User roles and permissions
- Entity lifecycle states
- Integration requirements
Phase 2: Data Model
The CAP Developer generates schema following conventions:
namespace customer.complaints;
using { managed, cuid } from '@sap/cds/common';
entity Complaints : cuid, managed {
complaintNumber : String(30) not null;
title : String(200) @mandatory;
description : String(5000) @mandatory @UI.MultiLineText;
category : Association to Categories @mandatory;
priority : Association to Priorities @mandatory;
status : Association to Statuses @mandatory;
customer : Association to Customers @mandatory;
assignedTo : Association to SupportStaff;
submittedDate : DateTime @cds.on.insert: $now;
targetDate : Date;
resolvedDate : DateTime;
resolutionNotes : String(5000) @UI.MultiLineText;
// Computed fields
virtual daysOpen : Integer;
virtual statusCriticality : Integer;
comments : Composition of many Comments on comments.complaint = $self;
attachments : Composition of many Attachments on attachments.complaint = $self;
history : Composition of many StatusHistory on history.complaint = $self;
}
Phase 3: Service Layer
Role-based service projections:
using { customer.complaints as db } from '../db/schema';
// Customer-facing service
service CustomerService @(path: '/customer', requires: 'Customer') {
@readonly entity Categories as projection on db.Categories;
@readonly entity Priorities as projection on db.Priorities;
entity Complaints as projection on db.Complaints {
*,
category: redirected to Categories,
priority: redirected to Priorities
} excluding { assignedTo, assignedBy }
where customer.btpUserId = $user;
}
// Support staff service
service SupportService @(path: '/support', requires: 'SupportStaff') {
entity Complaints as projection on db.Complaints;
entity SupportStaff as projection on db.SupportStaff;
action assignComplaint(complaintId: UUID, staffId: UUID);
action resolveComplaint(complaintId: UUID, notes: String);
}
Phase 4: Fiori Scaffolding
Use the scaffolder agent to generate apps:
@.ai/sap-fiori-scaffolder.md
Generate List Report + Object Page for SupportService.Complaints
- App ID: support-workbench
- Data source: /support
- Main entity: Complaints
Generated structure:
app/
├── support-workbench/
│ ├── webapp/
│ │ ├── Component.js
│ │ ├── manifest.json
│ │ ├── i18n/
│ │ └── annotations/
│ ├── package.json
│ └── ui5.yaml
Phase 5: UI Annotations
The Fiori Elements Developer adds annotations:
annotate SupportService.Complaints with @(
UI: {
HeaderInfo: {
TypeName: 'Complaint',
TypeNamePlural: 'Complaints',
Title: { Value: complaintNumber },
Description: { Value: title }
},
SelectionFields: [
status_ID, priority_ID, category_ID, assignedTo_ID
],
LineItem: [
{ Value: complaintNumber, Label: 'Number' },
{ Value: title, Label: 'Title' },
{ Value: status.name, Label: 'Status', Criticality: statusCriticality },
{ Value: priority.name, Label: 'Priority', Criticality: priorityCriticality },
{ Value: customer.email, Label: 'Customer' },
{ Value: assignedTo.name, Label: 'Assigned To' },
{ Value: submittedDate, Label: 'Submitted' }
],
Facets: [
{
$Type: 'UI.ReferenceFacet',
ID: 'GeneralFacet',
Label: 'General Information',
Target: '@UI.FieldGroup#General'
},
{
$Type: 'UI.ReferenceFacet',
ID: 'CommentsFacet',
Label: 'Comments',
Target: 'comments/@UI.LineItem'
}
],
FieldGroup#General: {
Data: [
{ Value: title },
{ Value: description },
{ Value: category_ID },
{ Value: priority_ID },
{ Value: status_ID }
]
}
}
);
Common Issues and Fixes
Issue: Named model error in manifest.json
TypeError: Cannot read properties of undefined (reading 'getMetaModel')
Cause: Manifest uses named model instead of default
Fix: Change "model": "Complaints" to "model": ""
Issue: 403 on entity access
Cause: Missing authorization scope
Fix: Add @requires annotation or update access-control.cds
Issue: Value help not working
Cause: Missing @Common.ValueList annotation
Fix: Add value list configuration:
annotate Complaints with {
category @Common.ValueList: {
CollectionPath: 'Categories',
Parameters: [
{ $Type: 'Common.ValueListParameterInOut', LocalDataProperty: category_ID, ValueListProperty: 'ID' },
{ $Type: 'Common.ValueListParameterDisplayOnly', ValueListProperty: 'name' }
]
};
};
Prerequisites
- VS Code with AI extension (Claude Dev, Cursor, Windsurf)
- Claude Opus 4.5 / Sonnet 4.5 or Gemini Pro 3
- Node.js 18+
- SAP CAP CLI (
npm i -g @sap/cds-dk)
Quick Start
- Clone the agents repository:
git clone https://github.com/michal-majer/sap-cap-fiori-ai-agents.git
cp -r sap-cap-fiori-ai-agents/.ai your-project/.ai
- Initialize CAP project:
cds init your-project
cd your-project
- Start AI session with orchestrator:
@.ai/sap-full-stack-orchestrator.md
[Your requirements here]
- Run development server:
cds watch
Output Example
A typical session generates:
- 10-15 database entities
- 3-5 service definitions with role-based access
- 3-6 Fiori Elements apps
- 2,000+ lines of UI annotations
- Mock data CSV files
- Authorization configuration
Need Help With SAP BTP?
Let's talk about your project. No sales BS, just straight answers.
Get in Touch