Skip to content

Commands

install.sh writes it to ~/.local/bin/kndl, and it runs the CLI from the install, ~/.kndl/app. It manages the installed home, KNDL_HOME or else ~/.kndl. From a checkout, bun run cli <command> runs the same CLI, on the same installed home.

CommandWhat it does
kndl onboardSet up a Hub, a Runner or both on this machine, as services.
kndl statusShow what’s installed and which services run.
kndl logsPrint the Hub’s or Runner’s log.
kndl doctorCheck the install, its configuration and its services.
kndl updateUpdate the install, rebuild, and restart its services.
kndl uninstallRemove the services, the command and the install.
kndl hubControl the Hub’s service, and print its Setup link.
kndl runnerJoin a Hub as a Runner, control the Runner’s service, and issue Runner tokens.
kndl secretsMake a HUB_SECRETS_KEY, or start over without it.
kndl loginSign the CLI in to a Hub.
kndl logoutSign the CLI out.
kndl whoamiShow which Hub the CLI is signed in to, and as whom.
kndl forwardForward a Session’s Open ports to this machine.

Every command takes --help. --version prints the commit the CLI runs from. Without an install in the home, onboard, status, logs, doctor, update and hub|runner install say how to install, and exit 1.

Terminal window
kndl onboard [flags]

Sets the machine up as a Hub, a Runner or both: prerequisites, hub.env and runner.env, builds and services. Each question has a flag, and a flag that’s given isn’t asked. Onboard keeps what hub.env and runner.env already answer, unless --reset.

FlagDefaultWhat it does
--role hub|runner|bothasksWhat the machine runs.
--reach local|lan|httpsasksWho reaches the Hub: this machine (HOST=127.0.0.1), the local network over plain HTTP (HOST=0.0.0.0), or anyone through an HTTPS proxy or tunnel.
--port <port>7777The Hub’s PORT.
--public-url <url>from --reachThe Hub’s HUB_PUBLIC_URL. local uses http://127.0.0.1:<port>, lan suggests this machine’s address, and https asks for an https: URL.
--insecure-cookiesasks, for lanlan only: sets HUB_INSECURE_COOKIES=1, so sign-in works over plain HTTP.
--dev-loginaskslocal only: sets KNDL_DEV_LOGIN=1, to sign in without GitHub.
--github-app create|manual|skipaskscreate makes the GitHub App from kndl’s manifest, in a browser. manual asks for the settings of an App you made. skip leaves hub.env as it is. create and manual need a terminal. See Set up the GitHub App.
--pair '<link>'A Runner’s pairing link, from Add a Runner or Re-pair on the Runners page. Replaces --hub-url and --token.
--hub-url <url>A Runner’s HUB_URL, for a Hub on another machine.
--token <chr_…>issued, with --role bothA Runner’s RUNNER_TOKEN, from kndl runner token.
--runner-name <name>the short hostnameThe Runner’s RUNNER_NAME.
--install-prerequisitesasksInstall what’s missing without asking. Some steps use sudo.
--no-servicesoffWrite the settings and build, but don’t install or start the services.
--linger, --no-lingerasksLinux: run loginctl enable-linger, so the services run while you’re logged out and start at boot.
--non-interactiveoffNever ask. A yes-or-no question takes its default, and any other missing answer fails, naming its flag.
--resetoffAsk every question again. Keeps HUB_SECRETS_KEY.
--move-old-dataoffRename kndl data the home holds without its env file to <name>.old-<YYYYMMDD>, without asking. Nothing is deleted.

Every yes-or-no flag has a --no- form. Onboard never asks without a terminal. It asks every question before it writes anything, so Esc or Ctrl-C at a question changes nothing, and exits 130. For a Hub with GitHub sign-in and no Owner, it ends with the Setup link.

Terminal window
kndl onboard --role both --reach local --dev-login --github-app skip
Terminal window
kndl status

Shows the commit installed, the branch it follows or that it’s pinned, each service’s state, the Hub’s URL and /health, and whether the Runner is connected. Exits 1 only when there’s no install: kndl doctor is the check.

Terminal window
kndl logs [hub|runner] [-f] [-n <lines>]

Prints the end of a service’s log, from <home>/logs/. The role can be left out when the machine runs only one.

FlagDefaultWhat it does
-f, --followoffKeep printing as it logs.
-n, --lines <lines>100How many of the last lines to print.
Terminal window
kndl logs runner -f
Terminal window
kndl doctor [--fix] [--yes]

Checks the prerequisites, the env files and their permissions, the Hub’s and Runner’s configuration, the web UI and mod builds, the services, the Hub’s health, whether the Runner reaches the Hub, and the GitHub App’s permissions. Prints ok, !! (a warning) or XX (a failure) for each, and exits 1 on a failure.

