The liken command

liken is the toolkit that you use to make and to operate a deployment. It runs on your workstation, and every release includes it. You do not need the repository or a build to make a cluster. To print the full usage, run liken with no arguments. Install a cluster runs the common commands in order.

Three terms occur on this page:

liken new

liken new <directory>

Starts a deployment. The command asks a few questions and writes a directory of manifests: cluster.yaml and one file for each machine. The comments in the files describe every field. The other commands use this directory.

liken mint

liken mint <identity-dir>

Makes a new cluster identity: the certificate authorities and the join token that all the machines in one cluster share.

liken adopt

liken adopt <harvest-dir> <identity-dir>

Takes identity files that you copied from the server of an existing cluster, and arranges them as an identity directory. You can adopt the identity of any k3s cluster. Adopt an existing k3s cluster gives the steps.

liken kubeconfig

liken kubeconfig [-server URL] <deployment-dir>

Writes an administrator kubeconfig to <deployment-dir>/identity/kubeconfig: the credential that kubectl uses to administer the cluster. The server address comes from the endpoint: in the deployment’s cluster.yaml. Pass -server when your machine reaches the cluster at a different address.

liken approve-reboot

liken approve-reboot [-server URL] <deployment-dir> <machine>

Reports what a machine waits for, and grants it one disruption. A machine whose rebootPolicy is Manual stages each change and waits. This command reads the machine’s status.pending, prints each waiting change, and writes the liken.sh/approve-disruption annotation with the staged change’s hash. The machine then takes the same path an Auto machine takes: it waits for the cluster’s turn, drains, and applies the change with the smallest disruption it needs. For a credentials change that disruption is a k3s restart, not a reboot.

The grant is one-shot. Once the change applies, its hash is no longer pending, and the next change hashes differently, so a stale annotation approves nothing. Running the command twice writes the same annotation. When two changes are pending, the command approves the reboot-class one, because a reboot applies every staged change. When nothing is pending, it reports that and writes nothing.

liken request-reboot

liken request-reboot [-server URL] <deployment-dir> <machine>

Asks a machine to reboot when no change asks it to. Every other reboot that liken performs applies a staged document, so a machine that agrees with every document it was given has no way to reboot, and it has no shell for a person to use. Two cases need one anyway: a kernel driver that bound the wrong device, which releases it only at boot, and a machine you are experimenting on. The command writes the liken.sh/request-reboot annotation, valued with the identity of the boot that is running now.

The request skips none of the cluster’s coordination. The machine waits for the cluster to grant it a reboot turn under spec.disruption , cordons its node, and drains its workloads, the same as a machine applying a staged change. The two policies control only the approval:

Nothing is staged, so the machine comes back on the documents it already runs. The reboot promotes no system slot and proves no release.

The request is one-shot, and nothing has to clear it. It names the boot it was written for, so the boot that comes back is a boot the annotation does not name. The RebootRequestHonored condition then reads True again. Run the command a second time and it names the new boot.

The annotation is the whole interface, so kubectl alone can write it. The machine reports the value to use in the same RebootRequestHonored condition:

kubectl describe machine <name>
kubectl annotate machine <name> liken.sh/request-reboot=<identity>

liken kubectl

liken kubectl [-server URL] <deployment-dir> [args...]

Runs the kubectl from your PATH against the deployment’s cluster. The command writes the admin kubeconfig (see liken kubeconfig ), sets KUBECONFIG, and hands the terminal to kubectl. Everything after the deployment directory goes to kubectl unchanged.

liken stern

liken stern [-server URL] <deployment-dir> [args...]

Runs the stern from your PATH against the deployment’s cluster, the same way liken kubectl runs kubectl. stern tails the logs of many pods at once.

liken flux

liken flux [-server URL] <deployment-dir> [args...]

Runs the flux from your PATH against the deployment’s cluster, the same way liken kubectl runs kubectl. liken plants the Flux engine when the cluster declares the flux feature, so this is the command that inspects it.

liken layer

liken layer <manifests-dir> <identity-dir> <output.cpio>

Packs your cluster’s part of the operating system into one small archive: your cluster manifest, your machine manifests, and your identity.

liken fetch

liken fetch [-digest sha256:<hex>] <source-url> <version|latest> <channel-dir>

Downloads a published release from a channel into a local channel directory, and verifies every artifact against the release document. To take the version that the channel names as the newest, give latest. -digest pins the release document to a known digest, which completes the trust chain.

liken media

liken media <release-dir> <deployment.cpio> <output.cpio>

Builds a bootable install image from a downloaded release and your deployment layer. Machines install themselves from it. Use this form for direct-kernel boots, for example QEMU or PXE.

liken stick

liken stick [-console ttyS0] <release-dir> <deployment.cpio> <output.img>

Builds the disk image for the USB install stick: one stick for the full deployment. Boot the stick, select an entry, and obey the console.

The menu holds two entries for each machine in the deployment, in the order of the machine names, and one entry for the stick itself:

install as big
wipe and reinstall as big
install as little
wipe and reinstall as little
liken hardware report

install as <name> uses blank disks only. wipe and reinstall as <name> erases every disk that the manifest of that machine declares, then installs. The report entry is last in the list because it applies to no machine. It describes the hardware of the machine in front of it, and it changes no disk. The menu has no time limit, because every entry writes to a disk or asks for a person. A machine that stays at the menu does nothing until a person selects an entry.

