AppApptypeAn application you deploy and use, installed into a system or loaded into an application as a component, rather than a library whose functions you call.See every one →What this type is →independently maintainedindependently maintainedoriginPublished by one person or a small company outside SAP. Says nothing about quality; the readings say that.See every one →

open-steamgate

An ABAP application server you clone and run on your own machine: transpiled ABAP serving classic /IWBEP/ OData v2 to Fiori over a local database, with no SAP system attached.

Classic Gateway work needs a system to run on: a SEGW project, a _MPC_EXT and _DPC_EXT pair, and a gateway that calls them. This cross-compiles that ABAP (Gateway classes, CDS views, AMDP methods, reports) and runs it against a local database, serving OData to Fiori elements, letting Eclipse edit it over ADT and answering SAP GUI on the DIAG port. abaplint and its transpiler turn the ABAP into something that runs, the /IWBEP/ interfaces come from open-abap-odata, and Open SQL goes through an eleven-method seam onto sql.js, SQLite, DuckDB, PostgreSQL or SAP HANA. It is the layer under an ERP rather than an ERP: the language runtime, the dictionary, Open SQL, the ICF service tree, the OData gateway, CDS, AMDP, the LUW, screens, jobs, daemons. A system is a directory of files, the ABAP a repository and the tables abapGit TABU JSON, so a whole one can be branched and thrown away; it starts from a browser page, a Docker compose stack, one Bun binary, a VS Code extension or npm start in the clone.

Facts

Last pushLicenceMIT

Where it sits

Lives in
Provides
ODataABAPODatacapabilityExposing data and operations through OData, including the service model, metadata and protocol versions clients require. Version differences affect which clients can consume a service and which query features they can use.Local developmentABAPLocal developmentcapabilityRunning the whole stack on a laptop against real bindings — the service, the UI and the routing in front of it — without deploying to see a change.Unit testingABAPUnit testingcapabilityTesting application logic without a running business process — and the test doubles that make dependencies on the database and on framework services tractable.
Serves
Requires
@abaplint/transpiler@abaplint/transpilerartifactturns the ABAP in the tree into something that runs; npm run transpiler:pin builds the pinned transpiler, CLI, runtime and core for a warm local build
Optional
SQLiteSQLiteoutside the atlasthe local database Open SQL runs against in the default configuration, as sql.js in the browser bundle or a SQLite file with WAL on NodePostgreSQLPostgreSQLoutside the atlasthe database behind the eleven-method seam when PostgreSQL is chosen; a release carries a postgres.yml compose file that starts oneSAP HANASAP HANAartifactthe data layer when an AMDP body is to run where it belongs and sy-dbsys is to read HDB; the maintainer records it as an option and never the default, and HANA Express is the image the compose file startsDockerDockeroutside the atlasruns the published image and the compose stacks, one per database; the arm64 image also runs on a Raspberry Pi 4abapGitabapGitartifactthe serialised form code moves in and out through; npm run segw:zip builds an abapGit offline repository to reach a real system

Who is behind it

Alice V.Alice V.PersonMaintains this
In the atlas: maintains 6, contributes to 12
@oisee
maintainerCodexPersonContributes to this
In the atlas: contributes to 1
@codex
1 contributor

Before choosing this

Conditions

PracticalFunctional boundary

Not a system to run a business application on: there is no business application in it, and what it implements of the language, the dictionary and Gateway is a stated subset of each. It is a clean-room reimplementation of the /IWBEP/ interfaces that bundles no SAP source and no standard DDIC, so a service that reads standard objects has nothing to read, and ANORMALIES.md records every place the runtime differs from SAP before any workaround is written.

What it declares

Every artifact

Type
App
Origin
Independently maintained
Runtime
Node.js

As an app

Where it runs
On your own server or machine
Distributed through
Container imageabapGitBinary download

For OData

Protocols
odata-v2

Connections11

