Skip to content

sap-devs Content Guide

This guide covers how to add, update, and translate content for the sap-devs CLI — packs, adapters, and profiles.


Overview: The Content Layer System

Content is loaded from up to four sources, merged by id with later layers overriding earlier ones:

LayerLocationPurpose
Official~/.cache/sap-devs/official/content/ (Linux), ~/Library/Caches/sap-devs/official/content/ (macOS), or %LOCALAPPDATA%/sap-devs/cache/official/content/ (Windows)Fetched from the official repo via sap-devs sync
Company~/.cache/sap-devs/company/content/ (Linux), ~/Library/Caches/sap-devs/company/content/ (macOS), or %LOCALAPPDATA%/sap-devs/cache/company/content/ (Windows)Optional; configured via sap-devs config company <url>
User~/.local/share/sap-devs/ (Linux), ~/Library/Application Support/sap-devs/data/ (macOS), %LOCALAPPDATA%/sap-devs/data/ (Windows)Per-user overrides
Project.sap-devs/ in the current working directoryPer-project overrides

If two layers define a pack with the same id, the later layer wins completely — unless the later pack has additive: true, in which case it augments the earlier pack rather than replacing it. See Additive Layers.


Pack Structure

Each pack lives in content/packs/<pack-id>/. All files are optional except pack.yaml.

content/packs/cap/
├── pack.yaml          # Pack metadata
├── context.md         # AI context text (English)
├── context.de.md      # German AI context text (optional)
├── tips.md            # Tips (English)
├── tips.de.md         # German tips (optional)
├── tools.yaml         # Tool version requirements
├── resources.yaml     # Curated resource links
├── mcp.yaml           # MCP server definitions
├── samples.yaml       # Canonical code samples
├── tutorials.yaml     # Curated tutorial references
├── learning.yaml      # Curated learning journey references
├── discovery.yaml     # Discovery Center mission/service/guidance references
└── paths.yaml         # Curated learning paths

pack.yaml

yaml
id: cap                          # unique slug — used as the merge key
name: SAP Cloud Application Programming Model
description: Node.js and Java framework for building cloud-native business applications on BTP
tags: [cloud, btp, nodejs, java, odata, cds]
profiles: [cap-developer, btp-developer]   # informational metadata only — see note below
weight: 100                      # default weight; profiles can override this per-pack
overlaps: []                     # optional — see note below
locales:
  de:
    name: SAP Cloud Application Programming Model
    description: Node.js- und Java-Framework für Cloud-native Business-Anwendungen auf BTP
versions:
  "@sap/cds": "9.8.0"             # optional — latest known versions for staleness checks
  "@sap/cds-dk": "9.8.0"

Note: weight sets the default priority for this pack. Individual profiles can override it in their packs list (see Profiles below).

Note: The profiles field is informational metadata only. A pack is only active when it is explicitly listed in a profile's packs list. Adding a pack id to profiles here does not automatically include it in that profile.

Note: overlaps is a list of pack IDs whose content subsumes this pack's content. If any listed pack is present at a higher weight during injection, this pack is automatically dropped to avoid redundant context. Semantics: "if cap is already included, my content adds nothing new — drop me." Only the lower-weight pack carries the declaration. Omit the field (or leave it empty) if no overlap exists.

Note: base (optional bool, default false) — when true, this pack is a base pack: it is auto-injected into every profile regardless of the profiles field, always rendered first (before profile-specific packs), and exempt from adapter byte-budget trimming and overlap deduplication. The profiles field is irrelevant for base packs and should be omitted. Authoring contract: keep base pack content minimal — base packs consume tokens in every context window. Note: declaring overlaps: [base] on a non-base pack has no effect (the base pack is separated before the deduplication pass runs). This is a known limitation.

Note: additive (optional bool, default false) — when true, this pack augments the lower-layer pack with the same id rather than replacing it. Only valid in company, user, or project layers. See Additive Layers.

Note: additive_position (optional string "before" | "after", default "after") — controls where additive content is inserted relative to the base pack's content. Only meaningful when additive: true.

Note: versions (optional map of string → string) — latest known versions for dependency staleness checks, e.g. "@sap/cds": "9.8.0". Used by sap-devs doctor and sap-devs inject to flag outdated project dependencies. When multiple packs declare the same key, the highest-weight pack wins.

context.md

Free-form Markdown injected as AI context into tools. No special syntax. May be long-form reference material, code examples, or conventions.

context.<lang>.md

Localised version of context.md for language <lang> (e.g. context.de.md). Falls back to context.md if absent for the active language.

tips.md

H2-delimited tips. Each tip:

markdown
## Use cds watch for local development
Tags: cap,nodejs
Run `cds watch` instead of `node server.js` — it reloads on every file change.

## Define managed entities for audit fields
Tags: cap,cds
Add `: managed` to your entities to get createdAt, createdBy, modifiedAt, modifiedBy for free.
  • ## <Title> — required
  • Tags: tag1,tag2 — optional, one line immediately after the heading
  • Body — tip content, may be multi-line Markdown

