Ramus
Java-based IDEF0 & DFD modeller. Build business-process models in the IDEF0 and DFD notations, keep them in git, and edit them by hand.


By Vitaliy Yakovchuk. Free software under the GNU GPL, version 3 — see License.
Contents
Download
Packaged builds are on the
Releases page: the macOS
DMG and the Windows installer are built by CI and attached to the release of a
v* tag. To build them yourself, see Building; to run the
application from source, see Quick start.
Quick start
You need a JDK and a desktop session. Gradle itself is not required — the wrapper downloads it.
git clone https://github.com/Vitaliy-Yakovchuk/ramus.git
cd ramus
./gradlew runLocal
The first run fetches Gradle and roughly 180 MB of dependencies; later runs start in seconds.
Open a model straight away instead of going through the dialog:
./gradlew runLocal -Popen="dest/doc/en/Enterprise activity.rsf"
Sample models live in dest/doc/en/ and dest/doc/ru/.
JDK version. Tested on Temurin 21; JDK 17 or newer is expected. The build
pins no toolchain, so sources compile against whatever JDK runs Gradle.
Packaging a macOS DMG additionally needs a full JDK 21+ with jdeps, jlink
and jpackage.
No JDK on the machine? See Docker below — it builds and runs without installing anything but Docker itself.
Project format
The application reads and writes .rsf — a ZIP of XML table dumps. It is
the only format it opens and the only one it saves.
The YAML project tree
Beside it the tree carries a text format: a project as a directory of YAML files, made to be read, diffed and edited by hand.
Model.ramus/
├── project.ramus entry point: schema version, plugins, counters
├── attributes.yaml every attribute of the model
├── qualifiers/ one file per qualifier
├── properties/ model settings
├── attachments/ user attachments (reports, files)
├── .gitignore
└── .local/ UI state; excluded from version control
Consequences worth knowing:
It goes into git as it is. Writing it is deterministic, so converting an
unchanged model rewrites no file and git status stays quiet until the model
itself actually changes. There are no timestamps in the files, deliberately —
they would make every write look like a change.
It is meant to be edited by hand. The YAML dialect is restricted on
purpose: block style, sorted keys, quoted strings, no anchors or aliases, no
line wrapping. One line in the file is one line of the value, so sed works
and a diff points at the change rather than the paragraph around it. Editing
values is safe; inventing identifiers is not — add new elements in the
application, then edit them in the files.
project.ramus is the entry point. It carries the schema version, the
application-version, minimum-version and the required plugins, and its
presence is what makes a directory a project.
The application neither opens nor saves it. A project handed to it — the directory or that file — is refused with a message naming it. The tree is reached through the converters, which read and write it with the same code the application uses for the model itself:
./gradlew :ramus-core-demo:rsfToYaml -Prsf=<file.rsf> -Pout=<directory>
./gradlew :ramus-core-demo:yamlToRsf -Pin=<directory> -Prsf=<file.rsf>
So the way to edit a model as text is a round trip: convert it out, edit the
files, convert it back, open the .rsf.
Full reference: docs/PROJECT_FORMAT.md.
Building
Runnable JAR
./gradlew :local-client:shadowJar
java -jar local-client/build/libs/ramus.jar
Docker
Builds in a container, so no JDK on the host:
docker build --target artifacts --output out . # out/ramus.jar
docker build --target test . # run the test suite
docker build -t ramus . # image that runs the GUI
Running the GUI from the container needs an X11 socket and an auth cookie — the recipe, the CI notes and the reasoning behind the Dockerfile are in docs/DOCKER.md.
macOS application and DMG
./packaging/macos/build-dmg.sh # one command: checks, builds, reports
The script picks a JDK (21 or newer, --jdk PATH overrides it), runs the
Gradle pipeline, and prints where the image landed and how to install it. It
refuses to run anywhere but macOS, because jpackage, iconutil and sips
exist only there.
Under the hood it is still Gradle, and the tasks can be called directly:
./gradlew :local-client:createMacApp # dev bundle, local-client/build/mac-app/Ramus.app
./gradlew :local-client:macDmg # standalone DMG in dest/macos/
macDmg runs the full pipeline: .icns from
packaging/macos/AppIcon.appiconset → jlink runtime → jpackage. The
resulting DMG bundles a Java runtime, so its users need no Java. If jlink is
unavailable the full JDK is bundled instead — larger, but it works.
The DMG is tied to one architecture, because the runtime inside it is: a
build made on Apple silicon does not run on an Intel Mac. The architecture is
part of the file name (Ramus-2.0.2-arm64.dmg), and
.github/workflows/macos-dmg.yml
builds both on GitHub’s runners — on a tag push it attaches them to the
release. No Mac needed to publish a build.
Installing. Open the DMG, drag Ramus into Applications. Nothing else — the Java runtime is inside the bundle.
The application is not signed with an Apple Developer ID, so a Mac that downloaded it from the internet quarantines it and reports that “Ramus is damaged”. It is not; macOS says that about everything unsigned. Either open it once through the context menu (right-click → Open → Open), or clear the flag:
xattr -dr com.apple.quarantine /Applications/Ramus.app
Pointing packaging at a specific JDK, without touching your shell’s
JAVA_HOME: create gradle-local.properties in the repository root (it is
gitignored).
packagingJavaHome=/Library/Java/JavaVirtualMachines/temurin-21.jdk/Contents/Home
# packagingUseJlink=false # bundle the full JDK instead of a jlink image
# packagingJmodsPath=…/jmods # explicit module path for jlink
# packagingLocales=en,uk,ru,pl # locale data kept in the jlink runtime
The bundled runtime keeps locale data for English, Ukrainian and Russian only.
Without it dates and Cyrillic sorting fall back to the root locale, and with
all of it the image grows by about ten megabytes; packagingLocales is the
dial between the two.
Windows installer
.\packaging\windows\build-installer.ps1 # one command: checks, builds, reports
The script checks the environment (Windows, a full JDK 21+, WiX Toolset 3) and runs the Gradle pipeline, which can also be called directly:
.\gradlew.bat :local-client:winInstaller # MSI in dest\windows\
.\gradlew.bat :local-client:winInstaller -PpackagingWinType=exe # EXE instead
Building needs WiX Toolset 3
(choco install wixtoolset): jpackage from JDK 21 drives WiX 3, support for
WiX 4 and 5 arrived only in JDK 24. Like the DMG, the installer can only be
built on the system it targets —
.github/workflows/windows-installer.yml
does it on GitHub’s runners, and on a tag push attaches the result to the
release.
Installing. Double-click, and that is the whole procedure:
- the Java runtime is inside the package, nothing else to install;
- it installs into the user profile, so no administrator rights are needed;
- a Start menu shortcut appears, and
.rsffiles open on double-click; - the next version replaces this one instead of installing beside it — that is
what the fixed
winUpgradeUuidinlocal-client/build.gradleis for, and it must never change; - uninstall goes through the normal Apps & features list.
The package is not signed, so SmartScreen greets a freshly downloaded installer with “Windows protected your PC” → More info → Run anyway. Only a code signing certificate removes that.
The old NSIS and IzPack path (./gradlew windowsInstaller) is still in the
tree but superseded: it hunts for a system JRE 1.6 and, failing to find one,
downloads it from a Sun URL that has not existed for over a decade.
Documentation
The design documents under docs/ are written in Ukrainian.
| Document | What it covers |
|---|---|
| docs/PROJECT_FORMAT.md | Complete project-format reference: syntax, identifiers, attribute types, how IDEF0 maps onto the files, safe-editing recipes |
| docs/AGENT_GUIDE.md | The procedure an agent follows to edit a model in the files, and where it must stop |
| docs/FORMAT_MIGRATION_PLAN.md | Why the format changed and how the migration was carried out, stage by stage |
| docs/START_REVIEW.md | The storage subsystem as it stood before that work — the baseline for comparison |
| docs/DOCKER.md | Containerised builds, running the GUI from a container, CI notes |
Contributing
Bug reports, fixes, documentation and packaging improvements are all welcome — open an issue or a pull request.
License
GNU General Public License, version 3. The full text is in LICENSE.
Copyright © 2005–2026 Vitaliy Yakovchuk.
Ramus is free software: you may redistribute it and modify it under the terms of the GPL. It comes with no warranty — see sections 15 and 16 of the license.