agentleFS
abap2UI5abap2UI5/app-template/.claude/skills/build-an-app/SKILL.md

build-an-app

Skill1 starsChanged 12 days agoMITView on GitHub

How to build an application WITH abap2UI5 (as opposed to changing the framework) - app class template, lifecycle, view building via z2ui5_cl_ui5_view_builder, data binding, events, popups, navigation, validation tooling. Use when writing or reviewing a z2ui5_if_app class, demo app, sample or any consumer application code.

2 other projects use a version of this.

Adopted by

Most recently taken up by

  • Other versions2 projects use a version of this.

    Word for word · 0

    None found.

    Edited · 0

    None found.

    Wrote their own version · 2

    1. BuilderIO/agent-native★ 7.6ksame name
    2. aazirani/flutter_agentify★ 0same name

    How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.

  • In this repository5 other files it gives its agents.

The file

We split this skill into the rules it gives an agent

3 rules. About 0 are common, 1 is distinctive, and 2 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈1

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 2

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Never feed abap_true into v raw — it serializes as X.

    line 84
  2. Distinctive:

    Never write a model path as a text literal.

    line 103
  3. Very specific:

    Before you finish, run the abap-check skill over what you wrote — it is the companion to this one and catches what a green lint does not: …

    line 128

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md
<!-- GENERATED by scripts/generate-skills.mjs in abap2UI5/app-template from .claude/skills/build-an-app/SKILL.md in abap2UI5/abap2UI5 - "this repository" in the text is the framework's. Do not edit; regenerate. -->

Building an abap2UI5 app

Read AGENTS.md in this repository — everything from "1. The model in one paragraph" down is the framework's complete self-contained guide (template, lifecycle, builder verbs, binding rules, events, popups, navigation, portability rules, validation tooling). This skill is the trigger and the checklist; the guide is the content.

Before writing one from scratch, ask whether it exists. abap2UI5/samples holds 150 working apps, each linted, rendered and downported to three releases — a value help, a tree, navigation between two apps, a dynamic table typed at runtime. Reading one beats reproducing it, and beats any snippet: the sample is gated, a snippet is a copy somebody has to keep in step.

  • With the MCP server: the examples tool queries that catalogue (examples { query: "value help f4" }) and hands back the class to read. Its neighbour capabilities answers the other question — whether a UI5 control can be expressed at all — out of samples-controls' 622 ports.
  • Without it: SAMPLES.md is the same catalogue as a page.

