Installing the Leed CLI

leed is the command-line tool you develop your site with: it clones your site repository, builds and serves it locally, validates what you changed, and pushes it to your preview site. One command installs it, signs you in, and leaves you with a working checkout — and that installer is the only supported way to get it.

The CLI talks about pages, deployments, previews and page types exactly as the CMS does, so if any of those words are new, read core concepts first.

Before you start

The installer checks three things before it touches anything on disk.

RequirementMinimum versionIf missingFatal?
curlany“curl is required but not found.”Yes
Gitany“git is required but not found. Install from https://git-scm.com/”Yes
Bun1.1.0Offers to run `curl -fsSL https://bun.sh/installbash` for you

Bun is the one worth understanding. If Bun is absent, or older than the minimum, the installer asks before doing anything — Install bun? [Y/n]. Answering no stops the install: “bun v1.1.0 or later is required.” There is no alternative runtime. The minimum is a constant inside the installer and will move over time, so trust the number the installer prints over the number written here.

Platform support

Supported natively. The installer opens your browser for the sign-in step with xdg-open.

Windows Subsystem for Linux is supported here too, not as a separate platform. The installer detects WSL by looking for microsoft or wsl in /proc/version, and uses wslview instead of xdg-open so the sign-in page opens in your Windows browser. Everything else on this page is identical to native Linux.

On any platform the installer does not recognize, it does not fail — it simply prints the sign-in URL instead of opening a browser, and you open it yourself. That is also what happens over SSH, where there is no browser to open.

Get your install command

Open the profile menu at the bottom of the CMS rail and choose Developer Setup. The dialog builds the command from the origin you are signed in to and gives you a copy button.

The Developer Setup dialog, showing the install command, the prerequisites list and the After Installation section
curl -fsSL https://app.leed.ai/install | bash

Run it in your terminal. Do not open https://app.leed.ai/install in a browser — that URL is content-negotiated and only returns the installer script to curl and wget.

Your account also needs developer access before the installer can finish. That is a permission, not a plan: developer access is a resource override an administrator grants to a team member, and without it step four fails with “Your account needs developer access.” See billing and developer access.

What the installer does

Six steps, in this order. Each one either asks you something or writes something, and most of them can be skipped on a re-run — which is why the same command behaves differently on your second machine than on your first.

StepWhat it asksWhat it writesIf it fails
1. Check prerequisitesWhether to install or update BunBun, if you agreeFatal — Git or Bun missing
2. AuthenticateApprove a code in your browser~/.config/leed/credentials.jsonFatal after five minutes without approval
3. Choose a directoryWhere to create your project (default ~/leed)The directory, if it does not existFatal if the directory is not writable
4. Download configurationNothing<project>/leed.config.jsonFatal — 401/403 means no developer access; anything else is a server error
5. Install the packageNothing~/.bunfig.toml, then the global leed binaryFatal if leed is still not on your PATH afterwards
6. Initialize the siteNothingYour site folder and its raw-content git checkoutReports whatever leed site init reports

Step 2 is the standard device-code sign-in the CLI uses everywhere: it prints a code, opens your browser, and waits for you to approve. It is described in full on CLI authentication.

Step 3 expands a leading ~, so ~/projects/leed works. If the directory already contains a leed.config.json, you are asked “Overwrite existing configuration?” — declining keeps the file you have and the installer carries on.

Step 4 downloads your company’s configuration and the registry credentials in one request. A 401 or 403 here is about your account, and the installer says so plainly. Any other status is reported as a server-side problem, with the server’s own response printed underneath, so you are never sent to chase a permission that is fine.

Step 6 runs leed site init, which clones your repository and installs the project tooling.

flowchart TD
    start([Installer starts]) --> git{git on PATH?}
    git -->|no| gitFatal[Fatal — install Git from git-scm.com]
    git -->|yes| bun{bun 1.1.0 or later?}
    bun -->|missing or older| askBun{Install or update bun?}
    askBun -->|declined| bunFatal[Fatal — bun 1.1.0 or later is required]
    bun -->|yes| creds{Token already stored for this environment?}
    askBun -->|accepted| creds
    creds -->|none| device[Sign in with the device code]
    creds -->|yes| probe{Probe the configuration endpoint}
    probe -->|200| reuse[Reuse the stored session]
    probe -->|401| device
    probe -->|any other status| reuse
    device --> dir{Directory already holds leed.config.json?}
    reuse --> dir
    dir -->|yes| overwrite{Overwrite it?}
    dir -->|no| config[Write leed.config.json]
    overwrite -->|yes| config
    overwrite -->|no| keep[Keep the existing configuration]
    config --> installed{leed 4.27.0 or later already installed?}
    keep --> installed
    installed -->|yes| skip[Skip the package install]
    installed -->|no| install[bun install -g --trust the CLI package]
    skip --> init([leed site init])
    install --> init