tips.<lang>.md

Localised version of tips.md. Same format.

tools.yaml

yaml
- id: nodejs
  name: Node.js
  required: ">=18.0.0"          # semver constraint
  detect:
    command: "node --version"
    pattern: "v(\\d+\\.\\d+\\.\\d+)"   # regex capturing the version string
  install:
    windows: "winget install OpenJS.NodeJS.LTS"
    macos: "brew install node@20"
    linux: "nvm install 20"
  docs: "https://nodejs.org"

- id: cds-dk
  name: SAP CDS CLI
  required: ">=7.0.0"
  detect:
    command: "cds --version"
    pattern: "@sap/cds: (\\d+\\.\\d+\\.\\d+)"
  install:
    all: "npm install -g @sap/cds-dk"   # "all" key applies to every platform
  docs: "https://cap.cloud.sap"

resources.yaml

yaml
- id: cap/docs-official           # <pack-id>/<slug>
  title: CAP Documentation
  url: https://cap.cloud.sap/docs
  type: official-docs             # official-docs | sample | community | tutorial | blog
  tags: [reference, getting-started]

mcp.yaml

MCP server definitions for the pack. The file is a YAML list of MCPServer entries.

yaml
- id: cap-mcp                        # unique slug within the pack
  name: CAP MCP Server
  description: MCP server for SAP CAP development
  install:
    command: "npx"                   # executable to run
    args: ["-y", "@sap/cap-mcp"]    # arguments passed to the command
  hosts: [claude-code, cursor]       # AI tools that should register this server

Fields:

  • id — unique identifier (combined with PackID at load time)
  • name — human-readable display name
  • description — short description shown in sap-devs mcp list
  • install.command — executable to run (e.g. npx, node, python)
  • install.args — list of arguments passed to the command
  • hosts — list of AI tool IDs that should register this server (used by sap-devs mcp install)

Note: All existing mcp.yaml files in official packs are currently stubs pending Plan 2 implementation.

paths.yaml

Curated learning paths that combine tutorials, learning journeys, and Discovery Center missions into ordered sequences. Used by sap-devs learn path list/show/open.

yaml
paths:
  - id: cap-getting-started              # unique path identifier (kebab-case)
    name: Getting Started with CAP
    level: beginner                      # optional: beginner, intermediate, advanced
    description: Build your first CAP application from project creation to deployment
    steps:
      - type: journey                    # journey, tutorial, or mission
        slug: developing-with-sap-cloud-application-programming-model
      - type: tutorial
        slug: cap-getting-started
      - type: mission
        slug: "4327"                     # mission IDs are stringified integers

Fields per path:

  • id — unique identifier across all packs
  • name — human-readable path name
  • description — short description shown in path show
  • level — optional experience level filter (beginner, intermediate, advanced)
  • steps — ordered list of content references; each has a type and slug

Packs without a paths.yaml get auto-generated paths from their featured content (grouped by level, minimum 2 items per level).


Adapters

Adapters define how to push content into a specific AI tool. Files live in content/adapters/<tool-id>.yaml.

yaml
id: claude-code
name: Claude Code
type: file-inject                 # file-inject | clipboard-export | mcp-wire
max_tokens: 0                     # optional — token budget for this adapter; 0 = unconstrained
targets:
  - scope: global                 # global (user-level) or project (current dir)
    path: "~/.claude/CLAUDE.md"
    mode: replace-section         # replace-section | append
    section: "SAP Developer Context"
  - scope: project
    path: "./CLAUDE.md"
    mode: replace-section
    section: "SAP Developer Context"
detect:
  - command: "claude --version"   # run this; if it exits 0, tool is present
  - path: "~/.claude"             # or check if this path exists
mcp_config:
  path: "~/.claude/settings.json"
  format: json
  key: "mcpServers"

Modes:

  • replace-section — replaces the named fenced section. The injected block is wrapped with <!-- sap-devs:start:SAP Developer Context --> and <!-- sap-devs:end:SAP Developer Context --> markers.
  • append — defined in the adapter schema but not yet implemented; using it causes a runtime error. Do not use until engine support is added.

Types:

  • file-inject — writes context to a config file. Used by sap-devs inject.
  • clipboard-export — copies context to clipboard (global scope only).
  • mcp-wire — registers MCP servers in the tool's JSON config. Used by sap-devs mcp install, not inject.

max_tokens: When set to a positive integer, the inject engine trims packs to fit within approximately max_tokens × 4 bytes of rendered context before writing to this adapter. Higher-weight packs are always included first; the engine stops at the first pack that would exceed the budget. Zero (the default) means unconstrained — all packs are included. Use sap-devs inject --stats --dry-run to see how many tokens each adapter is currently using.


Profiles

Profiles tag which packs belong to a developer persona. Files live in content/profiles/<profile-id>.yaml.