-console is repeatable. It adds a console= argument that the machines keep permanently. Use it to install a machine that has no screen: the menu and all the messages also go to that port.

liken bundle

liken bundle [-slot-size 1Gi] <vmlinuz> <liken.sqfs> <boot.cpio> <microcode.cpio> <liken-cli> <systemd-boot.efi> <grub-boot.img> <grub-core.img> <licenses.md> <channel-dir> <version> [component=version ...]

Lays out a release: it copies the artifacts into the channel and writes the release.yaml that names each one by its digest. The project’s own release workflow runs this command. A deployment does not need it.

liken serve

liken serve <channel-dir> [address]

Shares a release channel over plain HTTP, and records each request in a log. The address defaults to :8017.

liken index

liken index -source <url> <output-dir> < keys

Renders the index of a channel: a front page that lists every release, a page for each release, a page for the source mirror, and the versions.yaml document. Give the channel’s object keys on standard input, one key per line. The command reads each release document from the channel at -source, and writes the pages into the output directory. The contents of that directory belong at the root of the channel, because the pages link from the root.

The project’s own release workflow runs this command. A deployment does not need it.

The pages hold no information of their own. Each one is a view of a document that the channel already serves, and no machine reads a page. To repair a page, run the command again over the same channel.

The operator plugins

An operator gives a cluster a capability, and a short command uses it: capture a sink, pair a controller, enrich a library. kubectl liken <domain> <verb> reaches each operator’s command.

kubectl dispatches by longest prefix. For kubectl liken audio capture room, kubectl finds kubectl-liken-audio on PATH and runs it with capture room. So each operator ships one binary named kubectl-liken-<domain>, and the two-layer command needs no code of its own.

kubectl-liken is the liken toolkit under a second name. It owns the plugins group, and it walks the same prefix, so three commands reach the same binary:

You install the base binary the normal way, from a release download or a package, because it is the thing that reaches the cluster. You install the per-operator CLIs from the cluster, with plugins sync.

The plugins group

liken plugins sync   [-server URL] <deployment-dir>
liken plugins list   [-server URL] <deployment-dir>
liken plugins remove <domain>

plugins sync installs one CLI per operator. It lists the workloads that carry the cli.liken.sh/plugin label across the cluster’s Deployments, DaemonSets, and StatefulSets, reads each one’s operator image and its version tag, and pulls the matching -cli image into ~/.liken/plugins/bin. The -cli images are built for linux/amd64 only, so on a workstation of another architecture plugins sync stops with an error and installs nothing. The CLI comes from the same version as the running operator, so the two never drift. The command is idempotent: a second run installs the same versions over the same files.

plugins list reports each installed CLI’s version and the operator version it faces, and marks a CLI whose version has drifted from its operator. It also names an operator that runs in the cluster with no local CLI, so a cold start (kubectl liken audio with no plugin, which kubectl reports as “not found”) has a place to look.

plugins remove <domain> deletes one installed CLI.

Five domains ship a CLI today: audio, bluetooth, display, library, and media. Each one’s own site documents its verbs. The first cut:

Each capture verb is a thin client over its operator’s stream API. It authenticates with the credential you already hold: the API verifies your kubeconfig client certificate against the cluster’s client authority, or it accepts a bearer token. A capture needs no in-cluster routing, so it works from a workstation over one port-forward.

Install the plugins

Install the base binary from a release or a package. It is liken, and it answers to kubectl-liken as well. Then pull the CLIs the cluster’s operators ship:

liken plugins sync <deployment-dir>
installed kubectl-liken-audio from ghcr.io/liken-sh/audio-operator-cli:2026.09.03-007
installed kubectl-liken-media from ghcr.io/liken-sh/media-operator-cli:2026.09.03-007
export PATH="/home/you/.liken/plugins/bin:$PATH"

Add ~/.liken/plugins/bin to PATH. plugins sync prints the line to add when the directory is not on PATH yet. kubectl and the base binary both find the CLIs there.

Now the command reaches the operator. One capture, a sink’s sound to a file:

kubectl liken audio capture living-room --format flac > living-room.flac

Tab completion

Completion is a step apart from plugins sync, because the shell reads it from its own files, not from the plugin directory.

Turn on kubectl’s completion first, because the plugin completion builds on it:

source <(kubectl completion bash)

Install the base binary’s completion, which serves liken and kubectl-liken:

liken completion bash > ~/.local/share/bash-completion/completions/liken

Install each operator CLI’s completion, one file per domain:

kubectl-liken-audio completion bash \
  > ~/.local/share/bash-completion/completions/kubectl-liken-audio

A kubectl_complete-liken-<domain> shim on PATH enables kubectl liken <domain> <TAB>. Completion of an object name (a sink, a display, a Player, a peripheral, a library) reads the cluster read-only, and it honors --context and --namespace.

Maintain the plugins

An operator upgrade moves the operator to a new version, and the CLI that faces it must move with it. Re-run plugins sync after every operator upgrade:

liken plugins sync <deployment-dir>

plugins list shows the state, and marks a CLI whose version has drifted from its operator:

liken plugins list <deployment-dir>

liken version

liken version

Prints the version of the toolkit.