This document defines Lamium's packaging and update contract.
Lamium is a client-only Windows x64 package. The repository carries a LIP v3
tooth.json, and Bedrinth lists Lamium (seen 2026-09-28 with versions
0.1.1-0.1.3). In LeviLauncher an
update (0.1.2 -> 0.1.3) kept user settings, and uninstall removed the package
files but left config/, logs/ and empty directories such as licenses/
(VALIDATION-LOG.md, 2026-09-28). LIP CLI is not checked.
How packages get listed (sources read 2026-09-28; the older
LiteLDev/bedrinth-api is archived and no longer describes this):
- The LIP registry
LiteLDev/liprruns a daily job that finds repositories by GitHub code search for a roottooth.jsonand, for each semverv*git tag without a manifest yet, opens a registry PR withtooth.jsonfrom that tag. After a registry maintainer merges it, the version appears in the indexes (Lamium 0.1.1-0.1.3 came in through lipr PRs #867, #868 and #872). Authors have no registration step. Prerelease semver tags count; the GitHub pre-release flag is not consulted. - The Bedrinth site and LeviLauncher both read that registry
(
lipr.levimc.org). LeviLauncher recognizes thegithub.com/LiteLDev/LeviLamina#clientdependency key and uses its range to judge compatibility with the instance and may refuse to install a version whose range does not match. The range intooth.jsontherefore gates installs, not only display. - The listing icon is
tooth.jsoninfo.avatar_url: the raw GitHub URL ofassets/icon/lamium-icon-512.pngon main (L-72). The registry copiestooth.jsonfrom a tag, so a new icon URL shows after the next tag. The PNG comes from the SVG master throughscripts/Export-Icon.ps1; re-run it and commit both when the SVG changes. The release ZIP carries no icon. - LeviLauncher installs, updates and uninstalls Bedrinth packages through the
LIP daemon (
internal/mcservice/lip_package.go), not by overwriting the mod folder.
Recommended order (L-65, 2026-09-28):
- LeviLauncher / Bedrinth — recommended discovery and install/update path.
- LIP CLI — advanced and development-oriented managed install/update path.
- GitHub Releases ZIP — manual install and recovery fallback.
These channels must publish the same Lamium build for a given version.
Package-owned files are files shipped by the release archive and managed by the installer. Runtime-owned files are created or changed after installation and must not be replaced by an ordinary update.
Package-owned examples:
Lamium.dllmanifest.jsonCOPYING,COPYING.LESSERTHIRD_PARTY_NOTICES.mdand bundled license texts- static resources intentionally shipped with Lamium
Runtime-owned examples:
config/, includingconfig/settings.jsonlogs/schematics/, the user-created/imported structure library- per-server waypoint, map and schematic-placement data under
config/ - local-world
lamium/sidecars (shapes, waypoints, placements and map data), outside the installed package directory
Feature storage contracts are in OVERLAYS.md, MAP.md and SCHEMATIC.md. These remain user data unless a feature explicitly defines a migration owned by Lamium.
Release archives must not contain runtime-owned state. The package check already
rejects config/ and logs/.
Prefer leaving runtime-created files outside package ownership. Use explicit preservation metadata only if managed-update validation proves that the normal ownership model is insufficient.
Current LIP (futrime/lip, source read 2026-09-28) records each file it
places. An update uninstalls the old version and installs the new one, and
uninstall deletes only the recorded files, so runtime-created config/ and
logs/ survive by design. preserve_files only exempts package-placed files
from that deletion and is matched against the file name, not the path; it is
not a way to protect runtime-created settings. LeviLauncher's own LIP daemon
behaved this way in the 2026-09-28 update and uninstall checks.
A release is valid only when these agree:
- Lamium version in
xmake.lua tooth.jsonversion- Git tag
v<version> - release asset
Lamium-<version>-client-windows-x64.zip - symbols asset
Lamium-<version>-client-windows-x64.pdb.zip - the version shown by the built mod
The archive contains a top-level Lamium/ directory that installs to
mods/Lamium/. From 0.2.0 it holds no Lamium.pdb (L-135, decided
2026-10-11): the symbols were about 90% of the archive and only matter for
crash addresses, so LIP, LeviLauncher and a manual install get the DLL alone,
and Lamium.pdb is released beside it, compressed, in the symbols asset. To
read a crash address, unzip it next to the DLL of the same version.
tooth.json declares Lamium as a Windows x64, client-only package and pins
the supported LeviLamina Client range. Compatibility changes must update the
manifest and user-facing support text together.
scripts/New-ReleaseArchive.ps1 checks these (the tag only when CI runs on a
tag push), checks the tooth.json asset URL and placement, and builds the
release asset into bin/release/ with / entry separators, the top-level
Lamium/ directory, no runtime state and no PDB. It then checks that the
package's Lamium.pdb belongs to the DLL inside the archive (the same debug
GUID and age, scripts/PdbIdentity.ps1) and writes the symbols asset beside
it. CI runs it on every push, so drift fails before or at the tag.
scripts/Check-Package.ps1 checks the same for the package folder.
A normal managed update must:
- replace package-owned files with the new release;
- preserve runtime-owned settings and user data;
- not restore removed defaults over explicit user choices;
- not require moving Lamium settings to a nonstandard location merely to make updates safe;
- fail clearly rather than partially replacing the package.
Configuration migration remains Lamium's responsibility when the settings schema itself changes. Package management preserving a file does not make an old schema valid.
Run this in a dedicated LeviLauncher instance, never the development instance, with two versions already in the registry. It passed for LeviLauncher on 2026-09-28 (0.1.2 -> 0.1.3, VALIDATION-LOG.md); repeat it when packaging, installer behavior or compatibility metadata changes.
Minimum validation:
- Clean managed install.
- Launch Minecraft and open Lamium Settings.
- Change at least one saved setting and one key binding.
- Close Minecraft normally.
- Update to a newer Lamium package through the same managed path.
- Confirm
config/settings.jsonis still present and the changed values load. - Confirm the new Lamium DLL/version is active.
- Confirm package notices and static files match the new release.
- Confirm uninstall behavior is understood and does not accidentally promise preservation or deletion of user data that the package manager does not actually provide.
Run the install/update check through LeviLauncher/Bedrinth and through LIP CLI when both are intended as supported paths.
Also keep the manual ZIP path usable as a fallback.
Release assets are built by CI from the tag, not on a local machine:
- Smoke-test the commit to be released in game with its CI development
package (
Lamium-windows-x64-<sha>on the commit's Actions run), not a local build. - Tag that commit
v<version>and push the tag. - The tag's
Build and testrun builds, tests and checks the package, runsNew-ReleaseArchive.ps1, and itsdraft-releasejob creates a draft release "Lamium " with the ZIP and the symbols ZIP attached. The draft body starts with the one-line description and the notices; a hidden comment gives the commit, the run and both assets' SHA-256, and the run summary the SHA-256. - Write the release notes under the notice and publish the draft. Re-running the job replaces the assets of a draft but refuses a published release.
The tag's build is a fresh build of the tested commit, so its DLL bytes may differ from the development package that was smoke-tested. If that matters for a release, install the draft's ZIP before publishing. The tag is public once pushed (the LIP registry picks it up), so publish the draft promptly.
Before publishing a managed release:
- build and tests pass;
scripts/Check-Package.ps1passes;scripts/New-ReleaseArchive.ps1passes, and the ZIP and the symbols ZIP it writes tobin/release/are the two assets attached to the GitHub release; from 0.4.0 the tag's CI run attaches them (Release flow above). Do not zip by hand: hand-made Windows archives, 0.1.1-0.1.3, stored\separators;- the pushed tag is
v<version>, and its CI run passes; - release notes call out settings-schema migrations when one exists;
- release notes start with the one-line description, then the
independent-project notice from the README as a quote, then the supported
versions (maintainer, 2026-11-01: the notice must be prominent, not first)
("Not an official LeviMC product. Not approved by LeviMC and not associated
with LeviMC. NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR
ASSOCIATED WITH MOJANG OR MICROSOFT."), as LeviLamina's and Minecraft's
usage guidelines ask for every listing and description;
tooth.json's description carries both for LIP, Bedrinth and LeviLauncher; - the release's VALIDATION-LOG entry names the tag's CI run and the assets' SHA-256, since THIRD_PARTY_NOTICES tells users a release is built from its tag. Releases up to 0.3.1 were attached by hand and did not record where they were built;
- a managed-update smoke test is repeated when packaging, installer behavior or compatibility metadata changes.
Runtime Minecraft checks remain separate from package validation. A package can install correctly and still contain a gameplay regression.