Every branch on that diagram is a step somebody has watched the installer skip and wondered about. The probe on the third row is the one that surprises people most: when the configuration endpoint answers with anything other than 200 or 401 — a 502, say — the installer keeps your existing credentials rather than forcing you through a pointless re-login, and lets step four surface the real error.

What lands in ~/.bunfig.toml

Step 5 writes the @leed scope into Bun’s global configuration so bun install -g can reach the private registry:

[install.scopes]
"@leed" = { url = "https://gitlab.com/api/v4/projects/<project>/packages/npm/", token = "<your registry token>" }

There are four cases, checked in this order:

  1. An existing "@leed" line that references an environment variable ($VAR or ${VAR}) is left alone, and the installer prints “@leed registry in ~/.bunfig.toml uses an environment variable — leaving it alone”. That is a deliberate courtesy to developers managing their own token, not an error.
  2. No ~/.bunfig.toml at all — a fresh file with an [install.scopes] section is written.
  3. The exact same line is already there — nothing happens.
  4. Otherwise the stale "@leed" line is removed and the fresh one inserted under [install.scopes], adding that section if the file did not have one.

That file holds a real credential. It is covered, with the other two, in leed.config.json, files and environment.

Pinning a version

Pass a version as the script’s first argument:

curl -fsSL https://app.leed.ai/install | bash -s "1.2.3"

Without an argument, the installer takes the npm dist-tag that matches the CMS environment serving it:

CMS environmentTag installed
productionrelease
stagingstaging
devstaging
anything elserelease

In practice that means https://app.leed.ai/install installs release, which is what you want unless you are deliberately testing against staging.

Verify the install

leed -V

If that prints nothing, the Bun global bin directory is not on your PATH. The installer detects this and tells you what to add to your shell profile:

export PATH="$HOME/.bun/bin:$PATH"

Then open the site folder the installer created and build it:

cd ~/leed/<your-domain>
leed site build --serve

That is the loop you will live in from here: local development.

Re-running the installer

Running the same curl command again is safe, and it is the standard fix for a setup that has drifted. It reuses valid credentials rather than signing you in again, skips prerequisites that are already satisfied, warns before overwriting a leed.config.json, replaces a stale registry line in ~/.bunfig.toml, and upgrades or no-ops the package install. Nothing in your site repository is touched.

If a step does fail, every message the installer can print is cataloged in CLI troubleshooting and exit codes.

Automatic updates

The CLI does not merely check for updates — it installs them, without asking.

After any command finishes, and provided you are not in a development checkout, CI is unset, and neither of the internal --customer / --location flags was passed, the CLI consults a 24-hour throttle recorded in a .lastcheck.json file beside itself. If the throttle has elapsed it reads the release dist-tag from the registry, compares it with the running version, and — when the remote one is newer — runs bun install -g @leed/site-management@release on the spot.

To force the check past the throttle:

leed self-update

When there is nothing to do it prints “Already up-to-date, no updates required.”

Managed-file drift

An upgrade changes the CLI, not your repository — until the next time you run a leed site command. At that point the CLI compares the stored huskyVersion, vscodeVersion and skills version in your leed.config.json against its own version, and re-installs whichever set is behind: the git hooks, the VS Code workspace files, the Claude Code skills. Then it rewrites leed.config.json with the new version markers.

This is why files you deleted reappear after an update, and why the first leed site command after an upgrade does a little more than you asked for.

Shell completion

Tab completion is available for bash, zsh and fish. The shell is detected from $SHELL:

leed completion install

Restart your terminal to pick it up. To remove it:

leed completion uninstall

The package’s own post-install step also makes a best-effort attempt at this for every shell whose rc file already exists, and fails silently if it cannot — so completion may already be working before you run anything. The completion command is hidden from leed --help, but it is supported and documented here.

What init installs into your repository

Step 6 leaves more than a git checkout behind. Inside raw-content you get husky git hooks that enforce the commit and push workflow, a VS Code workspace with tasks for the common commands, and three Claude Code skills — site-builder, site-preview and site-publish.

The full inventory of what lands where — and which of those files you are allowed to edit — is in leed site init and in your site repository.

Every command the installer puts on your path, with its flags and its global options, is indexed at CLI command reference. And the session the installer created shows up alongside your browser sessions, badged Installer, in sessions, connected accounts and API tokens.

ESC