Reliable application upgrades, run by an independent installer.
K is for software you distribute yourself to machines nobody operates: desktop agents, background services installed by curl | sh, CLIs that update themselves. A failed upgrade there means the product silently stops and nobody can log in to fix it.
If a package manager, container image or fleet orchestrator already owns your installation, that manager owns upgrades too. Your adapter identifies that ownership so K can defer; you probably do not need K.
Why upgrading is non-trivial
The machine is remote and nobody operates it. An upgrade has to be triggered from far away, stop the running service, start the new one, and keep working while the service is down, because the service is the only thing anyone can reach. If the new version does not start, the old one has to come back on its own; nobody can log in to put it back. Replacing the file proves nothing about whether the service came back.
So the upgrader cannot live inside the application, and every step has to be journaled: an installer that dies halfway, or a machine that reboots mid-upgrade, must be settled by the next installer that runs, not by a person.
What K promises
K stages verified bytes in a second slot, stops the service, starts and probes the candidate, then commits or restores the previous executable. A durable journal lets a later installer recover interrupted work. An upgrade ends in exactly one of three states:
Promoted
The candidate answered the probe with the right version, a new pid and a new start id. Experiment became stable.
Rolled back
The candidate failed before the point of no return. Stable was never touched and is running again.
Unresolved
Bounded recovery could not settle it. Evidence and a verified way to retry are preserved; nothing is reported as success.
K refuses to guess. It never clears a live owner's lock, overwrites an incomplete stable slot, terminates a process by a recorded pid, or reconstructs missing history. It rolls back executables, not application data. Hashes check integrity; your distribution channel establishes trust.
What the installer adds
K is the transaction. The installer around it, built from K and your adapter, is what install.sh, your application's self upgrade and a remote request all launch. It outlives the application it replaces, runs when the application cannot start, and decides everything K does not: fresh installs, adopting an installation that predates K, repairing one K cannot settle, and what to say and ask in each case, attended or not.
That behavior is written down as the installer contract: one model for every entry, every machine and every outcome. It is advisory and still settling; the first implementation is raft-computer-installer.
What you ship
You supply the release source and the service lifecycle operations; K supplies the transaction machinery. Releases can come from a static manifest on any CDN or from a release platform such as K's sibling project Hands. The runner uses Node 24, external or bundled into a single executable.
Status
Documentation
- How an upgrade works
- The processes involved, one upgrade start to finish, what breaks, how to read the result. Read this first.
- Installer contract
- What the installer around K should do for every entry, machine and outcome. Advisory.
- Runnable example
- A service, a controller and a runner you can drive from a terminal.
- Integration
- Build, launch, observe, recover, package and distribute your own installer.
- Design
- K's normative contract: execution model, transaction, supervision, controller obligations, repair boundary.
- Reference
- Protocol, exit codes, budgets, on-disk layout.
- Test plan, harness, formal model
- What is tested, how, and what the Lean proofs cover.
- Prior art
- Rustup, Tailscale and Datadog, and what K took from each.
Incubating. TypeScript on Node 24. Apache-2.0. Contributions welcome.