Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Install

Layover is a single binary called layover. It needs no runtime — not Rust, not Node.

macOS and Linux

brew install KotkaZ/tap/layover

A tap rather than brew install layover, because homebrew-core does not accept prebuilt binaries from third parties. You register nothing — taps are built into Homebrew, and the homebrew- prefix is elided in the install expression.

Without Homebrew:

curl --proto '=https' --tlsv1.2 -LsSf \
  https://github.com/KotkaZ/layover-project/releases/latest/download/layover-cli-installer.sh | sh

Windows

powershell -ExecutionPolicy Bypass -c "irm https://github.com/KotkaZ/layover-project/releases/latest/download/layover-cli-installer.ps1 | iex"

Both installers pick the right build for your platform, unpack it, and put layover on your PATH.

What they do and do not check

Be aware of exactly how much verification you are getting, because it is less than you might assume:

layover-cli-installer.shCarries the expected SHA-256 for each archive and checks it — but only if sha256sum is on the machine. If it is not, the installer prints skipping sha256 checksum verification and carries on successfully. Stock macOS ships shasum, not sha256sum, so on a clean Mac the check is usually skipped.
layover-cli-installer.ps1Does no checksum verification at all.
The npm packageDownloads the archive without verifying it.

Both installers are generated by dist rather than written here, so this is upstream behaviour rather than a local choice — but it is our documentation's job to say so rather than let you assume otherwise.

They are also not short: the shell installer is around 1,600 lines and the PowerShell one around 630. Reading one before running it is sound instinct, and a bigger job than it sounds.

Installing with verification you can see

If the above matters to you, skip the installers and do it by hand. This is fail-closed: a mismatch stops it.

TARGET=x86_64-unknown-linux-gnu
BASE=https://github.com/KotkaZ/layover-project/releases/latest/download   # or releases/download/v1.7.0

curl -fsSLO "$BASE/layover-cli-$TARGET.tar.xz"
curl -fsSLO "$BASE/layover-cli-$TARGET.tar.xz.sha256"

# shasum on macOS, sha256sum on Linux -- use whichever you have, and do not skip it
shasum -a 256 -c "layover-cli-$TARGET.tar.xz.sha256" || sha256sum -c "layover-cli-$TARGET.tar.xz.sha256"

tar -xf "layover-cli-$TARGET.tar.xz"
$target = 'x86_64-pc-windows-msvc'
$base   = 'https://github.com/KotkaZ/layover-project/releases/latest/download'   # or releases/download/v1.7.0

Invoke-WebRequest "$base/layover-cli-$target.zip" -OutFile layover.zip
$expected = (Invoke-WebRequest "$base/layover-cli-$target.zip.sha256").Content.Split(' ')[0]
$actual   = (Get-FileHash layover.zip -Algorithm SHA256).Hash

if ($actual -ine $expected) { throw "checksum mismatch: got $actual, expected $expected" }
Expand-Archive layover.zip -DestinationPath .

sha256.sum on the release covers every artifact, if you would rather check them together.

A checksum published beside the file it describes proves the download was not corrupted, not who produced it. For that, every artifact carries a build-provenance attestation: proof that it was built from this repository by its release workflow, which the GitHub CLI checks.

gh attestation verify "layover-cli-$TARGET.tar.xz" --repo KotkaZ/layover-project

The binaries are not code-signed — no Authenticode on Windows and no notarization on macOS — so the operating system may still warn the first time one runs. Why provenance came first is in docs/first-release.md.

With npm

Worth knowing about, because if you are using Layover you almost certainly already have Node: the agent CLIs it supervises all ship as npm packages.

npm i -g https://github.com/KotkaZ/layover-project/releases/latest/download/layover-cli-npm-package.tar.gz

The package downloads the right prebuilt binary for your platform; nothing is compiled. It is not on the public registry yet, so the tarball URL is the install path for now.

Manual download

Every release attaches an archive per platform with a .sha256 beside it:

PlatformArchive
Linux x86-64layover-cli-x86_64-unknown-linux-gnu.tar.xz
Linux ARM64layover-cli-aarch64-unknown-linux-gnu.tar.xz
macOS Intellayover-cli-x86_64-apple-darwin.tar.xz
macOS Apple siliconlayover-cli-aarch64-apple-darwin.tar.xz
Windows x86-64layover-cli-x86_64-pc-windows-msvc.zip

Unpack it and put layover somewhere on your PATH. A sha256.sum covering every artifact is attached to the release too.

With Cargo

cargo install layover-cli                 # from crates.io
cargo install --path crates/layover-cli   # from a checkout

Do not run cargo install layover. That name belongs to an unrelated SSH tunnelling crate whose binary is also called layover, so the mistake is silent: the install succeeds, the command exists, and nothing on your PATH is the tool you wanted.

The crate is layover-cli; the binary it installs is layover.

From source

git clone https://github.com/KotkaZ/layover-project
cd layover-project
cargo install --path crates/layover-cli

Checking it worked

layover --version

Agent CLIs

Layover supervises other tools; it does not replace them. Install whichever runners your factory names, and make sure each works on its own before pointing Layover at it:

RunnerInstallCheck
Claude Codenpm i -g @anthropic-ai/claude-codeclaude --version
GitHub Copilot CLInpm i -g @github/copilotcopilot --version
OpenAI Codex CLInpm i -g @openai/codexcodex --version

Credentials reach child CLIs through the environment. Never put an API key in layover.toml — it is a file people commit.

Starting with the computer

A lights-out factory that stops at every reboot is not lights-out.

layover autostart                 # writes the file
layover autostart --show          # print it instead, to read first

That generates your platform's own artefact — a Scheduled Task on Windows, a launchd agent on macOS, a systemd user unit on Linux — and prints the single command that registers it. It does not register it for you: that touches the machine, and you should see what is being installed.

It also refuses to write anything if the factory does not load, because a service that fails at every logon is worse than no service.

What it starts is layover serve on the factory you pointed it at: the Tower, which fires its schedules and runs its queue, and the dashboard beside it.

All three run as you, never elevated and never machine-wide. Layover spawns agents that use your provider credentials, your git identity and your workspace; a system service would have none of them, or would run as root with all of them.

Verify your setup

layover validate --config layover.toml --strict

This exits non-zero if anything would stop the factory starting. It is worth running in CI over your factory definition: an unattended factory that discovers a typo three agents deep has already spent money to find out.

Why not Docker

Layover spawns agent CLIs as child processes, runs them in your workspace, and relies on your provider credentials and MCP configuration. A container would have to be handed all three, at which point it has your filesystem and your secrets and has bought you nothing. It is a local-first supervisor; run it locally.

Cutting a release

Releases are built by dist, configured in dist-workspace.toml. Tagging is the whole process:

git tag vX.Y.Z      # must match the workspace version in Cargo.toml
git push origin vX.Y.Z

That builds all five targets, generates the installers, checksums everything and publishes a GitHub Release. .github/workflows/release.yml is generated — change dist-workspace.toml and run dist init, never edit the workflow by hand.

Check the configuration without releasing anything:

dist plan