FlagDefaultWhat it does
--fixoffRepair what it can, after asking, then check again. It moves data aside only when you confirm in a terminal.
-y, --yesoffDon’t ask before each repair.
Terminal window
kndl doctor --fix
Terminal window
kndl update [--channel stable|dev] [--ref <ref>] [--no-update-runners] [--now]

Updates the install: fetches, moves it, runs bun install, rebuilds the web UI and the mod, restarts the services and runs doctor. kndl upgrade is the same command. The install’s checkout belongs to the CLI: update discards changes made in it.

FlagDefaultWhat it does
--channel stable|devthe install’s ChannelFollow stable, the latest Release, or dev, the head of main, from now on. stable never moves back: it waits for a Release that includes the commit checked out.
--ref <ref>, --branch <ref>A branch to follow from now on, or a tag or commit to pin the install to. Can’t be given with --channel.
--no-update-runnersoffOn the Hub’s machine: leave Runners on other machines on their commit. The Runner on this machine follows anyway.
--nowoffRunners updating stop their running Turns at once, rather than giving them up to ten minutes.

With neither flag, it moves along what the install follows: the latest Release on stable, the head of main on dev, or the head of the branch it follows. A pinned install stays where it is.

On the Hub’s machine, the restarted Hub asks each connected Runner to follow it to the new commit. See Keep Runners on the Hub’s commit.

Terminal window
kndl update --channel stable
Terminal window
kndl uninstall [--purge] [--yes]

Stops and removes the services, the kndl command and the install, and keeps the home’s data. Asks first. Without a terminal it needs --yes.

FlagDefaultWhat it does
--purgeoffRemove the whole home too: the Hub’s database, its key, and the Runner’s Sessions.
-y, --yesoffDon’t ask for confirmation.
Terminal window
kndl uninstall --purge
Terminal window
kndl hub install|start|stop|status
kndl hub setup-link
SubcommandWhat it does
installWrite the Hub’s service file, and start it.
startStart the Hub’s service.
stopStop it until the next start or login.
statusSay whether it runs. Exits 1 unless it does.
setup-linkPrint the Hub’s Setup link, replacing any earlier one. Refused once the Hub has an Owner. Run it on the Hub’s machine.
Terminal window
kndl hub setup-link
Terminal window
kndl runner join '<link>' [flags]
kndl runner install|start|stop|status
kndl runner token <name>
SubcommandWhat it does
join '<link>'Make this machine a Runner with a pairing link from the Hub’s Runners page. See below.
install, start, stop, statusControl the Runner’s service, as for kndl hub.
token <name>Issue a token for the Runner named <name>, replacing any token it had. Run it on the Hub’s machine. A pairing link doesn’t need it.
Terminal window
kndl runner join 'https://hub.example.com#7K2QD-M9XRT-4VBNC-H8PWE'

It’s kndl onboard with --role runner --pair '<link>'. It redeems the code for the Runner’s token, writes runner.env, installs and starts the service, and waits up to 30 seconds for the Hub to see the Runner connect. The code is redeemed before anything is built, so if a later step fails, kndl onboard finishes the job.

FlagDefaultWhat it does
--name <name>the short hostnameThe new Runner’s name: up to 63 letters, digits, dots, dashes and underscores. A Re-pair keeps the Runner’s name. See Runner names.
--hub-url <url>from the linkThe Hub’s URL, when what you give is only the code.
--install-prerequisitesasksInstall what’s missing without asking. Some steps use sudo.
--no-servicesoffWrite runner.env and build, but don’t install or start the service.
--linger, --no-lingerasksLinux: keep the service running while you’re logged out.
--non-interactiveoffNever ask.
--move-old-dataoffAs for kndl onboard.

A code that can’t be used fails before anything is written. See Troubleshooting.

Terminal window
kndl secrets key
kndl secrets reset [--yes]
SubcommandWhat it does
keyPrint a new HUB_SECRETS_KEY: 32 random bytes in base64. Changes nothing.
resetAfter losing HUB_SECRETS_KEY, clear what it encrypted in the Hub’s database, as bun run secrets-reset does. Refused while the Hub runs: run kndl hub stop first. Asks first; without a terminal it needs --yes.
Terminal window
kndl login [<hub>] [--no-browser]

Signs the CLI in to a Hub as you, approving it in a browser. Works on any machine, with or without an install. See Sign in the CLI.

Argument or flagDefaultWhat it does
<hub>the Hub in cli.jsonThe Hub’s URL. A URL without a scheme is read as https://.
--no-browseron over SSHPrint the sign-in page’s address, and ask for the code it shows, instead of waiting for a browser on this machine.

Without --no-browser, it opens the Hub’s sign-in page and waits up to 10 minutes for the browser to come back. It saves a CLI token, named after the machine’s short hostname, in cli.json, readable only by you. Signing in again replaces the token.

Terminal window
kndl login https://hub.example.com
Terminal window
kndl logout

Asks the Hub to revoke the CLI token, and forgets it. When the Hub can’t be reached, it forgets the token anyway and says to revoke the machine under CLI tokens on your Account page.