yaml
id: cap-developer
name: CAP Developer
description: Building cloud-native apps with SAP CAP on BTP
packs:
  - id: cap
    weight: 100       # higher weight = appears earlier in rendered context
  - id: btp-core
    weight: 80
  - id: abap
    weight: 10
tip_tags: [cap, nodejs, odata, cds, btp]   # tips with these tags are preferred for this profile

ApplyWeights() reorders packs so higher-weight packs appear first in the rendered context injected into AI tools.

Built-in Profiles

Two profiles are built into the CLI and require no YAML file on disk:

ProfileBehaviour
allIncludes every pack from every content layer, sorted by pack weight. Use for development or when working across multiple SAP domains.
minimalIncludes base packs only — no technology-specific content. Use for cost-conscious setups or AI tools with tight token budgets.

Both profiles appear in sap-devs profile list and can be set with sap-devs profile set all or sap-devs profile set minimal.

Reserved IDs: The IDs all and minimal are reserved. Any file named all.yaml or minimal.yaml in a content layer is silently ignored — the built-in definition always takes precedence.


Creating a New Pack

  1. Create the directory:

    bash
    mkdir content/packs/<new-id>
  2. Write pack.yaml with a unique id:

    yaml
    id: my-pack
    name: My Pack
    description: What this pack covers
    tags: [tag1, tag2]
    profiles: [cap-developer]   # or whichever profile(s) should include it
  3. Add content files as needed (context.md, tips.md, tools.yaml, resources.yaml). All are optional.

  4. Reference the pack in at least one profile:

    yaml
    # content/profiles/cap-developer.yaml
    packs:
      - id: my-pack
        weight: 50
  5. Test with dev mode:

    bash
    SAP_DEVS_DEV=1 go run . inject --dry-run

    Verify the new context appears in the output.

Base packs: If your pack should be auto-injected into every profile (e.g. shared ecosystem links), add base: true and omit the profiles field. Keep base pack content short — it is included in every context window regardless of budget constraints.


Updating Existing Content

Edit the file in the relevant layer. The official layer is under content/packs/ in this repo. To override official content without modifying it:

  • User override: Copy the pack to ~/.local/share/sap-devs/packs/<id>/ (Linux) and edit there.
  • Project override: Copy to .sap-devs/packs/<id>/ in the project directory.

The override pack must use the same id as the official pack. The later layer wins.


Translation Guide

How Language Resolution Works

The active language is resolved in this order:

  1. sap-devs config set language <tag> — explicit config setting
  2. LANG environment variable (e.g. de_AT.UTF-8de)
  3. LC_ALL environment variable
  4. Fallback: en

Region and encoding suffixes are stripped: de_AT.UTF-8de. If the resolved tag has no catalog, it falls back to en.

Translating Pack Content Files

Add localised content files alongside the base files:

content/packs/cap/
├── context.md         # base (English)
├── context.de.md      # German translation
├── tips.md            # base (English)
└── tips.de.md         # German translation

The loader automatically picks the locale-specific file when the active language matches. Falls back to the base file if the locale file is absent.

Translating Pack Metadata

Add a locales block to pack.yaml:

yaml
locales:
  de:
    name: SAP Cloud Application Programming Model
    description: Node.js- und Java-Framework für Cloud-native Business-Anwendungen auf BTP
  fr:
    name: SAP Cloud Application Programming Model
    description: Framework Node.js et Java pour applications cloud natives sur BTP

Translating CLI Strings

CLI strings live in internal/i18n/catalogs/<lang>.json. Copy en.json as a starting point — any missing keys fall back to English automatically.

bash
cp internal/i18n/catalogs/en.json internal/i18n/catalogs/fr.json
# Edit fr.json with French translations

Key naming convention: <command>.<subcommand>.<string_name>

json
{
  "inject.short": "Pousser le contexte SAP dans vos outils IA",
  "inject.done": "Contexte SAP injecté (portée {{.Scope}})."
}

Values may be plain strings or Go text/template expressions (e.g. &#123;&#123;.Scope&#125;&#125;).

In Go code, strings are looked up with:

  • i18n.T(lang, key) — plain string
  • i18n.Tf(lang, key, data) — template string, where data is map[string]any
  • Pass i18n.ActiveLang as the lang argument

Adding a New Language End-to-End

  1. Create the CLI catalog:

    bash
    cp internal/i18n/catalogs/en.json internal/i18n/catalogs/<lang>.json

    Translate values. Leave any untranslated keys as-is (they fall back to English).

  2. Add localised content files to each pack you want to translate:

    bash
    # For each pack:
    cp content/packs/<id>/context.md content/packs/<id>/context.<lang>.md
    cp content/packs/<id>/tips.md content/packs/<id>/tips.<lang>.md
    # Edit the new files with translations
  3. Add locales blocks to each pack.yaml you translated.

  4. Test:

    bash
    sap-devs config set language <lang>
    SAP_DEVS_DEV=1 go run . inject --dry-run
    SAP_DEVS_DEV=1 go run . tip

    Verify translated strings appear in output.

  5. Reset language when done testing:

    bash
    sap-devs config set language en