build linux output and runtime save locations.
Linux bundles
A Linux bundle is a shippable desktop package: a game executable players can double-click, with cooked content, a desktop menu entry, an icon, and a report of exactly what was built. Bundling exists so "works in the editor" becomes "runs on a player's machine" as one audited, reproducible artifact. This page covers validation and capability codes for Linux, cooking, building, and where the running game writes data. Examples use "Skyforge" at games/my_game.
Validate the Linux target first
Validation checks the project and everything it reaches against one platform's rules. Ask for Linux explicitly when you are about to ship a desktop build:
demi validate games/my_game --platform linux
validate [path]— validates the project and all reachable source.--platform linux— applies Linux capability and content checks in addition to document shape checks.- Returns
0when everything is valid,1when any validation error was reported.
Problems come back as stable capability error codes so build logs and continuous integration can classify them without parsing prose:
| Code | Meaning |
|---|---|
PROJECT_BUILD_FEATURE_MEDIA_UNSUPPORTED | The project needs media support (FFmpeg) that this build of the engine was compiled without. |
PROJECT_BUILD_FEATURE_NETWORK_UNSUPPORTED | The project needs networking (ENet) that this build of the engine was compiled without. |
PROJECT_BUILD_FEATURE_SVG_UNSUPPORTED | The project needs SVG support that this build of the engine was compiled without. |
PROJECT_BUILD_PERMISSION_NETWORK_MISSING | A platform permission required by the project is not declared (Android INTERNET is the common case). |
BUILD_PACKAGE_CONTENT_UNEXPECTED | Package content outside the audited roots was found and rejected. |
Environment checks add one more code, DOCTOR_OPTIONAL_FEATURE_MISSING, for optional features that do not block a run:
demi doctor --format json
doctor— inspects the environment and the project and reports what is ready and what is missing.--format json— emits the report as JSON for editors and pipelines.
Validate before packaging. A build never papers over a capability error; it fails with the code so you can fix the project or the toolchain deliberately.
Cook the content
Cooking turns authored source — JSON documents, Lua scripts, imported assets — into the platform-ready form the runtime loads. Cooking exists so startup is fast and shipping content is a hashed, known set of files.
demi cook --platform linux
cook— validates, then cooks every reachable source file.--platform linux— which platform profile to cook for.
Output lands under generated/cooked/<platform> together with cook.manifest.json: every cooked path and its content hash. The manifest is what later audits and incremental builds compare against. Returns 0 when the cook completes and the manifest is consistent.
Cooked output is generated content: never hand-edit it and never commit it. Re-run the cook instead.
Build the bundle
Building wraps the cooked content and a Linux runtime into the artifact a player installs:
demi build linux
build linux— cooks if needed, then packages the Linux runtime bundle.- Returns
0on success,1when validation, cooking, or packaging fails.
The bundle contains:
| Piece | What it is |
|---|---|
| Executable and launcher | The game binary players start. |
| Cooked content | The platform content from cook.manifest.json, verified by hash. |
| Freedesktop entry | The .desktop menu entry for application launchers. |
| Icon | The application icon taken from the project's build metadata. |
| Attributions | Third-party attribution files for the libraries the runtime links. |
build-report.json | A report of what was built: versions, content hashes, and configuration. |
Packaging is transactional. A failed or cancelled build leaves the previous artifact intact and never publishes a partial staging directory — the thing on disk is always a complete build or the previous complete build.
Package content audit
When content is packed for release, an audit checks every shipped file against the allowed roots. The audit exists so a release cannot accidentally include build output, editor state, or stray folders. The allowed roots are:
assets/— asset manifests and sources.certs/— declared certificate material.packages/— vendored package content.scenes/— scene documents.scripts/— Lua sources.demi.project.json— the project root document.demi.packages.lock.json— the pinned dependency lock.cook.manifest.json— the cooked-content manifest with paths and hashes.
Anything else is rejected with BUILD_PACKAGE_CONTENT_UNEXPECTED. The same roots apply when publishing packages (see Publishing packages) and when building release artifacts.
Where the running game writes
A shipped bundle must not write next to its own executable — that folder may be read-only or shared. Instead, the runtime uses the platform's per-user directories, following the XDG base directory rules:
| Data | Primary location | Fallback |
|---|---|---|
| Game saves | $XDG_DATA_HOME/<game>/ | $HOME/.local/share/<game>/ |
| Caches | $XDG_CACHE_HOME/<game>/ | $HOME/.cache/<game>/ |
<game>— the game's identity from the project build metadata.$XDG_DATA_HOME/$XDG_CACHE_HOME— environment variables from the XDG base directory specification; when unset, the fallbacks are used.
Saves and caches are per-user state. They never enter the bundle, never enter packages, and never become authored source. The save API itself is described in Replay & profiler.
Build metadata used by the bundle
Identity and window settings come from the project file:
"build": {
"application_id": "com.example.skyforge",
"display_name": "Skyforge",
"executable_name": "skyforge",
"version_name": "0.1.0",
"version_code": 1,
"icon": "asset://branding/icon",
"window": { "width": 1280, "height": 720, "mode": "windowed" }
}
application_id— reverse-DNS identity, required before packaging.display_name— the name in the desktop entry and window title.executable_name— the binary name inside the bundle; must match^[a-z0-9][a-z0-9_-]*$.version_name/version_code— human and machine version numbers written intobuild-report.json.icon— theasset://ID of the application icon.window— initial desktop window size in pixels andmode:windowed,borderless, orfullscreen.
The full project field list is on demi.project.json.
Before you hand the bundle to a player
demi doctor— the machine can produce a desktop build.demi validate games/my_game --platform linux— no capability or content errors.demi test linux— end-to-end tests pass (E2E tests).demi build linux— a fresh bundle andbuild-report.json.- Launch the bundle from a clean user account and confirm saves land under
$XDG_DATA_HOME.
Android packaging is covered in Android builds; all build commands are listed in Build, cook & test.