Skip to content

Install

candela installs as two programs: candela, the compiler that also runs source files and hosts the REPL, and candela-vm, the runtime that runs compiled artifacts. Both land together, along with the standard library and lpm, the client that fetches the packages a project depends on.

Linux and macOS

Run the install script:

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

It works out your operating system and processor, downloads the matching release archive, and checks it against the sha256sums.txt file published with the release before unpacking; on a mismatch, or for a release without that file, it installs nothing. It needs sha256sum or shasum alongside curl or wget.

Everything lands under ~/.candela, so the install needs no administrator rights and never runs sudo. Once the archive is unpacked the script offers to add that directory to your PATH by appending a line to your shell's rc file, and leaves your shell configuration alone unless you say yes. Open a new shell afterwards, or run the line it prints.

The standard library ships as .cdl sources in a libs directory beside the binary, and import "std/..." resolves relative to the binary's own location. Keep the two together; moving the binary on its own breaks those imports.

lpm goes to ~/.local/bin/lpm, not under the prefix: it is shared with every other tool that talks to the registry. It is in no receipt, so --uninstall leaves it where it is, and --no-lpm skips installing it. candela downloads it itself the first time a project needs one and finds none, so skipping it costs nothing but the wait.

Check the install:

candela --version

Options

Option What it does
--prefix DIR Install root. Default ~/.candela, also read from CANDELA_PREFIX.
--version VERSION Install a pinned release instead of the current one.
--no-confirm Run without prompting.
--no-modify-path Never write a PATH line to a shell rc file.
--no-lpm Do not install the registry client.
--force Reinstall even when that release is already installed.
--uninstall Remove every file the installer put under the prefix. lpm is shared and is left alone.
-h, --help Show the options.

Options go after -- when the script is piped into a shell:

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

Installing a specific release

Pass --version with a release tag. A leading v is optional, so both forms work:

curl -fsSL https://candela.lumenfx.dev/install.sh | sh -s -- --version 0.0.3
curl -fsSL https://candela.lumenfx.dev/install.sh | sh -s -- --version=v0.0.3

Releases published before sha256sums.txt existed cannot be verified, so pinning to one fails with a message pointing at the releases page. Release assets are named candela-<os>-<arch>.tar.gz; releases published before that naming keep the names they went out with, and pinning to one fails with the list of names that release does carry.

Uninstalling

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

It removes the files recorded in the receipt and leaves anything else under the prefix alone. A PATH line the installer added stays in your shell rc file for you to delete.

The receipt

The installer writes a file called receipt next to the binary, recording the version it installed, every file it wrote, and, when you asked for a specific release, that the install is pinned. candela reads the receipt to decide whether to look for newer releases:

  • No receipt means nothing installed this binary, so it was built from source and is left alone.
  • A pinned receipt means you chose this release, so newer ones are not announced.
  • Installing again without --version rewrites the receipt without the pin, which lifts it.

Windows

Windows installs from a package rather than the script. Download and run https://github.com/lumen-fx/candela/releases/latest/download/candela-windows-x86_64.msi.

The package installs per user, under %LOCALAPPDATA%\Programs\Candela, so it never asks for administrator rights. It adds that directory to your PATH and ships candela.exe, candela-vm.exe and the standard library. Open a new terminal afterwards so the updated PATH takes effect.

A portable candela-windows-x86_64.zip is published alongside the package for anyone who would rather unpack the toolchain by hand. Extract it somewhere and keep the libs directory beside the executables.

Nightly builds

A build of main goes out every night at https://github.com/lumen-fx/candela/releases/tag/nightly, for trying a change before there is a release carrying it. It is a prerelease, so nothing that looks up the newest release finds it: the install script with no arguments, candela's update check, and the Windows link above all stay on the newest real release.

Ask for the tag to install one:

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

That pins the install, so candela never offers you a release as an update. --force is what lets a later run replace yesterday's build: the receipt records the version as nightly either way, so without it the installer finds nothing to do. Install again without --version to go back to releases.

One tag holds the newest build, which is why the address never changes and last night's build is gone once tonight's is up. A nightly reports whatever version main carries, which is usually a number no release was ever cut for.

The assets are the ones a release publishes, apart from the Windows installer. On Windows, take candela-windows-x86_64.zip and unpack it. The installer stamps the version from the manifest and Windows compares packages by that number, so a nightly installer and a release installer of the same number would replace one another.

Staying up to date

candela --help and the REPL check at most once a day whether a newer release exists and print a line to standard error when there is one. Running a program never checks, so a script's output and exit status are never affected.

On Windows, candela --help goes further and asks whether to install the new release. Answer y and the package downloads and installs once the command exits; open a new terminal when it finishes. The REPL only prints the notice, because it is already reading from your keyboard.

The check is skipped when standard error is not a terminal, when CI is set, when the install is pinned, and when there is no receipt. To silence it everywhere else, set CANDELA_NO_UPDATE_CHECK:

export CANDELA_NO_UPDATE_CHECK=1

Editor support

The toolchain installs candela-lsp, a language server that runs candela's own parser and type checker, so an editor reports the same errors the compiler does. On top of diagnostics it gives hover, completion, go-to-definition, and a document outline. Every editor below finds it as candela-lsp on your path.

Highlighting comes from one of two grammars. VS Code and the IntelliJ-based IDEs use a TextMate grammar; Neovim, Helix, and Zed use the tree-sitter grammar, which also drives structural selection and bracket matching. Both live in the repository, under editors/.

  • VS Code. Install the Candela extension from the Marketplace or Open VSX. Set candela.languageServerPath to use a server that is not on your path.
  • IntelliJ IDEA and the other JetBrains IDEs. Build editors/jetbrains with ./gradlew buildPlugin, install LSP4IJ from the JetBrains Marketplace, then install the zip from build/distributions/ with Settings | Plugins | Install Plugin from Disk. On IntelliJ 2026.2 and later, LSP4IJ 0.21.0 or newer is required; earlier LSP4IJ builds do not load there.
  • Neovim. Copy editors/tree-sitter/nvim/candela.lua into your config, call require('candela').setup(), and install the parser with :TSInstall candela.
  • Helix. Append editors/tree-sitter/helix/languages.toml to your languages.toml, copy the queries into the Helix runtime directory, then run hx --grammar fetch and hx --grammar build.
  • Zed. Install editors/zed from the Extensions view with "Install Dev Extension".

Each client has a README with the full setup, including how to point it at a server you built yourself; Neovim and Helix share editors/tree-sitter/README.md.

In a browser

Every release also carries candela-web.tar.gz: candela compiled to WebAssembly, as the pair of files wasm-bindgen writes.

candela.js          loads the runtime
candela_bg.wasm     the compiler and the virtual machine

Load the module, hand run a whole program, and read what the program printed with get_output. A compile or run error arrives as a thrown value, and the report itself goes to the output, so read the output after catching.

import init, { run, get_output } from "./candela.js";

await init({ module_or_path: "./candela_bg.wasm" });
try {
  run('fn main() { print("hello"); }');
} catch {
  // the report is in the output read below
}
console.log(get_output());

This build has no file system, so a program it runs cannot import its own files. The language itself works, including the built-ins, and so do the standard library's math, random and time modules, which the build carries inside itself. The other std modules do not import here.

The prompt on candela.lumenfx.dev is this asset.

Building from source

To build the toolchain yourself, see Building candela. A binary you build is never announced as out of date, because it has no receipt.

Next

Write your first program in Hello, world.