-
Notifications
You must be signed in to change notification settings - Fork 1
Hook Development
The sap-dev AI Skill supports implicit extensibility through Aspect Hooks.
An Aspect represents a specific metadata perspective, sub-component, or textual representation of an SAP development object (such as short description texts or translation keys) that is fetched or deployed separately from the core object source code. By extracting these properties as scoped structured files, agents can edit them cleanly without downloading or editing the entire main object.
Hooks are project-local scripts (Python, Node.js, PowerShell, etc.) residing under the hooks/ directory in your workspace. The standard showcase reference is the fugr-descriptions hook package (managing Function Module short texts), available in the repository stud0709/sap-dev-release under ./hooks/fugr-descriptions/.
Unlike plugins which are called explicitly by the agent, hooks are implicitly intercepted by the sap-bridge daemon when standard tool handlers (sap_fetch or sap_push) are invoked for matching object types and aspects.
Hooks live by default under the hooks/ directory at the root of your active workspace.
Tip
The hooks folder location is fully configurable via the hooks_directory workspace setting, which can be modified under the Extensibility tab of the Web Dashboard.
your-workspace/
├── .sap_credentials.json <-- Secured project vault (contains signing key)
├── hooks/
│ └── fugr-descriptions/ <-- Hook package directory
│ ├── sap-dev-plugin.json <-- Hook metadata descriptor
│ ├── fetch.py <-- Script called during sap_fetch
│ ├── push.py # Script called during sap_push
│ └── .sap-dev.sig # Cryptographic verification signature
└── src/
└── NPL-001/
└── fugr/
└── z_my_group.descriptions.txt <-- Staged aspect file
-
Tool Interception: The agent calls
sap_fetchorsap_pushfor an aspect. -
Hook Matching: The daemon reads each hook package's
sap-dev-plugin.jsonto match the target object type and aspect. -
Execution: The daemon launches the hook script (
fetch.pyorpush.py) as a child process and pipes a JSON configuration block containing workspace metadata and active loopback tokens directly to the script'sstdin. -
Processing & Callback: The script executes, using the loopback endpoints (
/api/guarded/rpc,/api/guarded/sql) to talk to SAP, and prints the final result block tostdoutto be consumed by the daemon.
The following sequence diagram outlines how the aspect fetch event flow routes through the hook script to stage custom aspects locally:
sequenceDiagram
autonumber
actor Agent as AI Agent
participant Daemon as sap-bridge Daemon
participant Hook as Hook Process (Python)
participant SAP as SAP Backend
Agent->>Daemon: Call sap_fetch (Aspect: descriptions)
Note over Daemon: Match hook by aspects/can_handle<br/>Verify signature OR Developer Mode
rect rgba(0, 150, 255, 0.05)
Note over Daemon: Generate ephemeral SAP_BRIDGE_TOKEN
Daemon->>Hook: Launch fetch.py (Pass context JSON on stdin)
Hook->>Daemon: POST /api/guarded/sql (Request active descriptions)
Daemon->>SAP: Query tables via active session
SAP-->>Daemon: Return raw database rows
Daemon-->>Hook: Return JSON rows
Hook-->>Daemon: Exit (Write final structured content JSON to stdout)
end
Daemon-->>Agent: Stage result in workspace file
For details on enabling hooks, calculating HMAC-SHA256 signatures (.sap-dev.sig), and toggling Developer Mode, please refer to the high-level Extensibility portal page.
The bridge daemon invokes hooks at specific lifecycle intervals during fetch and push operations. The hook script or package directory is named after the target event:
| Event Name | Invocation Point / Trigger | Expected Behavior / Purpose |
|---|---|---|
fetch |
Standard sap_fetch (aspect extraction) |
Intercept fetch to return staged file content. |
push |
Standard sap_push (aspect deployment) |
Intercept push to deploy edited files to SAP. |
pre_fetch |
Before daemon fetches raw object from SAP | Perform pre-fetch tasks (e.g. status checks, environment preparation). |
post_fetch |
After daemon successfully fetches raw object | Modify, format, or process fetched data before storing it. |
check_permission |
Before write operations start | Execute custom backend security or authorization rules. |
pre_push |
Before data is sent to the SAP backend | Validate, lint, or run static checks (e.g., abaplint). |
custom_transport |
During transport request selection | Resolve or generate transport request numbers dynamically. |
resolve-object |
Inside Object Guard evaluation | Rewrite/map custom sub-objects to their parent container objects. |
If your hook requires multiple steps (e.g., linting, then static validation, then pre-push compilation), you can organize it as a script pipeline chain instead of a single script:
-
Chaining Directory Structure:
Instead of creating a file named
<event_name>.<ext>(likepre_push.py), create a directory named after the event:hooks/my-hook-package/ └── pre_push/ ├── 01_lint.py └── 02_check_style.js - Sequential Execution: The daemon automatically scans all files in the subdirectory, sorts them alphanumerically, and executes them in sequence.
-
Pipeline Data Flow:
The final script in the chain must print the expected JSON result block matching the execution contract.Loadinggraph LR input["Initial Input JSON"] --> s1["01_lint.py"] s1 -->|"stdout"| pipe["(Piped in memory)"] pipe -->|"stdin"| s2["02_check_style.js"] s2 --> output["Final Output JSON"]
The FUGR Descriptions hook serves as our standard reference implementation:
-
Purpose: Manages the short description texts of Function Modules within a Function Group (stored in standard SAP table
TFTIT). -
Aspect Name:
"descriptions" -
Fetch Lifecycle: Executes
fetch.py, which queriesTFDIRto locate the group's module list, extracts active descriptions fromTFTITvia loopback SQL, and formats them into a local staged JSON text file. -
Push Lifecycle: Executes
push.py, which sends the edited JSON mapping to the customsave_fugr_descriptionsRPC endpoint onZCL_SAP_DEV_RPC_EXTto deploy the new texts.
For full JSON descriptors, input/output schemas, environment parameters, and code blocks, refer to the developer documentation:
👉 HOOK_GUIDE.md inside the skill references directory.