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.
| Requirement | Minimum version | If missing | Fatal? |
|---|---|---|---|
curl | any | “curl is required but not found.” | Yes |
| Git | any | “git is required but not found. Install from https://git-scm.com/” | Yes |
| Bun | 1.1.0 | Offers to run `curl -fsSL https://bun.sh/install | bash` 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
- Linux
- Mac
- Windows
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.
Supported natively. The installer opens your browser for the sign-in step with open. Both Apple silicon and Intel work; Bun ships builds for each and the installer picks the right one.
Native Windows and PowerShell are not supported. The installer is a bash script, and nothing in the CLI’s install path has a PowerShell equivalent.
Install WSL, open your Linux shell, and follow the Linux tab. Your site repository then lives inside the WSL filesystem, where the build tooling expects it.
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.
curl -fsSL https://app.leed.ai/install | bashRun 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.
| Step | What it asks | What it writes | If it fails |
|---|---|---|---|
| 1. Check prerequisites | Whether to install or update Bun | Bun, if you agree | Fatal — Git or Bun missing |
| 2. Authenticate | Approve a code in your browser | ~/.config/leed/credentials.json | Fatal after five minutes without approval |
| 3. Choose a directory | Where to create your project (default ~/leed) | The directory, if it does not exist | Fatal if the directory is not writable |
| 4. Download configuration | Nothing | <project>/leed.config.json | Fatal — 401/403 means no developer access; anything else is a server error |
| 5. Install the package | Nothing | ~/.bunfig.toml, then the global leed binary | Fatal if leed is still not on your PATH afterwards |
| 6. Initialize the site | Nothing | Your site folder and its raw-content git checkout | Reports 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:
- An existing
"@leed"line that references an environment variable ($VARor${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. - No
~/.bunfig.tomlat all — a fresh file with an[install.scopes]section is written. - The exact same line is already there — nothing happens.
- 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 environment | Tag installed |
|---|---|
production | release |
staging | staging |
dev | staging |
| anything else | release |
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 -VIf 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 --serveThat 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-updateWhen 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 installRestart your terminal to pick it up. To remove it:
leed completion uninstallThe 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.