Applying manifests¶
kuke apply is the declarative interface: write a YAML file describing the resources you want, and Kukeon reconciles the host to match. It's the preferred way to create or update anything that isn't a one-off CLI operation.
The basics¶
Accepts a single path, or - to read from stdin:
The manifest can contain one or more resource documents separated by ---:
apiVersion: v1beta1
kind: Space
metadata:
name: blog
spec:
realmId: main
---
apiVersion: v1beta1
kind: Stack
metadata:
name: wordpress
spec:
id: wordpress
realmId: main
spaceId: blog
---
apiVersion: v1beta1
kind: Cell
metadata:
name: wp
spec:
id: wp
realmId: main
spaceId: blog
stackId: wordpress
containers:
- id: nginx
image: docker.io/library/nginx:alpine
kuke apply creates resources in dependency order — parents (realm → space → stack) before children (cell → container), regardless of the order they appear in the file.
What apply does¶
Per resource, the outcome is one of:
created— the resource didn't exist; it was created.updated— the resource existed but its spec differs; it was reconciled. Printed diffs follow.unchanged— the desired state already matches; nothing to do.failed— reconciliation failed; the error is printed. Processing continues for other resources, and the command exits non-zero at the end.
Example output:
Output formats¶
With -o json or -o yaml, apply emits a structured report instead of the human-readable one.
Idempotence¶
apply is idempotent: running the same manifest twice is safe. The second run should report unchanged for every resource.
Nesting and ordering¶
Today, each resource is a separate document. There is no "apply an entire stack as one tree" mode — you write the stack, then the cells under it, either in the same multi-doc file or separately.
Cross-file apply:
sudo kuke apply -f realm.yaml
sudo kuke apply -f space.yaml
sudo kuke apply -f stack.yaml
sudo kuke apply -f cell.yaml
or multi-doc:
kuke apply always requires the daemon¶
kuke apply routes through kukeond and has no in-process fallback. After #566/#588 the workload verbs (apply, create *, run, attach, delete *, kill *) route through the daemon-only client, which ignores kukeon/noDaemon — so KUKEON_NO_DAEMON=true and the --run-path promotion do not reach an in-process branch for apply. If the daemon is down, bring it back with kuke daemon start (or kuke init from scratch) before applying.
The in-process escape hatch survives only for the promotable callers — get *, purge *, log, refresh, restart, start, stop, doctor cgroups, plus the bootstrap init/uninstall. See Client and daemon for the broader story.
Parameterized cell blueprints¶
kuke apply -f consumes a fixed manifest — the file you ship is the spec the daemon reconciles to, with no substitution layer in between. When you need the same cell shape with different values per invocation (image tag, command, mount paths), apply a CellBlueprint to the daemon and run it with kuke run --from-blueprint instead of editing the YAML each time.
A blueprint is a daemon-stored, scoped resource. It declares its variable inputs alongside the cell template:
apiVersion: v1beta1
kind: CellBlueprint
metadata:
name: shell
realm: default
spec:
parameters:
- name: IMAGE
description: container image to run
default: alpine:latest
- name: CMD
description: command to exec
required: true
cell:
containers:
- id: shell
image: ${IMAGE}
command: ["/bin/sh", "-c", "${CMD}"]
Apply it once:
Then kuke run --from-blueprint shell materializes one cell with a unique name (<prefix>-<6hex> by default, prefix = spec.prefix or metadata.name; override with --name) and resolves each ${KEY} reference in the body. Resolution order, highest first:
--param KEY=VALUEon the CLI (repeatable)- Values from
--param-file <path>(oneKEY=VALUEper line,#starts a comment) - The parameter's
defaultin the blueprint - The
kukeprocess env (os.LookupEnv) - Required + unset → error; non-required + unset → empty string
# Use defaults / env / required errors
kuke run --from-blueprint shell --param CMD="echo hi"
# Override the image too
kuke run --from-blueprint shell --param IMAGE=alpine:edge --param CMD="/bin/sh"
# Load a batch of values from a file, with a CLI override on top
kuke run --from-blueprint shell --param-file ./shell.env --param IMAGE=alpine:edge
--param, --param-file, and --name are rejected when combined with -f (file mode is not a blueprint and has no parameter declarations); --param/--param-file are also rejected with --from-config (a CellConfig already binds its own values — use --env for a per-cell override there). The substituted body is what reaches the daemon — there is no parameter layer in the manifest API itself.
To additionally fill a blueprint's structural repo/secret slots, wrap it in a kind: CellConfig and use kuke run --from-config <cfg>; see kind: CellConfig. Both --from-blueprint and --from-config stamp a fresh <prefix>-<6hex> cell per invocation (pin one with --name).
See kuke run for the full flag surface.
See also¶
- Manifest Reference — the full schema of every resource
- CLI Reference → apply — every flag on
kuke apply - CLI Reference → run —
-f(file),--from-blueprint, and--from-configmodes, including parameter handling - Tutorials → Hello-world cell — a worked example end-to-end