Files
kandev/docs/specs/native-kandev-cli/spec.md
T
2026-06-20 19:40:15 +01:00

8.9 KiB

status, created, owner
status created owner
draft 2026-06-15 tbd

Native Kandev CLI

Why

Users start Kandev from the terminal through kandev, but the current launcher is a Node.js/TypeScript program even when Kandev is installed from Homebrew or run from a local production build. This adds a runtime dependency and extra moving parts to the most basic startup path. Users should keep the same kandev command while the launcher becomes a native executable.

What

  • kandev remains the public command for Homebrew, npm/npx, global npm installs, service units, and local development.
  • Homebrew and release bundle installs provide a native bin/kandev executable that can launch Kandev without executing the TypeScript CLI bundle.
  • The native kandev executable supports the public launcher commands users need after the web runtime merge: default run, run, start, service, --help, --version, --port, --backend-port, --verbose, --debug, and --headless.
  • Native dev mode is deferred until it can be ported with parity; the native launcher does not advertise or accept dev/--dev.
  • The native launcher starts the backend as a supervised child process by re-executing the same bin/kandev binary in a hidden backend mode.
  • The hidden backend mode is not a public command and is not shown in normal help output.
  • Backend restarts restart only the backend child process; the launcher/supervisor remains alive unless the shutdown policy requires the whole app to exit.
  • npm/npx continues to expose the kandev command through the kandev npm package. The npm package may use a minimal JavaScript shim, but that shim only resolves the platform runtime package and execs its native bin/kandev.
  • make start launches through the native apps/backend/bin/kandev start path after building local artifacts.
  • Existing service installs continue to be managed by kandev service ...; newly generated service units execute the public kandev launcher path.
  • Startup output continues to show the URL users should open, the MCP URL, database path when applicable, and log level when applicable.
  • Production run and start do not execute a Node.js web runtime; the Go backend serves the embedded Vite SPA assets.

API surface

Public CLI

kandev [--port <port>] [--verbose] [--debug] [--headless]
kandev run [--port <port>] [--verbose] [--debug] [--headless]
kandev start [--port <port>] [--verbose] [--debug] [--headless]
kandev service install|uninstall|start|stop|restart|status|logs|config [--system]
kandev --version
kandev --help

Port flags and environment variables:

  • --port and --backend-port select the public backend port.
  • KANDEV_PORT and KANDEV_BACKEND_PORT provide backend port defaults.
  • There is no production web port flag or environment variable. The Go backend serves the embedded SPA on the backend port.
  • --runtime-version is not supported by the native launcher and is rejected as a usage error.

Logging/debug flags:

  • --verbose shows backend info logs.
  • --debug shows debug logs and enables current debug environment behavior.
  • --headless skips browser opening and prints the ready URL.

Hidden backend mode

The native launcher has a private backend mode:

kandev __backend [backend flags]

This mode starts the backend server and is invoked only by the launcher/supervisor. It is intentionally hidden from public help output. Existing backend diagnostic flags may remain available in this mode for tests and direct diagnostics.

Runtime bundle

Release bundles expose this layout:

kandev/
├── bin/kandev
├── bin/agentctl
└── bin/agentctl-linux-amd64

bin/kandev is both the public launcher and the hidden backend-mode executable.

Supervisor manifest

When backend restart supervision is enabled, the launch manifest records the same executable plus hidden backend argv:

{
  "version": 1,
  "backend_executable": "/absolute/path/to/bin/kandev",
  "argv": ["__backend"],
  "cwd": "/absolute/path/to/bin",
  "env": {
    "KANDEV_SERVER_PORT": "38429",
    "KANDEV_AGENT_STANDALONE_PORT": "39429",
    "KANDEV_RESTART_ADAPTER": "supervisor"
  },
  "home_dir": "/absolute/path/to/home",
  "port": 38429,
  "mode": "run",
  "created_at": "timestamp"
}

State machine

