# Build from source

Building `kuke` and `kukeond` from a local checkout is the normal workflow when contributing to Kukeon or iterating on the daemon.

## Requirements

- Go (see `go.mod` for the required version)
- `make`
- `docker` (only needed when you want to rebuild the `kukeond` container image)
- `ctr` (shipped with containerd)

## Build the binaries

```bash
git clone https://github.com/eminwux/kukeon.git
cd kukeon

# Build kuke. The daemon binary is the same binary argv[0]-dispatched, so we
# link kukeond to kuke after the build.
rm -f kuke kukeond
make kuke
ln -sf kuke kukeond
```

`make kuke` writes the binary into the repository root.

## Build `kukebuild` (for `kuke build`)

[`kuke build`](../cli/kuke-build.md) is a thin shim that locates the `kukebuild` binary on `PATH` and exec's it. `kukebuild` is **not** part of the release artifacts — building it from source is currently the only way to obtain it, and a `kuke build` without it on `PATH` fails fast with `errdefs.ErrKukebuildNotFound`:

```bash
make kukebuild
sudo ln -sf "$(pwd)/kukebuild" /usr/local/bin/kukebuild
```

`make kukebuild` writes the binary into the repository root (it lives in its own Go module under `cmd/kukebuild/`); the symlink puts it on `PATH` so `sudo kuke build` can resolve it.

## Run against a local binary

For one-off tests you can run the binaries from the checkout:

```bash
sudo ./kuke init
sudo ./kuke get realms
```

## Rebuild the kukeond container image

`kuke init` bootstraps a `kukeond` cell from a container image. For iterating locally, you can build the image, load it into the right containerd namespace, and point `init` at it.

!!! warning "Namespace must exist before `ctr images import`"
`ctr images import` needs the target namespace to already exist; otherwise the import succeeds silently but nothing lands in the namespace, and the next `kuke init` will fail to find the image.

```bash
# 1. Create the kuke-system containerd namespace (either by running kuke init
#    once, or explicitly):
sudo ctr namespaces create kuke-system.kukeon.io

# 2. Build the container image. VERSION only affects the embedded kuke --version string.
docker build --build-arg VERSION=v0.0.0-dev -t kukeon-local:dev .

# 3. Load it into the kuke-system namespace.
docker save kukeon-local:dev | \
    sudo ctr -n kuke-system.kukeon.io images import -

# 4. Verify.
sudo ctr -n kuke-system.kukeon.io images ls | grep kukeon-local

# 5. Bootstrap against the local image.
sudo ./kuke init --kukeond-image docker.io/library/kukeon-local:dev
```

## Iterate on the daemon

To iterate after a code change, tear down the kukeond cell (user data under `/opt/kukeon/default/**` is left intact) and rebuild:

```bash
sudo kuke kill kukeond \
    --realm kuke-system --space kukeon --stack kukeon --run-path /opt/kukeon
sudo kuke delete cell kukeond \
    --realm kuke-system --space kukeon --stack kukeon --run-path /opt/kukeon
sudo rm -f /run/kukeon/kukeond.sock /run/kukeon/kukeond.pid

# Rebuild, reload, re-init
make kuke
docker build --build-arg VERSION=v0.0.0-dev -t kukeon-local:dev .
docker save kukeon-local:dev | sudo ctr -n kuke-system.kukeon.io images import -
sudo ./kuke init --kukeond-image docker.io/library/kukeon-local:dev
```

See [Guides → Local development](../guides/local-dev.md) for the full dev loop.

## Tests

```bash
# Unit tests
go test ./...

# End-to-end tests
make e2e
```

`make e2e` needs root, a running docker daemon, and standalone containerd at `/run/containerd/containerd.sock` (the same prerequisites `make dev-init` calls out under [Guides → Local development](../guides/local-dev.md)). Both supported paths work: a clean host where the suite owns `/run/kukeon/`, and a nested run inside a kukeon-managed `kukeon-dev-root` cell where each test auto-derives its own socket from `--run-path <tempdir>` so the parent dev cell's `/run/kukeon/` plumbing is untouched (see [`docs/dev-init.md`](https://github.com/eminwux/kukeon/blob/main/docs/dev-init.md)).
