Package layout, tests, and the public store.
Publishing packages
Publishing means releasing a reusable package so other DemiEngine projects can depend on it by name and version. Publishing exists to turn "we copy these scripts between games" into "we depend on a versioned release", with an audit of exactly which files ship. This page covers preparing a package, the audited content rules, the release workflow, and how the public store at demiengine.de hosts your work. Examples use "Skyforge" at games/my_game.
Before you publish
A publishable package is a directory with a valid manifest (see Installing packages for the field reference), its declared files, and passing tests:
packages/skyforge-kit/
demi.package.json
scripts/
scenes/
assets/
certs/
packages/
demi.package.json— the manifest:format_version,name,version,engine,dependencies,public_modules,files.- Each directory below it holds one kind of shippable content. Only audited roots are allowed (see the audit table).
Prove the package before releasing:
demi package test packages/skyforge-kit
package test [dir]— runs the package's declared Lua tests. Returns0when every test passed,1when any failed.
demi validate packages/skyforge-kit
validate [path]— validates the package source and everything it references. Returns1on validation errors.
Both must pass before the version number is spent.
What may ship: the content audit
Every release is audited before it becomes a .demipkg. The audit exists so a package cannot smuggle build output, editor state, or arbitrary folders into other people's projects. Only these roots are allowed:
| Root | What belongs there |
|---|---|
assets/ | Asset manifests and their sources (images, models, data files). |
certs/ | Certificate material the package declares it needs. |
packages/ | Declared package dependencies' content, when vendored. |
scenes/ | Scene documents. |
scripts/ | Lua gameplay and module sources. |
demi.project.json | The project root document, when the package is a full project. |
demi.packages.lock.json | The pinned dependency lock. |
cook.manifest.json | The cooked-content manifest with paths and hashes. |
Anything outside those roots is rejected with BUILD_PACKAGE_CONTENT_UNEXPECTED. Generated output that is not declared by cook.manifest.json does not belong in a release; consumers cook or verify from the manifest instead of trusting loose files.
Creating the release artifact
The release artifact is a .demipkg — a single audited file other projects install:
demi package publish packages/skyforge-kit \
--registry https://demiengine.de
package publish [dir]— audits the package directory, builds the.demipkg, and uploads it to the registry. The default directory is the current one.--registry <url-or-path>— where to publish.https://demiengine.deis the public store; a local path works for a private registry.- Returns
0when the release is registered,1when validation or the audit fails.
The same command is the consumer-side pack flow in reverse: exporting and importing packs is covered in Assets & packages.
Releases are immutable
Once a version is published, its content never changes. That immutability is the contract consumers rely on: version 1.2.0 means the same bytes to everyone, forever, and the lock file hash keeps proving it. To change anything, publish a new version:
- Fix or extend the package source.
- Raise
versionin the manifest (patch for fixes, minor for additions, major for breaking API changes). - Run
package testandvalidateagain. - Publish the new version.
Consumers pick the change up with demi package update inside their declared constraints, exactly as described in Installing packages.
The store at demiengine.de
The public package store is demiengine.de. It serves three audiences:
- Consumers — browse the catalog, read what a package provides, and copy the
package addline for their project. - Publishers — use the publishing page to upload a
.demipkg, set the release notes, and see which versions exist. - Tooling — the same registry endpoint answers
package add,install,update, andoutdated.
Two entry points exist for publishing:
| Entry point | Use it when |
|---|---|
| Publishing page on demiengine.de | You want a guided upload in the browser with release notes. |
bin/publish.py | You are publishing from a script or continuous integration and want one command. |
bin/publish.py— the store's command-line publisher. It wraps the same audited upload asdemi package publish, so a browser upload and a scripted upload produce identical, immutable releases.
Registry credentials, if your registry requires them, come from environment configuration — never from files inside the package or the repository.
A complete release checklist
- Manifest fields filled:
format_version,name,version,engine,dependencies,public_modules,files. - Only audited roots are present (
assets/,certs/,packages/,scenes/,scripts/, plus the three manifest files). demi package testpasses.demi validatepasses for the package.- Version raised and release notes written.
demi package publish --registry https://demiengine.de(or the publishing page, orbin/publish.py) completes.- A fresh project installs the release and requires one public module successfully.
Related pages: Installing packages for the consumer side, and Build, cook & test for validation and packaging commands.