Launcher process lifecycle:

  • idle: command parsed but no children started.
  • backend-starting: launcher has spawned kandev __backend and is waiting for backend health.
  • ready: backend is healthy and serving API, WebSocket, and SPA routes; browser may be opened unless headless.
  • restarting-backend: supervisor received a restart request and is replacing only the backend child.
  • shutting-down: launcher is terminating child processes after signal, service stop, or child exit policy.
  • failed: startup failed and the launcher exits non-zero after surfacing the actionable error.

Transitions:

  • idle -> backend-starting: user runs kandev, kandev run, kandev start, or service unit starts.
  • backend-starting -> failed: backend exits or health timeout expires.
  • backend-starting -> ready: backend health endpoint reports ready.
  • ready -> restarting-backend: backend restart adapter requests restart.
  • restarting-backend -> ready: replacement backend becomes healthy.
  • any active state -> shutting-down: signal, service stop, or non-restartable child exit.

Failure modes

  • If a required backend artifact is missing in start mode, kandev start exits non-zero with a message that tells the user to run make build.
  • If the runtime bundle is missing required files in run mode, kandev run exits non-zero and names the missing artifact.
  • If the backend does not become healthy before timeout, the launcher exits non-zero and includes captured backend output when running in quiet mode.
  • If the backend child exits unexpectedly after startup, the launcher either restarts it through the supervisor path when the exit is restart-controlled or shuts down the app with the backend exit code.
  • If npm/npx optional runtime resolution fails, the JavaScript shim exits non-zero with an actionable message explaining that the platform runtime package is missing.

Persistence guarantees

  • Service installation metadata remains durable across restarts and upgrades.
  • Supervisor manifest/control files remain under the configured Kandev home directory and are overwritten on each launch with the current executable path and backend argv.
  • The launcher does not persist child process state beyond the existing supervisor manifest. After a launcher restart, it starts a fresh backend child.
  • User data, database files, task worktrees, and backend-managed persistence remain owned by existing backend persistence behavior; the launcher migration does not change their retention.

Scenarios

  • GIVEN Kandev is installed from Homebrew, WHEN the user runs kandev --help, THEN the help output describes the public launcher commands and does not show __backend.
  • GIVEN Kandev is installed from Homebrew, WHEN the user runs kandev --version, THEN the command prints the installed Kandev version without executing the Node CLI bundle.
  • GIVEN a valid release bundle, WHEN the user runs kandev --headless, THEN the native launcher starts kandev __backend, waits for the backend to serve API and SPA routes, and prints the backend URL.
  • GIVEN a local checkout with built backend and web artifacts, WHEN the user runs make start, THEN the Makefile launches through apps/backend/bin/kandev start and does not invoke pnpm -C cli dev -- start.
  • GIVEN the backend has requested a restart through the restart adapter, WHEN the launcher receives the restart request, THEN only the kandev __backend child process is replaced.
  • GIVEN the user presses Ctrl-C while Kandev is running, WHEN the launcher handles the signal, THEN it terminates the backend child process before exiting.
  • GIVEN a new service install on Linux or macOS, WHEN the user runs kandev service install, THEN the generated service unit executes the public kandev launcher path.
  • GIVEN a user runs npx kandev@latest --help, WHEN npm has installed the platform runtime package, THEN the npm shim execs the runtime package's native bin/kandev and the user sees the same public help output.

Out of scope

  • Making npx itself Node-free.
  • Introducing kandevctl as a user-facing command.
  • Requiring a separate shipped backend binary such as kandev-backend.
  • Changing task, workflow, agent, or integration behavior after the backend has started.

Open questions

  • Should hidden backend mode be selected by the __backend argv token or by KANDEV_INTERNAL_ROLE=backend? Recommendation: __backend.
  • Should --runtime-version <tag> be ported in a later native launcher implementation or remain deprecated?
  • Should one release ship both the old Node CLI bundle and the native bin/kandev for compatibility while Homebrew/npm packaging switches over?