@kilogent/runner-dev
v0.5.13
Published
Kilogent's internal server runner — leases the agent jobs Kilogent's scheduler places on this server and runs each as a sandboxed headless agent session. Not for customer installation.
Readme
@kilogent/runner
Kilogent's internal server runner. It runs the agent jobs of Kilogent workspaces on Kilogent's own servers.
This is not something a customer installs. A workspace never has machines: it asks for work, and Kilogent decides which of its servers runs it (PRD §15.89). There is no customer enrolment, no approval and no per-workspace setup. If you are a Kilogent customer, there is nothing here for you to do.
A server is set up by the command the admin console prints for it (see Adding a server). On a Linux server, as root:
apt-get update
apt-get install -y --no-install-recommends nodejs curl ca-certificates
curl -fsSLo kg.tgz https://registry.npmjs.org/@kilogent/runner/-/runner-<version>.tgz
echo "<sha512 from the console> kg.tgz" | sha512sum -c
tar xzf kg.tgz && node package/dist/provision-root.mjs --project <projectId> --api-key <webApiKey>How it works
key file ──exchangeFleetKey──▶ the server's own session (no workspace in it)
heartbeat every 30 s ──▶ slots, memory budget, pinned version, which leases are still ours
wake-up signal / a freed slot / every 15 s ──▶ leaseJobs
each lease ──▶ its own Firebase app, signed in with a ONE-JOB PASS ──▶ the agent session ──▶ app deleted- The backend places, the server leases. The scheduler puts each queued job on one server. A server can only lease the jobs placed on itself, and each lease carries a one-job pass.
- The pass is the whole authority for a job. Progress, transcript, finalize, notes, the credit meter, the AI gateway key, GitHub, MCP connections and the Workspace MCP bearer all use it. It can write only its own job, its own task or chat, and its own agent's status.
- A job goes back to the queue only through the backend (
returnLease): a retry, a release, a usage limit, or a shutdown. - It stops itself before the backend gives up on it. With no accepted heartbeat for
staleServerMs − 30 s(60 s by default), or when a heartbeat is refused, it aborts every session and writes nothing more for them. The backend requeues or fails those jobs by its own rules.
Which package
| Package | Command | Project |
| --- | --- | --- |
| @kilogent/runner | kilogent-runner | production (kilogent-crew-prod) |
| @kilogent/runner-dev | kilogent-runner-dev | development (lumi-afb7d) |
They install side by side with different command names, config directories and service labels.
Adding a server
- In the admin console → Fleet, press Add server. It shows a one-time enrolment code (valid for 30 minutes) and the one command for a Linux server or the dev Mac.
- Run that command on the machine and paste the code when asked.
- Linux, as root: it downloads the pinned release, checks its sha512, and runs
node package/dist/provision-root.mjs. That creates the service user, installs Node, Docker, gVisor and the session firewall, installs the runner in the user's own prefix, enrols, and starts the service.--planshows what it would do and changes nothing. - The dev Mac, as the runner user:
npx --yes @kilogent/runner-dev@<version> provision. Before it, install Node 22 and Docker Desktop, open Docker Desktop once, and set it to start when you sign in. The command installs the runner into~/.local, enrols and installs the LaunchAgent; the image is pulled by the server itself. The Mac warnings on the Fleet page (FileVault and automatic login, an administrator account, cloud logins in the account) are advice for a dedicated machine and do not stop work.
- Linux, as root: it downloads the pinned release, checks its sha512, and runs
- The server makes its own key; only its hash leaves the machine. If it enrolled from an address the server does not list, Approve it in Fleet with the last four characters of the key the server printed.
kilogent-runner doctor and the Fleet page show the same list of what is not ready yet, each with its fix.
Retry sandbox in the console makes the server check again.
A lost, damaged or rotated key is replaced the same way, never by hand: press New enrolment code on the
server's row and run the command it prints. That command ends in --re-enrol, so a machine that already has a
key enrols again and replaces it. The old key keeps working until then. To cut it off sooner, disable the server,
and enable it again just before you run the command: a code used while the server is disabled is refused.
Disabling a server in the console revokes its sessions and recovers its jobs. The daemon stops its sessions, keeps retrying the exchange with backoff, and takes work again once it is enabled.
Commands
| Command | What it does |
|---|---|
| provision --project <id> --api-key <key> [--code-stdin] [--re-enrol] | Set up the dev Mac as this user. A Linux server uses dist/provision-root.mjs as root. --re-enrol replaces an existing key with the code. |
| enrol --project <id> --api-key <key> [--replace] | Enrol with a one-time code read from stdin; the server makes its own key. --replace gives a server that has a key a new one, and puts the old one back if the code is refused. |
| connect --key-file <path> --project <id> [--api-key <key>] | Make this machine a Kilogent server from an existing key file. |
| doctor [--fix] | The readiness list with each fix, and the key exchange, engines and service. Non-zero exit only for what stops work. --fix repairs the key file's mode. |
| start | Run the daemon in the foreground. |
| service install / uninstall / restart / status | Run the daemon as an OS service. restart, and install over a running service, let running jobs finish first; --now does not wait. |
| status | What the daemon last wrote about itself (<configDir>/fleet-state.json): phase, heartbeat, slots, running jobs, engines, pin. |
| logs [-n N] [-f] | The daemon's rotating log file. |
| engine list / install / uninstall | The engine CLIs sessions run on. |
| update [--check] [--dry-run] | Install the latest published version by hand. |
| config list / set <key> on\|off | notifications, keepAwake, autoInstallEngines. |
| uninstall [--purge] | Remove the service, then print the npm rm -g step. --purge also deletes the config directory — and the key file only if it lives inside it, which the confirmation says. |
Global flags: --json, -y/--yes, --no-color.
Everything that decides what a server does — how many jobs it runs, its memory budget, draining, which version the fleet runs, which workspaces are rolled out — is set in the admin console, not here, and reaches the server with its heartbeat.
The sandbox
Every Kilogent server runs every workspace's jobs, so each session runs in a container from the image its release names, by digest, pulled with a short-lived token the server asks for over its own fleet session. A server takes no work until it has pulled that image and a probe container has proved a session can run.
On Linux the runner's user cannot reach Docker at all: every session goes through a root-owned launcher, under gVisor, on a network that cannot reach the host, the cloud metadata service or private addresses. The dev Mac runs sessions with Docker Desktop and claims no such boundary.
Where the console turns it on (§15.92), a session starts at a small memory limit and the runner raises it while the session runs, up to a max set in the console: the root launcher does it on Linux, the daemon itself on the Mac. The heartbeat reports the memory this server has for sessions and what its sessions really use, and the backend places work by those numbers. A session stopped at its max fails its job with a sentence saying so; one stopped below its max goes back to the queue and runs again from its max.
A session runs directly on the machine only in a local emulator stack (both FIRESTORE_EMULATOR_HOST and
FIREBASE_AUTH_EMULATOR_HOST set).
Engines
The daemon installs every engine it has an installer for when it starts, reports each engine's state
on every heartbeat, and installs one on demand when a lease needs it. A binary given by
CREW_<ENGINE>_BIN is the operator's: it is reported as unmanaged and never installed over. Deep
Agents has no installer; point CREW_DEEPAGENTS_BIN at it.
Which version is installed comes from crewConfig/engines. If a new version breaks a job, the
daemon puts the known-good version back, runs the job again, and — only if that works — reports the
version so no other server installs it.
The pinned version
The console pins one exact runner version for the fleet, and records npm's integrity for it. A server whose version differs checks that npm still gives the pinned bytes, pulls and probes the next release's image while it keeps working, and only then drains (finishes its jobs, takes no new ones), installs that exact version and exits so the service restarts it. The pin reaches a few servers at a time, so the fleet never stops together. When a server cannot move, the reason is shown in the console.
Shutting down
SIGTERM aborts every session and hands each job back with its retry unused, then sends a last heartbeat that takes the server out of placement at once. Whatever did not get back within the grace period, the backend recovers.
Uninstalling
Remove the service before the package, or the service keeps restarting a binary that no longer exists:
kilogent-runner uninstall
npm rm -g @kilogent/runnerEnvironment variables
| Var | Effect |
|---|---|
| CREW_SANDBOX_IMAGE | A locally built session image, read only in a local emulator stack. A server runs its release's image. |
| CREW_SANDBOX_RUNTIME / CREW_SANDBOX_NETWORK / CREW_SANDBOX_USER | Container runtime, network and user when Docker is used directly (the dev Mac, a local stack). |
| CREW_<ENGINE>_BIN | An engine's binary, e.g. CREW_CLAUDE_BIN, CREW_DEEPAGENTS_BIN. |
| KILOGENT_RUNNER_HOME | Config and log directory (default ~/.kilogent-runner). |
| CREW_FUNCTIONS_URL / CREW_MCP_URL | Override the Functions and Workspace MCP endpoints (emulators, e2e). |
| CREW_NO_NOTIFY / CREW_NO_POWER | Turn off desktop notifications / sleep inhibition. |
| KILOGENT_RUNNER_REGISTRY | npm registry for update (default https://registry.npmjs.org). |
License
MIT — see LICENSE.
