CAP-level Agents
The @cap-js/agents plugin allows to easily create enterprise grade agents based on given CAP services, and served via the A2A protocol. It uses state-of-the-art agent harness frameworks like LangChain and LangGraph, or the Pi internally.
Add the Agents Plugin
Within your project root run this to add the @cap-js/agents plugin:
npm add @cap-js/agentsJava variant coming soon.
Declare @agent Services
Using @agent Annotation
Simply add the @agent annotation to a service definition to create an agent. For example, clone the capire/bookshop sample, and add a new file srv/cat-service-agent.cds with the following content:
using { CatalogService } from './cat-service';
annotate CatalogService with @agent;Optionally specify an alternative endpoint path ...
As usual with CAP protocol annotations, you can also choose a custom path under which the A2A endpoint should be served, instead of using the default path /a2a/<service>:
annotate CatalogService with @agent: '/cats-agent'More than Just Another Protocol
With that, the plugin auto-generates MCP tools from the service's entities and actions, creates a ReAct loop, and serves it via A2A protocol — no code required.
Using @agent.hitl
In AI land, HITL stands for Human-in-the-Loop and describes a mechanism that allows human intervention in the agent's decision-making process. Annotate a CDS action with @agent.hitl to require human approval before the agent may execute it. For example, the submitOrder action in the CatalogService can be annotated like this:
using { CatalogService } from './cat-service';
annotate CatalogService with @agent;
annotate CatalogService.submitOrder with @agent.hitl; When the agent decides to call the action, the task pauses and transitions to the A2A input-required state instead of running the action immediately.
Optional: AGENTS.md
You can add an AGENTS.md file next to the service definition's .cds file to add detailed information about the agent's identity and behaviour. When present, it replaces the generic default agentification: instead of the auto-generated ReAct agent, the plugin auto-builds the agent from the directory at startup — no JavaScript handlers required.
For example, we do so in the XTravels sample:
srv/travel-agent/
├── service.cds # the service definition
├── service.js # next to the service definition
└── AGENTS.md # next to the service definitionAGENTS.md defines who the agent is. The frontmatter populates the agent card; the body is the agent's system prompt:
---
name: travel-agent
version: 1.0.0
description: >
An agent to do travel planning, including choosing and booking hotels,
event passes, and flights using distributed subagents and tools, then
persists confirmed itineraries into the xtravels app.
---
# Travel Agent
## Identity
You are a friendly and knowledgeable travel planning assistant within the
XTravels application — the trips you persist show up in the app's Fiori UI.
## Guidelines
- Be proactive: when a user asks to plan a trip, start searching immediately.
Ask clarifying questions only when necessary.
- Use reasonable defaults for missing details: pick an upcoming weekend,
prefer mid-range budgets, suggest popular options.
- Call multiple tools or subagents in parallel when the request spans multiple
domains (flights + hotels + events).
...Using ./srv/* subfolders
You can use subfolders like ./srv/travel-agent as shown above for the XTravels sample. This helps keeping your service definitions and agent-related files organized, especially when working with multiple services and agents, and is supported by the cds.folders.srvs: srv/* config option added included with the @cap-js/agents plugin.
Optional: skills/*/SKILL.mds
The AGENTS.md file defines the agent's identity and behaviour, while the SKILL.md file describes the workflow and provides examples for a specific skill.
srv/travel-agent/
├── AGENTS.md # next to the service definition
├── skills/
│ ├── flight-booking/SKILL.md
│ ├── itinerary/SKILL.md
│ └── planning/SKILL.md
├── service.cds # the service definition
└── service.js # next to the service definitionTest-drive Locally
As usual, and following the Calesi principles of "convention over configuration", you can run your CAP server locally in development profile using cds watch including agents connected to available LLMs, with minimal additional setup.
Run with cds watch
Start your server with cds watch, and note that the @agent-annotated service gets served with an additional endpoint for the A2A protocol:
cds watch[cds] - serving CatalogService {
at: [ ..., '/a2a/browse' ]
...
}Automatic Config
In development profile, the plugin uses the pre-configured cds.requires.llm: auto config option, which automatically fetches required/missing credentials from given local installations of Claude Code or OpenCode, if any. This allows us to work with zero additional configuration.
You can see the effects of this in the server logs when starting your CAP application with cds watch:
[agents] - cds.connect.to 'llm' with: {
kind: 'anthropic',
model: 'claude-sonnet-4-6',
credentials: {
anthropicApiUrl: 'http://localhost:4711/anthropic/',
apiKey: '***'
}
}Switch on DEBUG output with cds watch to see detailed logs for the agent and LLM interactions, including something as shown below:
DEBUG=agents cds watch[agents] - Loaded config from ~/.claude/settings.json : {
anthropicApiUrl: 'http://localhost:4711/anthropic/',
model: 'claude-sonnet-4-6',
apiKey: '***'
}Learn more about configuring LLMs below.
Using Chat Preview Alpha
For local development, the plugin serves a rudimentary experimental chat preview at http://localhost:4004/a2a/browse/preview/.

Markdown-Based Agents
In addition you can further customize the agent by providing a Markdown-based agent definition, as described in the Markdown-Based Agents section.
Markdown-Based Agents
To define an agent's identity, behaviour, and skills explicitly, add a sibling directory matching the slugified service name. When present, it replaces the default agentification: instead of the auto-generated ReAct agent, the plugin auto-builds the agent from the directory at startup — no JavaScript handler required.
srv/
├─ travel-agent/.cds
└─ catalog-agent/ ← matches the slugified service name
│. AGENTS.md ← agent identity + behaviour
└─ skills/
└─ book-purchase/
└─ SKILL.md ← workflow + examplesAGENTS.md defines who the agent is. The frontmatter populates the agent card; the body is the agent's system prompt:
---
name: catalog-agent
version: "1.0.0"
description: >
Bookshop assistant for placing book orders on behalf of the user.
---
# Catalog Agent
## Identity
You are the **Catalog Agent**, a helpful assistant for the capire bookshop.
...Configuration
cds.requires.llm
The LLM used by an agent is configured via cds.requires.llm. You can provide a kind as with any required service.
cds:
requires:
llm:
kind: aicore
model: anthropic--claude-4.6-sonnet"cds": {
"requires": {
"llm": {
"kind": "aicore",
"model": "anthropic--claude-4.6-sonnet"
}
}
}| Kind | Description |
|---|---|
aicore | The default for production and hybrid, connects to SAP AI Core |
auto | The default for development, using local Claude or OpenCode configuration |
mock | A pure mock for development, provides dummy responses when called |
See SAP AI Core → Create a Service Instance for how to create an instance.vite
Automatically Fetching Credentials
In development profile, with the pre-configured auto kind, the plugin tries to fetch missing credentials from local installation of Claude Code or OpenCode. This allows you to work with local LLM instances without providing any additional config at all.
Advanced
The following capabilities are experimental and documented separately. Their public surface may change.
- Connectivity — destination-based connectivity,
AICORE_SERVICE_KEY/ANTHROPIC_API_KEY, and theanthropickind - Configuration — using multiple models, global and per-service settings, file I/O, and push notifications
- Quota Enforcement — configurable rate limits and resource quotas
- Audit Logging — immutable audit trail of agent decisions and tool usage
- Data Privacy — deletion of message history
- Telemetry — OpenTelemetry metrics, tracing, and MLflow export
- Content Filter — SAP AI Core content filtering and prompt injection shielding