open-steamgate connectionsopen-steamgatePROVIDES→ provides3provides stated Runs the ABAP side on the developer's own machine — the ICF tree, the Gateway, the apps and the database as one unit started from a clone, a container, a single binary or a browser page — and lets [Eclipse ADT](artifact:sap-adt-eclipse) and vsp edit the source in it as they would a system, with every change landing on the git tree as abapGit files. oisee/open-steamgate — README, What it is: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, ADT façade: https://github.com/oisee/open-steamgateLocal developmentprovides stated Serves classic code-based SEGW services from a local runtime: the URL parser, `$filter` mapped to SELECT-OPTIONS, `$batch` with changesets, navigation, `$expand`, deep insert, function imports, value helps, MERGE and media entities, all of it ABAP behind one `if_http_extension`. oisee/open-steamgate — repository description: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, Where it stands: https://github.com/oisee/open-steamgateODataprovides stated Runs ABAP Unit for a folder of `*.clas.abap` and `*.clas.testclasses.abap` outside any system, on either of its two runtimes — transpiled to JavaScript on Node, or compiled to Go — and reports per class, test class and method; the same tests on both are compared method by method. oisee/open-steamgate — README, Generated classes in CI: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, The whole system in Go: https://github.com/oisee/open-steamgateUnit testingNEEDS→ connects to2connects to stated Eclipse ADT and vsp treat it as a system — package tree, edit, save, activate, ABAP Unit, F8 preview, create and delete — over HTTPS as a Cloud Project and over RFC as a Custom Application Server through the built-in JavaScript bridge oisee/open-steamgate — README, ADT façade: https://github.com/oisee/open-steamgateABAP Development Tools for Eclipseconnects to stated If: `STG_DB=hana` selects HANA as the backend Open SQL and AMDP bodies run against a real HANA through the eleven-method database seam, over the npm driver `hdb` open-steamgate — docs/db-backends.md, the HANA client: https://raw.githubusercontent.com/oisee/open-steamgate/main/docs/db-backends.md open-steamgate — docs/db-backends.md, what a remote database costs: https://raw.githubusercontent.com/oisee/open-steamgate/main/docs/db-backends.mdSAP HANAif→ needs1needs stated turns the ABAP in the tree into something that runs; `npm run transpiler:pin` builds the pinned transpiler, CLI, runtime and core for a warm local build oisee/open-steamgate — README, Thanks: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, warm local development: https://github.com/oisee/open-steamgate@abaplint/transpiler→ optionally needs5optionally needs stated If: objects are moved between this and a real ABAP system the serialised form code moves in and out through; `npm run segw:zip` builds an abapGit offline repository to reach a real system oisee/open-steamgate — README, Thanks: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, Build on it: https://github.com/oisee/open-steamgateabapGitifoptionally needs stated If: it is started as a container rather than from the clone, a binary or the browser build runs the published image and the compose stacks, one per database; the arm64 image also runs on a Raspberry Pi 4 oisee/open-steamgate — README, the ways to run it: https://github.com/oisee/open-steamgateDockerifoptionally needs stated If: the PostgreSQL backend is chosen the database behind the eleven-method seam when PostgreSQL is chosen; a release carries a `postgres.yml` compose file that starts one oisee/open-steamgate — README, Databases: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, TL;DR: https://github.com/oisee/open-steamgatePostgreSQLifoptionally needs stated If: `STG_DB=hana` selects HANA as the backend the data layer when an AMDP body is to run where it belongs and `sy-dbsys` is to read HDB; the maintainer records it as an option and never the default, and HANA Express is the image the compose file starts oisee/open-steamgate — README, AMDP and SQLScript: https://github.com/oisee/open-steamgate open-steamgate — docs/db-backends.md, what a remote database costs: https://raw.githubusercontent.com/oisee/open-steamgate/main/docs/db-backends.mdSAP HANAifoptionally needs stated If: the SQLite backend is used, which is the default the local database Open SQL runs against in the default configuration, as sql.js in the browser bundle or a SQLite file with WAL on Node oisee/open-steamgate — repository description: https://github.com/oisee/open-steamgate oisee/open-steamgate — README, Databases: https://github.com/oisee/open-steamgateSQLiteif

Where it sits in your app

Download
Your serverSAP cloudoisee/open-steamgate — README, ADT façade, checked 2026-10-16: “Eclipse ADT and vsp treat OSD as a system: package tree, edit, save, activate, ABAP Unit, F8 preview, create/delete. Every change lands on the git tree as abapGit files. It works over HTTPS (Cloud Project) and over **RFC** (Custom Application Server) through the built-in JavaScript bridge”HTTP, RFC, inboundopen-steamgate — docs/db-backends.md, the HANA client, checked 2026-10-16: “Built 2026-09-18, `tools/hana-client.mjs`, `STG_DB=hana`. **Both suites reach”outboundif `STG_DB=hana` selects HANAas the backenddocumentedrequiresdocumentedmay needif the SQLite backend is used,which is the defaultdocumentedmay needif the PostgreSQL backend ischosendocumentedmay needif it is started as acontainer rather than from theclone, a binary or the browser b…documentedmay needif objects are moved betweenthis and a real ABAP systemSQLite, systemSQLitesystemPostgreSQL, systemPostgreSQLsystemDocker, SoftwareDockerSoftwareopen-steamgate, moduleopen-steamgate@abaplint/transpiler, module@abaplint/transpilerabapGit, moduleabapGitABAP Development Tools for Eclipse, moduleABAP DevelopmentTools for EclipseSAP HANA, service instanceSAP HANA
SAPnot SAP's, or the project's ownstated in the documentdocumented onlyunder a condition

README

quoted from oisee/open-steamgate under MIT, read
oisee/open-steamgate/README.mdOn GitHub

open-steamgate

Open SteamGate: a developer in a steampunk airship cabin, the gateway's arches in the clouds outside

An ABAP application server you can clone.

Part of the steampunk family: vsp (ADT ↔ MCP), abapiti (TypeScript and WASM to ABAP), open-rfc-go (RFC) and open-diag-go (SAP GUI DIAG).

TL;DR — run it

waydo thisthen open
Browser, nownothing to installoisee.github.io/open-steamgate/main/app/flp.html
Dockergit clone https://github.com/oisee/open-steamgate && cd open-steamgate && docker compose -p osd11 -f docker/compose.sqlite.yml up -dhttp://localhost:8011/app/flp.html
PortainerStacks → Add stack → Web editor, paste one YAML block from docs/spin.md (SQLite, DuckDB, PostgreSQL or HANA Express)http://<host>:8011/app/flp.html
One binary (Bun)download osd-linux-x64 / osd-linux-arm64 / osd-darwin-arm64 / osd-darwin-x64 / osd-windows-x64.exe / osd-windows-arm64.exe from Releases, then mv osd-linux-x64 osd && chmod +x osd && ./osd uphttp://localhost:3030/
VS Codeinstall open-steamgate: local ABAP server, or the .vsix from Releases via Extensions: Install from VSIX…; then run osd: Startthe OSD tree in VS Code
Node, from sourcenpm ci && npm run bootstrap && npm start (Node 22.18+ or 24)http://localhost:3030/
Your report as a CLI toolnode tools/gogen/osabap.mjs zmy_report.prog.abap, then tools/gogen/.out/osabap (needs Go 1.26)a native binary, no server (below)

