# Run Kandev as a Service Install Kandev as an OS-managed service (systemd on Linux, launchd on macOS) so it auto-starts and stays running. User-mode services installed by `kandev service install` can self-update from the System → Updates page. Non-service installs and `--system` services still update manually: `npm i -g kandev@latest` or `brew upgrade kandev`, then re-run `kandev service install`. This guide assumes you've already installed kandev via [Homebrew or npm](../apps/cli/README.md#quick-start) and that `kandev` works when run interactively. > **Windows:** not yet supported. See [open issues mentioning Windows](https://github.com/kdlbs/kandev/issues?q=is%3Aissue+windows) for SCM support progress, or open a new one if there isn't one yet. ## Quick Start ```bash # Laptop / single-user — runs as you, starts when you log in: kandev service install # Linux VPS / shared box — runs at boot, no login required: sudo kandev service install --system ``` After install, kandev is reachable at `http://localhost:38429` (or `--port ` if you passed it). ## User Mode vs `--system` Mode | | **User mode** (default) | **`--system` mode** | | -------------------------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------- | | Install requires sudo | No | Yes | | Unit location (Linux) | `~/.config/systemd/user/kandev.service` | `/etc/systemd/system/kandev.service` | | Unit location (macOS) | `~/Library/LaunchAgents/com.kdlbs.kandev.plist` | `/Library/LaunchDaemons/com.kdlbs.kandev.plist` | | Daemon runs as | You | `$SUDO_USER` if invoked via `sudo`, else the current user | | Auto-starts on reboot | **Linux:** only after `sudo loginctl enable-linger $USER` (run once). **macOS:** only at next login. | Always, regardless of login state | | Survives logout / SSH disconnect | **Linux:** yes, after linger. **macOS:** no (use `--system` instead). | Yes | | Default `KANDEV_HOME_DIR` | `~/.kandev` | `/var/lib/kandev` | | Logs | `journalctl --user-unit kandev` (Linux) · `~/.kandev/logs/service.err` (macOS) | `sudo journalctl -u kandev` (Linux) · `/var/lib/kandev/logs/service.err` (macOS) | | Best for | Laptop, workstation | Headless Linux VPS, Mac mini server, shared box | **30-second rule of thumb: VPS → `--system`. Laptop → default.** Linux user-mode with `loginctl enable-linger` is functionally equivalent to system mode for a single-user VPS, but the linger one-liner itself requires sudo — so you're not avoiding sudo, just deferring it. For a VPS, `--system` is one less thing to remember after a reboot. ## Commands ```bash kandev service install [--system] [--port ] [--home-dir ] [--no-boot-start] kandev service uninstall [--system] kandev service start|stop|restart|status [--system] kandev service logs [-f] [--system] kandev service config [--system] ``` | Command | What it does | | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `install` | Writes the unit file, reloads the service manager, enables auto-start, and starts the service. Then polls `/health` for up to 30s and dumps logs if it doesn't come up. | | `uninstall` | Stops the service, disables auto-start, removes the unit file. | | `start` / `stop` / `restart` | Control the running service without touching the unit file. | | `status` | Print the OS service-manager view (systemd / launchctl). | | `logs [-f]` | Dump the last 200 lines, or stream if `-f`. journalctl on Linux; `tail` on macOS log files. | | `config` | Print the resolved paths, env vars, and whether the service is currently installed / active. Useful for diagnosis — read-only, no privileges needed. | ### Flags - `--system` — system-level install. Requires sudo. See the comparison above. - `--port ` — bake `KANDEV_SERVER_PORT=` into the unit. Defaults to 38429. - `--home-dir ` — bake `KANDEV_HOME_DIR=` into the unit. Defaults to `~/.kandev` (user mode) or `/var/lib/kandev` (`--system`). - `--no-boot-start` — Linux user-mode only. Skip the `loginctl enable-linger` hint at the end of install. - `-f`, `--follow` — only for `logs`. Stream rather than dump. ## After an Upgrade If Kandev is running as a user-mode service installed by `kandev service install`, open **Settings → System → Updates** and use **Apply update** when it appears. The button is shown only when the backend can prove it is running from a kandev-managed service unit/plist with valid service metadata. Both `npm` and Homebrew install kandev under a versioned directory (e.g. `node_modules/kandev/0.49.0/`, `Cellar/kandev/0.49.0/`). Manual upgrades replace those paths, so the unit file must be refreshed afterward. **Manual fix:** re-run install. It's idempotent. ```bash npm i -g kandev@latest # or: brew upgrade kandev kandev service install # rewrites the unit with the new paths ``` If you launch `kandev` interactively after an upgrade, it will detect a stale unit and print a one-line reminder. You can also check with `kandev service config` — the `cli entry:` and `node path:` lines tell you the paths that *would* be baked in by the next install. System services (`kandev service install --system`) do not expose UI self-update. Update them from a privileged shell, then re-run `sudo kandev service install --system`. ## Linux Boot-Start (`loginctl enable-linger`) Linux user services normally run only while you're logged in. To keep kandev running across reboots without an active SSH session, run **once**: ```bash sudo loginctl enable-linger $USER ``` After this, your user's systemd instance is started at boot by `systemd-logind`, and your enabled user units (including kandev) start with it. To disable later: ```bash sudo loginctl disable-linger $USER ``` If you'd rather not deal with linger and you're already comfortable with sudo, install with `--system` instead — it sidesteps the issue entirely. ## What's Inside the Unit File The unit hard-codes absolute paths so it works in the empty `PATH` that systemd/launchd give a fresh service. A typical Linux user unit looks like: ```ini # managed by kandev — regenerated by `kandev service install` [Unit] Description=Kandev autonomous agent platform Documentation=https://github.com/kdlbs/kandev After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=/usr/local/bin/node /usr/local/lib/node_modules/kandev/bin/cli.js --headless Environment=KANDEV_HOME_DIR=/home/alice/.kandev Environment=KANDEV_LOG_LEVEL=info Environment=PATH=%h/.local/bin:%h/.bun/bin:%h/.opencode/bin:/usr/local/bin:/usr/bin:/bin:/opt/homebrew/bin:/home/linuxbrew/.linuxbrew/bin Environment=KANDEV_RUNNING_AS_SERVICE=true Environment=KANDEV_SERVICE_MODE=user Environment=KANDEV_SERVICE_MANAGER=systemd Environment=KANDEV_INSTALL_KIND=npm Environment=KANDEV_SERVICE_METADATA=/home/alice/.kandev/service/install.json Restart=on-failure RestartSec=5s KillMode=mixed TimeoutStopSec=30s [Install] WantedBy=default.target ``` The `--headless` flag tells the CLI not to open a browser (you'll connect to it remotely or via `localhost`). The `KANDEV_SERVICE_*` variables and `/service/install.json` metadata let the backend verify that UI self-update is safe before it shows the Apply button. ## Troubleshooting ### `systemctl: command not found` / `launchctl: command not found` Kandev's service support requires either systemd (most Linux distros) or launchd (macOS). It does not currently support OpenRC, SysV init, or Windows SCM. You can still run kandev as a daemonized process with `nohup` / `screen` / `tmux`, or wrap it in your init system of choice using the launcher info from `kandev service config`. ### "service did not become healthy within 30s" The install succeeded (unit file written, service told to start) but kandev's HTTP `/health` endpoint never responded. `install` dumps the last 50 lines of logs when this happens — common causes: - Port already in use → pass `--port `. - Cold-disk + slow first launch → re-run `kandev service install`; the second start is usually fast enough. - Missing dependency on the unit's `PATH` (e.g. `git`, `docker`) → install the missing tool and `kandev service restart`. ### The unit warns about a "file that doesn't look like a kandev-managed file" `kandev service install` refuses to silently clobber files it didn't write. If you (or another tool) had previously put something at `~/.config/systemd/user/kandev.service` or the equivalent on macOS, install will: 1. Copy the existing file to `.bak` 2. Write the kandev unit in its place 3. Print a `WARNING` line so you notice Inspect the `.bak` if you're not sure what was there. ### Service runs as `root` when you wanted it to run as your user This happens with `--system` if `SUDO_USER` isn't set (e.g. you logged in as root directly rather than `sudo`'ing). Either run install via `sudo` from your normal user, or hand-edit the `User=` (Linux) / `UserName=` (macOS) directive in the unit file. ### After upgrading, the service silently keeps running the old version The OS service manager keeps running whatever `ExecStart` it has — it doesn't know about npm/brew upgrades. For managed user services, use **Apply update** on the Updates page. Otherwise, **always re-run `kandev service install` after an upgrade** so the unit picks up the new paths, then `kandev service restart` to pick up new code. ## Updating: TL;DR ```bash # Option A: managed user service # Use Settings -> System -> Updates -> Apply update # Option B: manual / system service # 1. Update the binary npm i -g kandev@latest # or: brew upgrade kandev # 2. Refresh the unit file (rewrites paths to point at the new version) kandev service install # add --system if that's what you used originally # 3. (install does this automatically) Verify it came back up kandev service status ``` ## Uninstalling ```bash kandev service uninstall # or: sudo kandev service uninstall --system ``` This stops the service, removes its unit/plist, and reloads the service manager. Data in `~/.kandev` (or `/var/lib/kandev`) is left intact — delete it manually if you want a clean slate.