Quick orientation while it loads:

  • One ABAP class implements z2ui5_if_app; main( client ) runs once per roundtrip — dispatch with check_on_init( ) / check_on_event( ) / check_on_navigated( ).
  • The check_on_navigated( ) branch is part of the dispatcher, not an option. check_on_init( ) is "this app instance never ran", not "the app starts": it stays false when a called app hands control back (nav_app_leave, any z2ui5_cl_pop_* value help — those run over nav_app_call too) and when a bookmarked state is restored. Those roundtrips fire check_on_navigated( ) alone, and a branch that does not re-run view_display( ) there leaves the previous screen standing with no error anywhere. Apps built without it work perfectly until the day someone calls them from a navigation — the linter's missing-view-display-on-navigated covers the branch that exists but never displays.
  • …and all of it is ONE IF/ELSEIF chain, so exactly one arm runs per roundtrip. check_on_init( ) being true implies check_on_navigated( ) is true — every path to a first main( ) sets the flag (factory_first_start, fresh start and draft restore alike, factory_system_startup, prepare_app_stack for call and leave). On that first roundtrip the init arm wins and the navigated arm is skipped, so the init arm seeds AND displays: IF check_on_init( ). model_init( ). view_display( ). ELSEIF check_on_navigated( ). view_display( ). ELSEIF check_on_event( ). on_event( ). ENDIF. — the guide's template. Carry the init arm only for what must happen ONCE — model_init( ), or a couple of control-state flags seeded inline; an app with nothing to seed drops it and starts the chain at check_on_navigated( ). An init arm that ONLY displays decides nothing (redundant-init-display), and neither does IF check_on_init( ) OR check_on_navigated( )..
  • Never split the chain. No IF check_on_init( ). … ENDIF. block that seeds followed by an IF check_on_navigated( ). block that displays, and no lifecycle IF nested in another arm: the flags overlap (init implies navigated, a returning app can bring an event), so separate blocks run more than one arm per roundtrip, and the linter reports them as separate-lifecycle-ifs. Only a guard block that leaves the method (… RETURN. ENDIF.) is exempt.
  • Ask the lifecycle with the call itself, never with IS INITIAL. The three check_on_*( ) methods return abap_bool, so the branch is IF client->check_on_init( ). — a predicative call, the way the sample corpus and the documentation on z2ui5_if_client write it. Compounds keep the shape (ELSEIF client->check_on_event( `LOCK` )., IF client->check_on_navigated( ) AND mv_ready = abap_true.) — but never IF client->check_on_init( ) OR client->check_on_navigated( )., whose OR is redundant, see the display-branch rule above. IS NOT INITIAL asks a boolean whether it is EMPTY, which is what that question means for a string, and it is one more dialect an app author has to read. Only a NEGATIVE branch is spelled out, as = abap_false: the corpus has no negated predicative form. Every other abap_bool follows the same rule: IF mv_flag = abap_false. and DELETE lt_x WHERE flag = abap_false., never IS INITIAL on either.
  • PUBLIC attributes = serialized, browser-visible state. Bound data only; everything else PROTECTED.
  • Build views with z2ui5_cl_ui5_view_builder (ele/tag/a/end/stringify). The legacy z2ui5_cl_xml_view is frozen — never use it in new code.
  • A boolean from an ABAP variable goes through a( )'s b parameter: )->a( n = `editable` b = mv_edit_mode ) renders true/false. Never feed abap_true into v raw — it serializes as X.
  • The chain's layout is strict, not taste — read the view-chain-layout skill before writing one. It is the single source of the rules, identical in this repository and both sample repositories, and it is machine-checked (the linter's chain-house-layout rule: npm run check:abap2ui5 reports, npm run fix applies). In short: one call per line, four spaces per level, the ) rides with the arrow ()->), end( ) alone in the column of the ele( ) it closes, a control's a( )s one level in with their v = aligned. Blank lines only in the single-chain shape, where a blank opens a block and there are exactly two.
  • Which factory( ) shape you use is decided by the chain shape, not by preference: a view split into a statement per subtree hangs the chain off the factory( ) (one statement, not two) so the variable holds the mvc:View; a view written as one chain may take a factory( ). of its own. A standalone factory( ). with the split shape is broken — the variable then holds the root and the next statement adds a second root beside the mvc:View. See the skill.
  • Bind with client->_bind( var ) (also for display-only; _bind_edit is obsolete). Row-template fields bind as `{UPPERCASE}`. Never write a model path as a text literal.
  • Events: client->_event( NAME ), dispatch via CASE client->get_event( ).; client-resolved args are $-prefixed. An arg that carries data (user text, a foreign key) goes on a wire with s_ctrl-check_arg_literal = abap_true — otherwise a value starting with $ or { is evaluated by the client instead of passed (guide, section 5). Changed bound data is pushed automatically — view_model_update( ) is obsolete, does nothing, and gets deleted whenever you touch an app.
  • A per-keystroke wire (liveChange, liveSearch, sliderChange) sets s_ctrl-check_queue_last: an event fired while a roundtrip is in flight is dropped by default, so typing under a running roundtrip lost its last keystrokes and the backend sat one value behind the control. The flag keeps the LAST firing and sends it once the response has landed — one roundtrip at a time, order preserved. There is no flag for firing them all at once, and a timer tick or poll needs none: START_TIMER has its own slot and waits out the roundtrip in flight.
  • Business logic is computed in ABAP, never in frontend formatters (thin frontend). UI5 1.71 is the compatibility floor — check "available since".
  • The app checks its own authorizations at the top of main.
  • Validate with the abap2UI5-linter (npm run check:abap2ui5, or npm run check:abap2ui5:fast without the render gate); iterate without a SAP system via the mcp-server (deploy_app → build_backend → run_app, then interact_app to drive the event branch and run_unit_tests for the class's own test double — chapter 9 of the guide lists the tooling).
  • Before you finish, run the abap-check skill over what you wrote — it is the companion to this one and catches what a green lint does not: abapGit round-trip diffs, activation errors (class_constructor visibility, LOCAL FRIENDS), SLIN/ATC traps and runtime breakage that only shows on a real system.
  • The API contract is src/02/z2ui5_if_client.intf.abap in abap2UI5/abap2UI5 — when unsure about a method or a cs_event action, read it there; the follow_up_action abapdoc documents the full frontend-action catalog.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.