Skip to content

Install Lumen

Installing Lumen gives you lumenc, the command you use to create, run, and package apps, the Lumen runtime library it loads, the launcher a packaged app is built from, the runtime modules an app can declare, the candela standard library scripts import, and the app templates lumenc new writes. You do not need a Rust toolchain to build apps, or to package one for someone else.

Every release install also carries lumen-server, the server that runs a server-rendered site in production and the one lumenc web --serve starts. It is published as a container image too, ghcr.io/lumen-fx/lumen-server, for Linux on x86_64 and aarch64.

Linux and macOS

curl -fsSL https://lumenfx.dev/install.sh | sh

The installer resolves the current release, downloads the archive for your platform, and unpacks it under ~/.lumen. It prints what it is about to do and asks before writing anything.

Every release publishes a sha256sums.txt covering its assets. The installer downloads that file first and checks the archive against the line for it; anything that does not match is not installed.

Builds are published for Linux and macOS on x86_64 and aarch64. The installer needs curl or wget, and sha256sum or shasum.

Afterwards, lumenc lives in ~/.lumen/bin. If that directory is not on your PATH, the installer offers to add a line to your shell's startup file, and tells you the line to add if you decline. Open a new shell and check:

lumenc --version

The install also carries a shell completion script for bash, zsh, and fish under ~/.lumen/share, and prints the one line your shell needs to load it. See shell completions.

Runtime modules

