↑ subaud · local-first · MIT  

Declarative machine setup you can read before you run

kempt

One manifest describes the machine you want — kempt shows you every change before it makes it.

A config repo is one kempt.toml plus the files it references — the packages, dotfiles, and system settings that make a machine yours. kempt plan shows you exactly what it would install, link, or change; kempt apply makes only those changes, and only after you've read them. That's the point: stand up a new machine, or reproduce your setup on another, without hand-running a pile of shell scripts and hoping they still do what you remember. The primitive set is closed and there is no exec/script escape hatch — every action is a built-in, versioned primitive, so the whole plan is reviewable before anything on your machine changes.

what it's for

You should be able to read a setup before you run it.

Machine setup today is imperative: a dotfiles installer, a bundle file, a shell script you pipe into sh and hope. You run it and find out what it did afterward — there is no honest way to read the full set of changes first, because the script decides as it goes. kempt inverts that. The setup is declarative — a manifest of the state you want, not a sequence of commands — so kempt can inspect the machine, compute the difference, and show you the exact plan before it touches anything. Nothing changes until you approve the diff.

declarative, not imperative

The manifest describes the end state — this software present, these files linked, this service loaded — not the steps to get there. kempt derives the steps, and derives them against your machine as it actually is right now.

plan before apply

kempt plan is read-only. It prints every delta apply would make and changes nothing. What you read is what apply does — there is no branch the plan can't see, because every action is a known primitive.

no escape hatch

There is no exec, no run, no script hook — not as a discouraged option, but as an absent one. A manifest can only invoke kempt's built-in primitives, so a plan can never hide an arbitrary command.

idempotent by contract

Every step computes current vs desired and no-ops on a match. Running apply twice is safe; converging a mostly-set-up machine is cheap; the plan is honest about how little is actually left to do.

install

Install, point it at a repo, plan, apply.

The installer downloads the latest release for your platform, verifies its checksum fail-closed, and drops the kempt binary in ~/.local/bin (override with KEMPT_INSTALL_DIR). Then point kempt at your config repo, read the plan, and apply it.

# 1. install the binary (fail-closed checksum, installs to ~/.local/bin)
$ curl -fsSL https://kempt.tools/install.sh | sh
#    or build from source:  go install ./cmd/kempt

# 2. point kempt at your config — a git repo, or a tarball URL (no git needed)
$ kempt init <repo-url>
$ kempt init https://github.com/you/dotfiles/archive/refs/heads/main.tar.gz

# 3. read the plan, then apply only what you approve
$ kempt plan
$ kempt apply

Binaries are served from the kempt.tools domain under the download family-URL contract, with GitHub releases as a durable backing store.

get started

Guide, docs and spec.