Each release also carries sqlite.yml, duckdb.yml and postgres.yml; start one with docker compose -f sqlite.yml up -d. ./osd doctor checks a downloaded binary.

🎉 gogen compiles itself (self-hosting step 4, 2026-10-20)

gogen, the ABAP-to-Go compiler in this tree, is written in JavaScript. abapiti compiled gogen itself into Go, and that Go-built gogen emits the same Go as gogen on Node, byte for byte, for the reference class. The output builds and passes its unit test:

step4: build=ok run=ok cmp=equal ref=b90648781967b2cf out=b90648781967b2cf
PASS: ZCL_GOGEN_T_RUNTIME/LTCL_RUNTIME/ELAPSED

Measured on 0b925177 in main with abapiti 3115e569. About twenty full runs, about fifteen fixes on each side, Node output unchanged by every one: the story and both SHAs. The trap-by-trap log before it is in docs/self-hosting-step4-traps.md.

What it is

open-steamgate (OSD) cross-compiles real ABAP — _MPC_EXT / _DPC_EXT Gateway classes, CDS views, AMDP methods, reports — and runs it against a local database. It serves OData to Fiori Elements, lets Eclipse edit it over ADT, and answers SAP GUI on the DIAG port. No SAP system is attached.

It is the layer under an ERP, not an ERP. The language runtime, the dictionary, Open SQL, the ICF service tree, the OData gateway, CDS, AMDP, LUW, screens, jobs and daemons are all here. There is no business application: no finance, no logistics. Everything runs as a subset: of the language, of the dictionary, and of Gateway (classic code-based SEGW).

Everything is a file. The ABAP is a repository, the tables are abapGit TABU JSON, a build is an immutable generation addressed by the hash of its inputs, and the database sits behind an eleven-method seam: sql.js, SQLite, DuckDB, PostgreSQL or HANA. So a whole system can be copied, branched, compared and thrown away.

The name: vsp (vibing-steampunk) → steamgate. Gate is the SAP Gateway, the /IWBEP/ framework whose runtime this project reimplements.

The ways to run it, in a sentence each

  • Browser. The transpiled ABAP, the OData runtime and SQLite run in a service worker on your machine; no server answers anything.
  • Docker. ghcr.io/oisee/open-steamgate, tags showcase-draft (with the demo packs) and draft (core), multi-arch amd64 and arm64. The arm64 image also runs on a Raspberry Pi 4 (docs/spin.md).
  • Binary. One self-contained Bun executable per platform. It copies its system into your user data directory on first start and layers your own folders over it with osd up --layer <folder>.
  • VS Code. The OSD tree, F8 data preview, ABAP Unit in the Test Explorer, debugging, and a .http CodeLens that finds the DPC method behind a request.

For warm local development (OSD_WARM=1 STG_DEV=1 npm start), run npm run transpiler:pin after npm ci. It builds the libs.lock.json pin in $HOME/.cache/osd/transpiler-<ref> and links transpiler, CLI, runtime and core; a verified build is reused. Override the persistent location with TRANSPILER; temporary directories and session scratchpads are refused. Startup and osd doctor print a prominent install hint if warm capabilities are missing. See warm setup.

The launchpad in the browser build:

tilewhat it is
Travels, BookingsFiori Elements V2 list report and object page over a SEGW-shaped _MPC_EXT / _DPC_EXT pair
Flight analyticsan analytical list page over a CDS cube ($select → GROUP BY)
SEGWthe Service Builder as an app, editing the project tree
Vivid Vibes · Zork · SAP LSDpages an ABAP class writes: WebGL and audio over APC, a Z-machine in ABAP, a light-show replayed as SAP GUI screens

The first visit installs the worker; after that the app works offline. Private windows usually refuse service workers.

Launchpad

What it looks like

Every pixel below is served by transpiled ABAP over SQLite. SAPUI5 1.120 is loaded from SAP's CDN, unchanged.

Object page with the travel's picture and its bookings

The SEGW project tree as a Fiori app

Analytical list page over the flight cube

SAP Easy Access served by ABAP

node scripts/capture-docs-shots.mjs takes these pictures while npm start is running.

Where it stands, 2026-09-30

0.3 beta was released on 2026-09-29 (vscode-v0.2.1307); 0.4 is in progress. AGENDA.md records every decision, docs/backlog/ is the open list, and ANORMALIES.md records every place the runtime differs from SAP, written down before any workaround.

