Skip to content

Develop kndl

Clone kndl, run it from the checkout, and make a change that passes the checks. How to open a pull request is in CONTRIBUTING.md.

  • macOS or Linux, with git.
  • Bun 1.4 or newer.
  • Claude Code (claude) on PATH. bun run typecheck needs it to check the mod; it doesn’t need to be signed in.
  • tmux, for the Runner’s tmux tests. Without it, bun test skips them.
  • To run Sessions: a Mac with Apple Silicon, or Linux with KVM your user can open (add it to the kvm group), and a Claude setup token from claude setup-token, saved on your Account page.
Terminal window
git clone https://github.com/kddige/kndl.git
cd kndl
bun install

bun install also brings microsandbox’s runtime for your platform. Every command on this page runs from the checkout’s root.

CI runs these on every pull request:

Terminal window
bun run typecheck
bun run lint
bun run format:check # `bun run format` fixes it
bun test
CommandWhat it does
bun run typechecktsc --noEmit in each code package and in scripts/, and astro check in packages/docs.
bun run lintoxlint, configured in .oxlintrc.json.
bun run format:checkoxfmt, configured in .oxfmtrc.json: formatting and import order.
bun testEvery package’s tests, including the mod’s pure modules (packages/mod/src/*.spec.ts). KNDL_SANDBOX_IT=1 adds the tests that boot real Sandboxes.
bun run mod:checkBuilds the mod and runs claude plugin validate and claude plugin test on each plugin.

kndl is one Bun workspace in TypeScript, on Effect.

PathWhat it is
packages/protocolThe messages the Hub, Runners, the mod and the web UI exchange, as Effect Schemas, and which home a process keeps its state in. See Protocol.
packages/hubThe Hub: an HTTP and WebSocket server with its data in SQLite.
packages/runnerA Runner: runs each Session’s Claude Code in tmux in a microsandbox Sandbox, on its Creator’s setup token, and relays its mod’s calls to the Hub.
packages/modThe Claude Code mod each Session loads, as two plugins: hub-link reports Turns and subagents to the Hub, and hub-link-commands delivers prompts and stops (ADR 0014).
packages/cliThe kndl command. Its decisions are pure modules with tests; Host.ts and Shell.ts do the I/O. KNDL_DRY_RUN=1 prints the commands that change the system instead of running them.
packages/webThe web UI: React on Vite, with Base UI and StyleX.
packages/docsThis site: Astro Starlight.
install.shThe installer curl … | sh runs.
scripts/The PR title check and the release tooling.
GLOSSARY.md, docs/adr/The glossary and the decisions.

A checkout keeps its state apart from an install: the Hub’s database is packages/hub/hub.db, and everything else is in ~/.kndl-dev, so a checkout and an install can share a machine.

Put the Hub’s settings in packages/hub/.env.local, which bun run hub reads. Settings in your shell’s environment win over the file’s. git ignores .env* and *.pem files.

packages/hub/.env.local
KNDL_DEV_LOGIN=1
HUB_SECRETS_KEY=… # from `bun run secrets-key`

Make a secrets key once, and back it up with hub.db:

Terminal window
bun run secrets-key

Then run the Hub one of two ways:

ToRunOpen
Work on the web UI, with hot reloadbun run hub and, in another terminal, bun run webhttp://localhost:5173
Serve the built web UI, as an install doesbun run web:build, then HUB_PUBLIC_URL=http://127.0.0.1:7777 bun run hubhttp://127.0.0.1:7777

HUB_PUBLIC_URL must be the address you open: it defaults to Vite’s http://localhost:5173. Vite passes the Hub’s routes through to the Hub at HUB_URL, by default http://127.0.0.1:7777.

To sign in with GitHub instead of dev login, add the App’s settings to .env.local, as Set up the GitHub App describes, and make a Setup link to become the Owner:

Terminal window
bun run setup-link

Every setting is in the configuration reference.

On the same machine as the Hub, issue a Runner token, then start the Runner with it:

Terminal window
bun run runner-token build-box
RUNNER_TOKEN=chr_… bun run runner

bun run runner builds the mod first. The token is shown once; running runner-token again for the same name replaces it. For a Hub on another machine, also set HUB_URL.

To keep the token out of your shell history, put the settings in an env file:

Terminal window
# ~/.kndl-dev/runner.env (chmod 600)
HUB_URL=https://hub.example.com
RUNNER_TOKEN=chr_…
Terminal window
bun --env-file="$HOME/.kndl-dev/runner.env" run runner

A checkout’s Runner uses tmux socket kndl-dev and keeps Sessions in ~/.kndl-dev/sessions, so it can run beside an installed one. It never updates itself: pull the checkout to the Hub’s commit and restart it. Every setting is in the configuration reference.

To look at Sandboxes by hand, run microsandbox’s CLI from the Runner’s package:

Terminal window
cd packages/runner && bun x msb list

The web UI runs against an in-process fake Hub that plays scripted Sessions:

Terminal window
VITE_FAKE_HUB=1 bun run web # signed in
VITE_FAKE_HUB=signed-out bun run web # starting signed out

Every component in its states is at /kit. The docs’ screenshots are taken against the fake Hub.

Terminal window
bun run mod:build
claude --plugin-dir packages/mod/plugins/hub-link --plugin-dir packages/mod/plugins/hub-link-commands

mod:build bundles the mod into each plugin’s hooks/hub-link-lib.js. A running Session picks up a new build at its next start, wake or change of model.

Terminal window
bun run docs:dev # http://localhost:4321/kndl/
bun run docs:build # checks every link, too

Pages are Markdown in packages/docs/src/content/docs, written to docs/design/docs-style.md. The glossary and the decisions are rendered from GLOSSARY.md and docs/adr/: edit those. Pushes to main that touch the site deploy it to GitHub Pages.

Terminal window
bun run cli status

It manages the installed home (KNDL_HOME, or ~/.kndl), never ~/.kndl-dev.

A Release is a dated tag on main, like v2026.10.1, cut by hand. Pushing the tag runs CI and creates the GitHub Release, with notes built from the merged pull request titles. The steps are in docs/agents/releasing.md, and the reasons in ADR 0025.

Coding agents write much of kndl, often in kndl Sessions. AGENTS.md (also CLAUDE.md) is their instructions, docs/agents/ holds the workflows they follow, and .claude/skills/ the skills they use. Pull requests written with an agent are welcome; you’re responsible for what you submit.

What you seeFix
The Runner exits with a ConfigError naming RUNNER_TOKENSet RUNNER_TOKEN: Run a Runner. The Runner doesn’t read the Hub’s .env.local.
The hub-link mod isn't built: …Start the Runner with bun run runner, or run bun run mod:build first.
The Hub's web UI isn't built.Run bun run web:build and reload, or use bun run web and open http://localhost:5173.
Settings in .env.local are ignoredThe file goes in packages/hub/, not the checkout’s root. Check your shell doesn’t export the same names.
Only the web UI at http://localhost:5173 may make this requestOpen the address HUB_PUBLIC_URL names, or change it.

Everything else is in Troubleshooting.

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