Some capabilities live outside the engine, in libraries the runtime loads at startup: files, audio, canvas, downloads, processes, archives, stored values, cookies, WebSockets, and the browser-only ones a web build uses (the page's JavaScript, the browser around it, SVG drawings). An app asks for one by name under [dependencies] in lumen.toml, which lists the modules and their config keys; scripting covers the calls each one adds.

The script hosts are modules too: candela's compiler, which lumenc run, check and build compile scripts with, and the bytecode host a packaged app runs its scripts on, plus the deprecated Rhai and Lua hosts. An app never declares them; Lumen loads the one each script needs.

The installer downloads them with the toolchain, from the module archive published with the same release, and unpacks them into the same tree, so the libraries sit in ~/.lumen/bin beside the engine, which is where the runtime looks for them. --no-modules installs the toolchain without them, and such a toolchain runs and builds no script. The web halves of the modules, which lumenc web puts into a site, and the descriptors that say which module runs which script language, come with the toolchain itself under ~/.lumen/bin/modules, so a web build does not need the module archive. On Windows there is no module archive: the script hosts are compiled into lumenc.exe and lumen.dll. The setup-lumen action installs them the same way on Linux and macOS runners; see Continuous integration.

LICENSE, NOTICE and THIRD-PARTY-LICENSES land at the root of the prefix, carrying the license text of the toolchain and of everything it is built from. lumenc package copies them into each app you package.

An app whose modules are missing prints one line per module, lumen-runtime: MODULE LOAD FAILED: <name>, with the paths it probed under it, then keeps running with every call into that module's namespace failing. To put the modules in place, run the installer again with --force; a plain rerun at the same version stops at "Already up to date" and changes nothing:

curl -fsSL https://lumenfx.dev/install.sh | sh -s -- --force

Installer options

Option Effect
--prefix DIR Install root. Default ~/.lumen.
--version VERSION Install a specific release and pin to it.
--no-confirm Accept the defaults without prompting.
--no-modify-path Never write to a shell startup file.
--no-modules Skip the bundled runtime modules, script hosts included, and install the toolchain alone.
--no-lpm Skip lpm, the package-registry client.
--force Reinstall even when already at the target version.
--uninstall Remove every file the installer wrote.
-h, --help Show the installer's own help.

LUMEN_PREFIX sets the install root like --prefix.

To pass options through the pipe, hand them to sh:

curl -fsSL https://lumenfx.dev/install.sh | sh -s -- --prefix ~/tools/lumen

The package registry client

lpm resolves the packages an app declares and downloads them. It goes to ~/.local/bin/lpm, outside the prefix, because one copy serves every toolchain on the machine and lumenc looks for it there. You do not have to put that directory on your PATH; add it if you want to run lpm yourself.

--no-lpm skips it, and lumenc installs it the first time an app names a registry package.

Uninstall

curl -fsSL https://lumenfx.dev/install.sh | sh -s -- --uninstall

The installer records every path it writes, so an uninstall removes exactly those files and nothing else. A PATH line added to a shell startup file stays behind; delete it by hand, and so does lpm, which sits outside the prefix.

Homebrew

brew tap lumen-fx/lumen
brew install lumen

The formula unpacks the same release archive the script installs, so lumenc, the runtime library, the launcher, lumen-server, the candela standard library, the app templates, and the web halves of the first-party modules all come with it. brew upgrade lumen moves you to a newer release.

A Homebrew install carries no runtime modules and no shell completions, and it never checks for updates on its own, because Homebrew owns when the version moves. Use the script installer if you want any of those.

Windows

Download and run the per-user installer for your machine:

https://github.com/lumen-fx/lumen/releases/latest/download/lumen-windows-x86_64.msi
https://github.com/lumen-fx/lumen/releases/latest/download/lumen-windows-aarch64.msi

It installs under your user profile, so it needs no administrator rights, and it adds lumenc and lumen-server to your user PATH. Open a new terminal afterwards. Remove it from Settings > Installed apps, which also removes the PATH entry.

Each release also publishes lumen-windows-x86_64.zip and lumen-windows-aarch64.zip, portable archives you can unpack anywhere. A portable copy never checks for updates; you replace it by unpacking a newer zip.

A Windows install carries no runtime modules, so an app that declares [dependencies] starts without them and says so in one line on stderr. lumenc package --static compiles them into the executable instead.

Scoop

scoop bucket add lumen https://github.com/lumen-fx/scoop-lumen
scoop install lumen

Scoop installs the portable zip rather than the MSI, so the two never end up side by side. It puts lumenc and lumen-server on your PATH. scoop update lumen moves versions and scoop uninstall lumen removes it. Like the zip, it carries no runtime modules and does not check for updates on its own.

Platforms with no build

Releases cover Linux, macOS, and Windows, each on x86_64 and aarch64. On anything else install from source:

cargo install lumenc

This needs a Rust toolchain. It builds lumenc, then fetches the matching Lumen source and builds the runtime library, the launcher, and the candela standard library from it, putting all three beside the installed lumenc so running and packaging an app work the same as they do from a release. Expect it to take a while: it is compiling the engine.

A source install does not carry the app templates, because cargo keeps only the binary it installed. lumenc new wants a release install, or a clone of the template repository you were going to scaffold from. The same goes for the web halves of the first-party modules: a lumenc web build of an app declaring one wants a release install, or --lib-dir naming a directory whose modules/<name>/web/ holds it.

It does not build the runtime modules either, so the capabilities behind [dependencies] need a release install.

Nor does it build lumen-server, which lumenc web --serve runs. Build it from a Lumen checkout of the same version with cargo build --release -p lumen-server, and point LUMEN_SERVER at the binary.

Set LUMEN_SKIP_ENGINE_BUILD=1 to install only the compiler, if you are building the rest yourself. lumenc run, build, and check work without the runtime library and the launcher; lumenc package needs them, and it says so and names the directory to put them in. A script that reaches for import "std/..." or an array method needs the libs/ directory beside lumenc, or CANDELA_LIB_PATH naming one elsewhere.

Nightly builds

A build of main goes up every night as a prerelease, on one tag:

https://github.com/lumen-fx/lumen/releases/tag/nightly

Take one to try a fix or a feature before it is released. It carries the same archives a release does, and the notes on it name the commit it was built from. The same run pushes the server image as ghcr.io/lumen-fx/lumen-server:nightly.

On Linux and macOS, install one by naming the tag:

curl -fsSL https://lumenfx.dev/install.sh | sh -s -- --version nightly --force

The installer unpacks it under the prefix with its runtime modules, the same as a release, and pins the install to nightly, so lumenc never offers to replace it with a release. Every night is published under the same tag, so --force is what replaces the nightly you already have with the latest one. Run the installer again without --version to go back to the current release and lift the pin. On Windows, download lumen-windows-x86_64.zip and unpack it yourself.

Nothing reaches for a nightly on its own. A plain install.sh, the setup-lumen action, and lumenc's own update check all resolve the current release, and a prerelease is not one, so a nightly arrives only on a machine that asked for it.

Three things to expect from a nightly:

  • There is no Windows installer, only the portable zip. An installer would share product identity with a released install and take it over.
  • lumenc --version reports the version main carries, which no release is behind. It does not say which night you have; the commit in the notes does.
  • lumenc web and lumenc package --target download their extra files from the current release rather than from the nightly, because that is the only version they can resolve. A nightly compiler pairs them with a released browser runtime.

Every night's assets replace the last, so a link keeps working and the build before it is gone. Keep a copy if you need one to stay around.

Staying up to date

An installed lumenc looks for a newer release at most once a day and prints a single line when it finds one:

lumenc 0.2.0 is available (you have 0.1.0). Update: curl -fsSL https://lumenfx.dev/install.sh | sh

In a terminal it then offers to update for you. On Linux and macOS that reruns the installer. On Windows it downloads the new installer and runs it once the current command exits, because Windows cannot replace a running lumenc.exe.

The check is deliberately quiet:

  • Only the commands you type by hand are checked: run, check, build, bundle, new, fmt, and i18n. Automation subcommands stay silent.
  • Only an installed copy checks. A copy built from source, or unpacked from the portable Windows zip, never reaches the network.
  • Anything with --headless, a non-terminal stderr, or a CI environment variable turns it off.
  • LUMEN_NO_UPDATE_CHECK set to any non-empty value turns it off everywhere.

Pinning a version

Install with --version to hold a project on a known release:

curl -fsSL https://lumenfx.dev/install.sh | sh -s -- --version 0.1.0

A pinned install is never offered a newer release, and the files it downloads later stay on the pinned version: lumenc package --target and lumenc web fetch from the release the pin names. Run the installer again without --version to lift the pin.

Releases from before sha256sums.txt was published cannot be installed this way; the installer has nothing to verify them against and stops.

Continuous integration

A GitHub Actions workflow installs the toolchain with the setup-lumen action instead of the script above, which prompts and writes to a shell startup file:

steps:
  - uses: actions/checkout@v4
  - uses: lumen-fx/lumen/tools/setup-lumen@main
  - run: lumenc check .

It runs on Linux, macOS, and Windows runners, downloads the release built for the runner, checks it against the release's sha256sums.txt, and puts lumenc on PATH. Pass version to hold a workflow on a release:

  - uses: lumen-fx/lumen/tools/setup-lumen@main
    with:
      version: "0.1.0"

On a Linux or macOS runner it also installs the runtime modules, so a job can run an app that declares them under [dependencies]. A Windows runner gets none, for the same reason a Windows install does. Pass modules: false to leave them out of a job that only checks or formats an app:

  - uses: lumen-fx/lumen/tools/setup-lumen@main
    with:
      modules: false

The unpacked toolchain is kept in the workflow cache, keyed on the release, the runner's platform, and whether the modules came with it, so later runs skip the download.

Two things behave differently in a workflow than on a workstation. The update check never runs: a CI environment variable turns it off, and an unpacked archive has no install receipt to check against in the first place. And lumenc run loads the runtime library, which on Linux links GTK, ALSA, X11, and Wayland; a job that runs an app installs those first, while check, new, and fmt need none of them.

The action's own inputs and outputs are documented with it, in tools/setup-lumen.

Next