areawhat worksdocs
Gateway, OData v2URL parser, $filter → SELECT-OPTIONS with every io_tech_request_context facet, $batch with changesets, navigation, $expand, deep insert, function imports, value helps, MERGE, create below a parent, media entities ($value), service-to-service calls. All of it is ABAP behind one if_http_extensiondocs/prior-art.md
SEGWIWPR ↔ _MPC/_DPC generation with RFC/BOR and search-help mappings; one YAML → a whole project (stg-compile); the project tree in 53 SEGW-shaped tables with byte-identical export; the generator ported to ABAP; the Service Builder as a Fiori appdocs/stg-compile.md, docs/segw-editor.md
SADL and CDSCDS projections, @OData.publish, writable projections (including through a chain of views), analytical cubes, virtual elementsdocs/cds-publish.md, docs/cds-writes.md
AMDP and SQLScriptAn AMDP body runs where it belongs, on HANA, or portably on DuckDB. The SQLScript front end lowers to three dialects and refuses a silently wrong translationdocs/amdp-in-hana.md, docs/portable-amdp-report.html
ADT façadeEclipse ADT and vsp treat OSD as a system: package tree, edit, save, activate, ABAP Unit, F8 preview, create/delete. Every change lands on the git tree as abapGit files. It works over HTTPS (Cloud Project) and over RFC (Custom Application Server) through the built-in JavaScript bridgedocs/adt-facade.md, docs/adt-over-rfc.md
Classic screensSAP Easy Access, SE16, ST05 and an editor, served by ABAP on the paths the originals usedocs/webgui.md
Jobs and daemonsJOB_OPEN/SUBMIT/CLOSE with standard signatures, SUBMIT … VIA JOB … WITH … IN, multi-step jobs, durable keys, tail events, a doctor. ABAP daemons: dialog-step queue, PCP, timers, AMCdocs/abap-daemons.md
FilesOPEN / READ / TRANSFER / DELETE DATASET behind a sandbox: deny by default, allowed roots, no escape through .., symlinks or a swapped directory. A streaming zip reader in ABAP (own inflate, bounded memory, CRC-checked) runs the same on a systemdocs/dataset.md, docs/zip-stream.md
OSGo: ABAP → Gogogen compiles the system to Go: the whole OSD as one Go binary (841 classes at #251, the demo answers), a report as a native command-line tool with its selection screen (osabap), ABAP Unit on Go compared method by method with Node, and sXML about 27× faster than on Node on a 10 MiB benchmark (#275)tools/gogen/README.md
Databasessql.js, SQLite file (WAL), DuckDB, PostgreSQL and HANA behind one seam; FOR ALL ENTRIES sent in blocks, similar to the kerneldocs/db-backends.md
InstrumentsComparing two systems (responses, SQL at the seam, a branch of a whole system), .http regression cases with a frozen clock, and a frame-by-frame oracle against a real systemdocs/regression-http-cases.md, docs/frame-comparison.md
Packs and deliveryA pack is a directory (osd-pack.json: ABAP, tables, rows, pages, tiles) layered over the tree. There is one Bun binary (build/osd), a relocatable release directory, Docker for amd64 and arm64, the browser preview on GitHub Pages, and a CI that gates every publication on the tag's testsdocs/using-osd.md, docs/preview-deployments.md
Testsnpm test = transpile + abaplint + ABAP Unit + mocha over the wire, plus Playwright for the apps. A unit run fails when a test class in the tree did not run

ABAP as a language for command-line tools

gogen compiles ABAP to Go (OSGo; building needs Go 1.26). Two hosts come out of it.

A report becomes a native command. osabap takes a classic executable report and builds one self-contained binary with no server, no database and no SAP system (npm run osgb -- <report> is the same command: osabap is the compiler, OSGB the binary it makes). The compiler itself runs on Node; the binary does not. The selection screen is the command-line contract:

node tools/gogen/osabap.mjs tools/gogen/apps/hello/zhello.prog.abap   # -> tools/gogen/.out/osabap
tools/gogen/.out/osabap Alice                        # parameters in declaration order
tools/gogen/.out/osabap --name Alice --loud --s-tag one --s-tag two  # a repeated select-option = I/EQ rows
tools/gogen/.out/osabap -params @arguments.json     # or all of it as JSON
tools/gogen/.out/osabap                              # no arguments, a terminal: the selection screen as a TUI
tools/gogen/.out/osabap -sapgui                     # the same screen to a real SAP GUI over DIAG, on 127.0.0.1
GOOS=windows GOARCH=arm64 node tools/gogen/osabap.mjs report.prog.abap   # cross-compiles

The usual lifecycle runs: INITIALIZATION, the selection-screen events, START-OF-SELECTION, WRITE to stdout. CL_GUI_FRONTEND_SERVICES maps to the local file system. OPEN DATASET works inside the roots you allow (-allow-read ./in -allow-write ./out). Build with --read-params P_FILE,P_CONFIG to grant reads to the files or directories the user supplies, or --read-lists P_DEPS to also grant the paths listed in that file (relative to its directory). Supplying a list means the user vouches for every path in it, including absolute and ../ entries; a list the report wrote earlier is still the user's choice to pass. The host grants these reads before ABAP runs; -no-default-reads disables them, and writes still require explicit permission. A report with tables of its own (their .tabl.xml beside the report) keeps its rows in the SQLite file -db notes.db names, created with those tables when missing; 12 of the 18 Open SQL forms of tools/gogen/apps/sql-corpus compile so far. The samples are in tools/gogen/apps/, and the details are in docs/osabap-native.md.

The whole system in Go. node tools/gogen/osgo.mjs builds tools/gogen/.out/osgo, the complete OSD (ICF, Gateway, the apps, SQLite) as one Go binary. The same ABAP Unit tests run on Node and on Go and are compared method by method; closing the gap is the work before 0.4.

Generated classes in CI. The same folder of *.clas.abap and *.clas.testclasses.abap can run on either runtime:

npm run osgo:unit -- ./generated --json --class ZCL_EXAMPLE
npm run osgjs:unit -- ./generated --json --class ZCL_EXAMPLE

Both commands read the immediate directory, stage missing class metadata in a temporary folder, preserve existing .clas.xml, reject source lines longer than 255 characters with file:line, and report overrides on stderr and in JSON. --class accepts multiple owner names; omit it to run all owners in the folder. They work from any cwd when invoked by the checkout's absolute script path. JSON contains rows (class, testclass, method, status, message), totals (success, failure, not_compiled, error, tests) and overrides. Exit codes are 0 for at least one test and all SUCCESS, 1 for assertion FAILURE, 2 for NOT_COMPILED/ERROR/SKIPPED, and 3 when there are no tests.

The JS command requires installed Node dependencies and synced libraries. It copies the configured checkout layers into a disposable checkout, excluding all content packs (including OSD_PACKS), runs the generators and transpiles the whole tree (roughly 20 seconds for transpilation), then runs ABAP Unit only for the selected owners, including class and instance lifecycle hooks. This command still builds the whole tree; the local warm path can use the pinned transpiler's only option. For large generated folders, use Node with a larger heap and a private SQLite file instead of in-memory sql.js:

NODE_OPTIONS=--max-old-space-size=12288 npm run osgjs:unit -- ./generated --db file --json

--db sqlite (the default) uses sql.js; --db file creates its database in the invocation's staging directory and removes it on completion. Inherited STG_DB_PATH cannot select another database. NODE_OPTIONS reaches the scanner, transpiler, generators and Unit child; choose a heap limit that fits the host. ABAPiti's public osd-up.sh runs the pinned JS binary with a private STG_DB_PATH, and osd-m1.sh deploys generated classes through ADT. Its workflow uses the binary, not a Node heap flag; this checkout runner mirrors that file isolation and documents the extra heap needed to build a large folder at once. The recorded measurements use Node v26.9.0, the checkout's existing local runtime/transpiler 2.13.93 build and its resolved core 2.120.59. Each invocation owns its output and database; parallel runs leave the input folder, output/ and build/live untouched. The Go command additionally accepts --jobs N (default 4) and needs Go 1.26.

The generated support page inventories statements, built-ins, elementary declarations and conversions, joins per-class results for both runtimes, and lists kernel compatibility warnings. It is evidence from a corpus, not a specification. Regenerate from a read-only ABAPiti checkout with the commands below; flatten the split fixtures as the ABAPiti CI does, and repeat the two runtime commands for any extra qjs, mono and int8 folders under .local/abapiti. Retain JSON from partial runs so passing and failing classes keep their results. Declare full-folder runs using --runs <manifest.json>; each array entry has folder (input basename), runtime (osgo or osgjs) and file (relative to that manifest), or reason for a crash without class results. Full-folder runs covering every test owner with all rows SUCCESS credit helper classes as exercised by their tests; partial runs with failures leave helpers not measured; missing test owners leave helpers and omitted owners not measured. Harness crashes, OOM and setup failures before any class are not measured with a reason; fails applies only to test results. Manifest entries may include wallSeconds and peakRssKiB (GNU time maximum resident set size across the command and its children, including the build). Both runners snapshot provenance into their JSON: backend, heap override, installed runtime/transpiler and database versions, Node, and Go for osgo. A manifest's provenance can preserve those settings for a crash without JSON or an older run; it takes precedence over the result's snapshot. Missing metadata is printed as "not recorded". Regeneration reads the snapshots, so changes to installed tools or NODE_OPTIONS cannot rewrite historical provenance. The file backend uses node:sqlite, not better-sqlite; its SQLite version comes from the installed Node binary. Harness rows carry source: "harness"; assertion messages never determine provenance. Plain --osgo/--osgjs files give per-class evidence only, which is safe for runs restricted with --class.

Editors can import kernelWarnings and KERNEL_FORMS from tools/osd-kernel-compat.mjs, then call kernelWarnings([{file, source}]) on unsaved buffers. Each finding includes file, line, form, message and supportAnchor, a stable link into this page; KERNEL_FORMS lists the fixed anchors and titles. Show findings as Error diagnostics by default while allowing the code to run. osg.kernelStrict: "refuse" opts into refusal, matching the unit runners' --kernel-strict mode.

mkdir -p .local/support-work/go-cache .local/support-work/go-tmp .local/support-work/go-path
export GOPATH="$PWD/.local/support-work/go-path" GOMODCACHE="$PWD/.local/support-work/go-mod"
export GOTOOLCHAIN=go1.26.0 GOFLAGS=-buildvcs=false
export GOCACHE="$PWD/.local/support-work/go-cache" GOTMPDIR="$PWD/.local/support-work/go-tmp"
export ABAPITI_TEST_OUT="$PWD/.local/support-work/corpus"
OSD_HEAVY_RANGE=50-59 tools/osd-heavy.sh bash -c 'cd .local/abapiti-src && go test ./wasm -run "^TestOSD_EmitUnitClasses$" -count=1'
cp .local/support-work/corpus/TestOSD_EmitUnitClasses/split/*.abap .local/support-work/corpus/TestOSD_EmitUnitClasses/
rm -r .local/support-work/corpus/TestOSD_EmitUnitClasses/split
OSD_HEAVY_RANGE=50-59 tools/osd-heavy.sh bash -c 'timeout 1200 npm run -s osgo:unit -- .local/support-work/corpus/TestOSD_EmitUnitClasses --json > .local/support-work/osgo-corpus.json'
OSD_HEAVY_RANGE=50-59 tools/osd-heavy.sh bash -c '/usr/bin/time -f "wallSeconds=%e peakRssKiB=%M exit=%x" -o .local/support-work/osgjs-corpus.time timeout 1800 env NODE_OPTIONS=--max-old-space-size=12288 node tools/osgjs-unit.mjs .local/support-work/corpus/TestOSD_EmitUnitClasses --db file --json > .local/support-work/osgjs-corpus.json 2> .local/support-work/osgjs-corpus.err'
npm run osg:support -- .local/support-work/corpus/TestOSD_EmitUnitClasses --osgo .local/support-work/osgo-corpus.json --osgjs .local/support-work/osgjs-corpus.json --out docs/osg-support.md --json .local/support-work/support.json
# Append extra input folders and partial or successful --osgo/--osgjs files.
# To credit helpers, create a full-folder manifest (paths relative to this JSON):
# Run each extra folder on both runtimes with the same commands and timeout,
# writing osgo-{int8,mono,qjs}.json and osgjs-{int8,mono,qjs}.json.
# When remeasuring, update wallSeconds/peakRssKiB from each .time file.
# If a run has no JSON or only setup ERROR rows, retain its crash/setup reason.
# The committed page uses the following full-folder result files:
cat > .local/support-work/runs.json <<'JSON'
[
  {
    "folder": "TestOSD_EmitUnitClasses",
    "runtime": "osgo",
    "file": "osgo-corpus.json",
    "provenance": {
      "database": "modernc.org/sqlite",
      "heap": "Node default (no --max-old-space-size override)",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "Go": "go1.26.0"
      }
    }
  },
  {
    "folder": "TestOSD_EmitUnitClasses",
    "runtime": "osgjs",
    "file": "osgjs-corpus.json",
    "wallSeconds": 96.27,
    "peakRssKiB": 2590272,
    "provenance": {
      "database": "--db file (node:sqlite)",
      "heap": "--max-old-space-size=12288 MiB",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "node:sqlite (SQLite)": "3.53.4"
      }
    }
  },
  {
    "folder": "int8",
    "runtime": "osgo",
    "file": "osgo-int8.json",
    "provenance": {
      "database": "modernc.org/sqlite",
      "heap": "Node default (no --max-old-space-size override)",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "Go": "go1.26.0"
      }
    }
  },
  {
    "folder": "int8",
    "runtime": "osgjs",
    "file": "osgjs-int8.json",
    "wallSeconds": 23.06,
    "peakRssKiB": 1371808,
    "provenance": {
      "database": "--db file (node:sqlite)",
      "heap": "--max-old-space-size=12288 MiB",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "node:sqlite (SQLite)": "3.53.4"
      }
    }
  },
  {
    "folder": "mono",
    "runtime": "osgo",
    "file": "osgo-mono.json",
    "provenance": {
      "database": "modernc.org/sqlite",
      "heap": "Node default (no --max-old-space-size override)",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "Go": "go1.26.0"
      }
    }
  },
  {
    "folder": "mono",
    "runtime": "osgjs",
    "file": "osgjs-mono.json",
    "wallSeconds": 511.18,
    "peakRssKiB": 1636204,
    "provenance": {
      "database": "--db file (node:sqlite)",
      "heap": "--max-old-space-size=12288 MiB",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "node:sqlite (SQLite)": "3.53.4"
      }
    }
  },
  {
    "folder": "qjs",
    "runtime": "osgo",
    "file": "osgo-qjs.json",
    "provenance": {
      "database": "modernc.org/sqlite",
      "heap": "Node default (no --max-old-space-size override)",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "Go": "go1.26.0"
      }
    }
  },
  {
    "folder": "qjs",
    "runtime": "osgjs",
    "file": "osgjs-qjs.json",
    "wallSeconds": 1800.45,
    "peakRssKiB": 8879396,
    "reason": "30-minute timeout after a successful build with the larger heap and private file-backed SQLite; no class results; exit 124",
    "provenance": {
      "database": "--db file (node:sqlite)",
      "heap": "--max-old-space-size=12288 MiB",
      "versions": {
        "@abaplint/runtime": "2.13.93",
        "@abaplint/transpiler": "2.13.93",
        "Node": "v26.9.0",
        "node:sqlite (SQLite)": "3.53.4"
      }
    }
  }
]
JSON
# Exact command for the committed page:
npm run osg:support -- .local/support-work/corpus/TestOSD_EmitUnitClasses .local/abapiti/int8 .local/abapiti/mono .local/abapiti/qjs --runs .local/support-work/runs.json --out docs/osg-support.md --json .local/support-work/support.json
# Replace --out with --check docs/osg-support.md to compare without writing.

The header identifies generator content by combining the git blob hashes of tools/osg-support.mjs and tools/osd-kernel-compat.mjs into a short SHA-256 id, and lists both files and their blob hashes. The default date comes from the external ABAPiti commit, which is immutable; rebasing or squash-merging OSG therefore leaves the page and its exact --check comparison unchanged. To override metadata explicitly, append --osg-rev <hex-id> --date <yyyy-mm-dd>.

Architecture

façade — test/start.mjs, no ABAP work process — transpiled ABAP RFC DIAG HTTPS browser · Fiori / UI5 Eclipse ADT · vsp SAP GUI JS RFC→ADT bridge JS DIAG stub HTTP :3030 · HTTPS ADT façade → object store (abapGit files) proxy · pool of work processes ICF · APC Gateway · SEGW · SADL · packs DatabaseClient seam SQLite · DuckDB · PostgreSQL · HANA

A generation is one transpiled system named by the hash of its inputs (the layers of abap_transpile.json, the packs, and the generated gen/). Moving the live pointer to another generation recycles the work processes, and moving it back is a rollback. The browser build bundles the same output into a service worker. More: docs/generations.md, docs/architecture-split.md.

Run it

Node 22.18+ (major 22) or Node 24. 22.18 is the first Node 22 that strips TypeScript types without a flag; the gogen typing work moves tools to .ts.

git clone https://github.com/oisee/open-steamgate && cd open-steamgate
npm ci
npm run bootstrap            # pinned library clones + packs, then gen/
npm start                    # http://localhost:3030/ is the launchpad
npm run dev                  # the same, rebuilding as you edit ABAP
npm test                     # abaplint + ABAP Unit + mocha over the wire
npm run e2e:install && npm run e2e         # Playwright
npm run web:preview && npm run web:serve   # the browser-only build on :3031
npm run start:duckdb         # on DuckDB (STG_DB_PATH=x.duckdb persists)
npm run unit:hana            # on a real HANA
npm run binary && build/osd up             # the workbench as one Bun binary
npm run vsix                 # the VS Code extension

HANA Express: running its image accepts SAP's developer licence, see docs/amdp-in-hana.md. npm run bootstrap reads libs.lock.json: it clones the pinned libraries into .local/lars/, fetches the packs and runs the first transpile.

Build on it

docs/using-osd.md is the working guide. In short:

  • A service is one YAML file (npm run stg:compile): SEGW without the GUI. An entity reads from a table, a CDS view, a function module, a search help, another service, or a hand-written GET_ENTITYSET.
  • OData from CDS needs one annotation: @OData.publish: true.
  • Content comes as a pack: a directory with osd-pack.json, dropped into packs/, layered after the tree. A collision is reported with both files.
  • A real system is reached with a zip. npm run segw:zip builds an abapGit offline repository, and a Fiori app goes as a BSP application with its ICF node (docs/a4h-deploy.md).
  • A worked example, as a book: osg-demo — The Airship Fleet / Флот дирижаблей builds one ABAP application on open-steamgate chapter by chapter, from a first class to OData, Fiori, CDS, jobs, osabap and abaplint in ABAP. Every chapter runs against a pinned open-steamgate tag; EPUB and PDF, English and Russian, are on the releases page.

Thanks

This is grown on Lars Hvam's work and would not exist without it: abaplint and the transpiler turn the ABAP into something that runs, open-abap is the runtime library under it, and abapGit is how code gets in and out. Fixes go back upstream, one small PR each (docs/upstream.md).

Family

  • vsp / vibing-steampunk: MCP server and CLI for ADT, SAP-LZH decode, abapGit deploy-back.
  • open-rfc-go: pure-Go NI / RFC / CPIC transport, used as an external oracle.
  • sap-lsd, sap-tui: the DIAG light-show and the terminal viewer behind the LSD tile.

Protocol facts from two private siblings are summarised in docs/layers-we-own.md.

Prior art

MIT unless noted; the evidence is in docs/prior-art.md. abaplint/transpiler · open-abap/open-abap-odata (the /IWBEP/ interfaces; its licence is still unclear, so we use it as interfaces only) · abapGit · SAP/open-ux-odata (Apache-2.0, studied as the conformance reference, not a dependency) · larshp/hithub (the browser preview's recipe).

License

MIT — see LICENSE. This is a clean-room reimplementation of the /IWBEP/ interfaces. It bundles no SAP source and no standard DDIC.

MIT, read

History

Latest

v0.7.2118

Other 3

Notes

open-steamgate 0.7.2118 (stable): VS Code extension for desktop and vscode.dev. Upload this file to the Marketplace by hand; it replaces 0.7.2117.

  • Commit: dfa44b00fde6ff867a4fff389bd7d7224b8ad1ea (PR #835 head: the gear-gate launchpad logo split one element per line for BSP, and docs)
  • Gear-gate icon and launchpad logo. Marked as a web extension (ExtensionKind workspace,ui,web; tag __web_extension). Browser entry, Fiori apps, media, lazy DuckDB-Wasm. No PreRelease property.
  • Built locally with the marketplace profile, not through release.yml.

SHA-256 ef566fc43fde9b6c452fa816e2c8ee6e5243c4560845b0714763e3222c0d8388

Upload: Marketplace publisher oisee -> open-steamgate -> Update -> this .vsix.

  1. v0.7.2117

    Other 6

    Notes

    open-steamgate 0.7.2117: VS Code extension, desktop + vscode.dev (browser entry). Built for a manual Marketplace upload as the stable release.

    • Commit: 2ee859c847ccdb834def597891d23da31b754464 (PR #835 head: #828 + #833 on main, plus the gear-gate launchpad logo and docs)
    • Gear-gate icon and launchpad logo (2026-10-20)
    • Marked as a web extension: ExtensionKind workspace,ui,web, tag __web_extension
    • Browser entry dist/web/extension.js, Fiori apps, media, lazy DuckDB-Wasm; packs: zork
    • Stable (no PreRelease property)
    • Built locally with the marketplace profile (OSD_VSIX_PROFILE=marketplace OSD_VSIX_WEB=1 OSD_VSIX_PRERELEASE=0, pinned transpiler fork), not through release.yml: its tagged tests did not run on this exact commit; CI on #835 is in progress.

    SHA-256 64b19f953df0b1768e57f0676b14d50e0405a457a7f972f4282af03fdb1df550

    Upload: Marketplace publisher page (oisee) -> open-steamgate -> Update -> this .vsix, or npx @vscode/vsce publish --packagePath open-steamgate-0.7.2117.vsix.

  2. v0.7.2114prerelease

  3. v0.7.2109prerelease

  4. v0.7.1914prerelease

  5. v0.7.1696

  6. v0.7.1681

  7. v0.6.1650

  8. v0.7.1673

  9. v0.7.1671

  10. v0.6.1666

  11. v0.6.1621prerelease

  12. v0.6.1531prerelease

  13. v0.6.1511prerelease

  14. v0.6.1504prerelease

  15. v0.5.1486prerelease

  16. v0.4.1444prerelease

  17. v0.4.1414prerelease

  18. v0.4.1413prerelease

  19. v0.3.1370prerelease

  20. v0.2.1322prerelease

  21. v0.2.1307prerelease

  22. v0.2.1284prerelease

  23. v0.2.1207prerelease

  24. v0.2.1119prerelease

Others providing29

OData
  1. launchpad-kpiPuts a number from an abap2UI5 app on a Fiori launchpad tile
  2. odata-fwABAP framework for OData services with one class per entity
  3. open-abap-odataOData and Gateway shims serving SEGW-style services on Node.js
  4. @root3287/cap-segwCompiler from a CDS service to SEGW model and data provider classes
  5. OData Batch CreatorBuilds OData batch request payloads from an uploaded $metadata file
Local development
  1. abap2UI5 PlaygroundIn-browser ABAP editor beside the abap2UI5 app it builds
  2. web-abap2UI5abap2UI5 transpiled to JavaScript and run in a browser tab
  3. abap_trial_dockerScripts running the ABAP Developer Edition in Docker
  4. pokrakam/abapDevSysInitABAP report setting up a new ABAP Developer Edition or trial system
Unit testing
  1. abap2UI5 headless frontendDrives abap2UI5 app classes from ABAP Unit tests
  2. @abap2ui5/mcp-serverMCP server for the abap2UI5 check, deploy and run loop
  3. assertFluent assertion helper for ABAP Unit tests
  4. @abaplint/transpilerTranspiles ABAP to JavaScript to run on Node.js
  5. Modernization Agents for SAP on AWSAWS agents for ABAP, PI/PO and BW modernisation work
  6. abap_db_preparatorReplays stored database snapshots in ABAP unit tests
  7. cacamber-BDD-for-ABAPBDD framework turning Given/When/Then into ABAP Unit steps
  8. abap-utesthelpHelper classes for ABAP Unit tests and test doubles
  9. regression_testSnapshot testing library for ABAP, from debugger or unit test
  10. abapCovUploads ABAP Unit code coverage to codecov.io
  11. ABAP remote filesystemVS Code extension editing ABAP systems over ADT as a filesystem
  12. express-icf-shimShim running an ABAP ICF handler behind an Express 4.x server
  13. open-abap-coreCore ABAP artifacts for code transpiled by @abaplint/transpiler
  14. mockup_loaderLoader of Excel-prepared ABAP unit test data, with stub generation
  15. mockAA free mocking framework for ABAP, published under the Apache License 2.0.
  16. Vise_for_ABAPA characterisation-test helper: `ZCL_VISE=>GRIP` records a field's value once and fails a later run if it has changed.
  17. abap-senchaBDD/TDD assertion library for ABAP Unit, styled after Chai.js
  18. abap-test-containerGitHub-hosted test data container for ABAP Cloud
  19. abap-unit-runnerApplication job that runs and schedules ABAP Unit tests in the cloud
  20. adash-servicesBackend exposing ABAP Unit runs and coverage over REST and OData

Details

Sources3
GitHub APIdiscovered herechecked
github.com/oisee/open-steamgatetree, pushes, contributors, CIchecked
README.mdquoted, and what the entry declareschecked

Sources are graph entities: the same page may back several entries, and an unreachable source flags every row that rests on it.

Compatibility and provenance
runtimesnode
discovered viaGitHub API
first seen in the atlas
ecosystem and domainabap, developer-experience
Flavors1
Standard ABAP
“Everything runs as a subset: of the language, of the dictionary, and of Gateway (classic code-based SEGW).” — oisee/open-steamgate — README, What it ischecked
Contributors1

From the repository’s contributor list, .

History in the atlas1
  1. First seen.
For your agent
Ref
artifact:oisee-open-steamgate
JSON
/artifacts/oisee-open-steamgate.json
MCP
Connecting an agent