Terminal window
kndl whoami

Shows which Hub the CLI is signed in to, as whom, and on which machine. Exits 1 when it isn’t signed in, or the Hub refuses or doesn’t answer.

Terminal window
kndl forward [<session>] [<port>...] [--bind <address>]

Opens a Session’s Open ports on localhost here, as they open and close, until you stop it. It keeps the Session awake, and wakes an Asleep one you started. For anyone else’s Asleep Session, it says only its Creator can wake it. See Forward a Session’s ports.

Argument or flagDefaultWhat it does
<session>a picker of your Active SessionsThe Session: its id, the start of it (the short id the web UI shows), or its URL.
<port>...every Open portOnly these ports, each to the same port here, or <port>:<local port> to another.
--bind <address>127.0.0.1 and ::1The address to listen on, such as 0.0.0.0 for every interface.

A port taken here is skipped, naming the process that holds it, and tried again every 2 seconds. Ctrl-C stops it, exiting 0. It exits 1, saying why, when the Session goes to sleep, is archived or can’t be woken, when the CLI token is revoked, or when you lose access to the Repo. It reconnects when the Hub restarts.

Terminal window
kndl forward 3f96a2 3000 5173:8080

A Hub serves the same CLI as one binary, for macOS and Linux on arm64 and x64. See Install the CLI from a Hub.

Terminal window
curl -fsSL https://hub.example.com/cli | sh

It runs only login, logout, whoami and forward. The other commands say they need a kndl install, and exit 1.

Each run asks the Hub for its commit, waiting up to two seconds. When the Hub runs another commit, the binary replaces itself with that commit’s and runs the command again. KNDL_NO_SELF_UPDATE turns that off.

The Hub serves it with no sign-in:

RouteWhat it answers
GET /cliThe install script, with the Hub’s HUB_PUBLIC_URL origin in it.
GET /cli/version{"commit":"<commit>"}, the Hub’s commit. 503 when the Hub doesn’t run from a git checkout.
GET /cli/<os>-<arch>The binary, for darwin-arm64, darwin-x64, linux-x64 or linux-arm64, with its commit in the x-kndl-commit header. The Hub builds each the first time it’s asked for.

Run these from the root of a kndl checkout. They keep state in the dev home, ~/.kndl-dev, and the Hub’s settings in packages/hub/.env.local. See Develop kndl.

CommandWhat it does
bun run hubStart the Hub on HOST:PORT, 127.0.0.1:7777.
bun run runnerBuild the mod, then start a Runner. Needs RUNNER_TOKEN.
bun run webStart the web UI’s dev server on http://localhost:5173, passing /auth, /health, /runner/ and /ws to the Hub.
bun run web:buildBuild the web UI into packages/web/dist, which the Hub serves.
bun run cli <command>Run the kndl command from the checkout.
bun run runner-token <name>Issue a token for the Runner named <name>, as kndl runner token does.
bun run setup-linkPrint the Hub’s Setup link, as kndl hub setup-link does.
bun run secrets-keyPrint a new HUB_SECRETS_KEY. Put it in packages/hub/.env.local, and back it up with the database.
bun run secrets-reset [--yes]Clear what a lost HUB_SECRETS_KEY encrypted. See below.
bun testRun every package’s tests. KNDL_SANDBOX_IT=1 adds the ones that boot real Sandboxes.
bun run typecheckType-check every package.
bun run lintLint with oxlint. A warning fails it.
bun run formatFormat with oxfmt. bun run format:check only checks.
bun run mod:buildBuild the mod’s hook library into each plugin under packages/mod/plugins/.
bun run mod:checkBuild the mod, then validate and test each of its plugins with claude plugin.
bun run docs:devServe this site with hot reload on http://localhost:4321/kndl/.
bun run docs:buildBuild this site into packages/docs/dist, and check its links.

For when HUB_SECRETS_KEY is lost, and the Hub refuses to start without it. It needs no key.

It clears everything the key encrypted, and keeps the things that held it:

  • every Sensitive value, own and shared, keeping each Variable, which then needs a value;
  • people’s Claude credentials;
  • Installations’ header secret values, keeping each Installation;
  • OAuth Installations’ tokens and clients, so each needs connecting again;
  • the record of Test builds, and replaced values kept for redaction.

It lists what it clears, by name and never by value, and asks you to type yes. --yes doesn’t ask, and without a terminal it’s needed. It’s refused while a Hub runs on the database:

The Sensitive values can't be reset: a Hub is running on /path/to/hub.db. Stop it first.

Afterwards, make a new key with bun run secrets-key, set it, start the Hub, and enter the values again: on each Environment, on Shared variables, and on MCP. See If the key is lost.

kndl is an independent project. It is not affiliated with or endorsed by Anthropic. Claude and Claude Code are trademarks of Anthropic, PBC. About kndl