Skip to content

Client and daemon

Kukeon ships as a single binary that behaves as either kuke (client CLI) or kukeond (daemon) depending on the name it's invoked as. Installing Kukeon creates a hard link so both names resolve to the same on-disk binary.

/usr/local/bin/kuke     -> kukeon binary
/usr/local/bin/kukeond  -> same binary (hard-linked), different argv[0]

cmd/main.go inspects filepath.Base(os.Args[0]) and dispatches to the matching cobra tree. See Architecture → Process Model for the dispatch itself.

The two halves

kuke — the client

kuke is the user-facing CLI. It does not directly own containerd, CNI, or cgroups; instead, it sends requests to kukeond over a unix socket. Every kuke subcommand — init, apply, create, get, delete, start/stop/kill, purge, refresh — is a client of the daemon by default.

kukeond — the daemon

kukeond is a single long-lived process that:

  • listens on /run/kukeon/kukeond.sock (configurable via --socket);
  • serves the kukeonv1 API to every kuke client;
  • holds the containerd client, the CNI manager, and the cgroup manager;
  • reconciles desired state (from manifests) against actual state (in containerd, CNI, cgroups).

It runs as the root container of the kukeond cell inside the system realm, so it's managed by the same primitives as any other workload.

In-process mode

kuke can bypass the socket and execute the operation in-process. The --no-daemon flag used to live on every subcommand; #222 retired it from the remaining daemon-routed workload commands (apply, create, run, attach, delete, kill, start, stop, log, refresh). On those commands the in-process path is now reached via:

  • KUKEON_NO_DAEMON=true in the environment, or
  • an explicit --run-path /some/path (which auto-promotes to in-process mode — the daemon ignores client-supplied run-paths, so a caller passing a non-default --run-path would otherwise silently read/write the daemon's path instead).

--no-daemon itself stays accepted on kuke init, kuke uninstall, kuke purge, and every kuke get <kind> (the get kinds were retained per a user override on the original #222 AC so the in-process escape hatch stays available for every resource lookup, not just get realm). kuke image * is daemon-independent by design (always in-process regardless of any of these knobs).

# Workload command via env var
sudo KUKEON_NO_DAEMON=true kuke apply -f cell.yaml

# Workload command via --run-path promotion
sudo kuke apply -f cell.yaml --run-path /opt/kukeon

# Commands that still expose --no-daemon directly
sudo kuke get realms --no-daemon
sudo kuke get cells --no-daemon --realm default --space default --stack default
sudo kuke purge realm myrealm --cascade --force --no-daemon

When to use it:

  • Bootstrappingkuke init runs in-process by necessity; the daemon isn't up yet.
  • Daemon is down — anything that should talk to kukeond but can't because the daemon is stopped or being rebuilt.

Trade-offs:

  • In-process mode requires root (it talks directly to containerd, netlink, cgroups).
  • There's no long-lived state holder, so every command is self-contained.
  • Two in-process commands running at the same time will race on the same on-disk state. Don't do it.

The --host flag

The client talks to the daemon over a unix socket by default:

--host unix:///run/kukeon/kukeond.sock   (default)

Other transports are on the roadmap (ssh://user@host is the intended future shape), but today only the unix transport is supported. If you need to manage a remote host, bring your own tunnel — e.g. ssh -L /tmp/kukeond.sock:/run/kukeon/kukeond.sock user@host and then kuke --host unix:///tmp/kukeond.sock ….

Parity between daemon and in-process

kuke get realms and kuke get realms --no-daemon should return identical output on a healthy host. Divergence between them is a regression — if you see it, please file a bug. The two paths share the same reconciler and data store; the only difference is who holds the process. The explicit-flag check survives on every kuke get <kind> after #222 (get realm is the one the CLAUDE.md dev-init regression guard exercises; the others are available as the same shape of escape hatch); #223 retires get realm's parity-check role once kuke status (#202) absorbs the parity contract.