kurel CLI

kurel CLI Reference

Go Reference Go Reference

kurel is an OAM-native package manager for Kubernetes. Packages are described with a launcher Application document (app.yaml) and an optional parameter schema (kurel.yaml); build-time parameter substitution produces static, GitOps-ready Kubernetes manifests.

This package defines the kurel command tree (NewKurelCommand) and entry point (Execute). The completion and version subcommands are provided by pkg/cmd/shared.

Command tree

kurel
├── build <app.yaml|package-dir>   Build Kubernetes manifests from an OAM Application
├── config                          Manage kurel configuration
│   ├── view                        View current configuration
│   └── init                        Initialize a configuration file (.kurel/config.yaml)
├── completion [bash|zsh|fish|powershell]   Generate a shell completion script
└── version                         Print version information

kurel build

Builds static manifests from an Application (a path to app.yaml, or a directory containing app.yaml and optionally kurel.yaml) plus a platform ClusterProfile. Output goes to stdout by default, or to a directory with --output.

All built-in component and trait handlers are registered automatically (via builtinComponentHandlers() / builtinTraitHandlers(), which return the library’s exported sets from pkg/oam/builtin/registry, unfiltered; testdata/builtin-registries.txt pins the set, TestBuiltinRegistries_TypesUnchanged), alongside the built-in lowering rules: the trait-position ones (builtinTraitLoweringRules() — currently just expose, registered via RegisterBuiltinTraitLowering rather than RegisterBuiltinTrait) and the component-position ones (builtinComponentLoweringRules() — worker, webservice, postgresql, helm and oci, registered via RegisterComponentLowering). worker lowers to a deployment component plus, unless topologySpread: false, a synthesized topology-spread trait. webservice lowers to a same-name deployment and service pair, deployed as one component, with the same topology-spread treatment on the deployment. Unless serviceAccountName is authored, both also emit a same-name serviceaccount member for the component’s ServiceAccount, and turn each claim a pvc volume describes into a synthesized pvc trait on the deployment member (go-kure/launcher#702), so builtinComponentHandlers() must register serviceaccount and the pvc trait handler must be registered. postgresql lowers to a cnpg-cluster (plus cnpg-objectstore, cnpg-pooler and one cnpg-database per database when authored), with a post-policy step on the cnpg-cluster for the values postgresql derives after the policy; nothing besides the rule needs registering for it. helm lowers to a helmrelease (plus a generated helmrepository, ocirepository, gitrepository or bucket for an inline source, shared within the document) or, under delivery: template, to a helmtemplate. oci lowers to an ocirepository and a fluxcd-kustomization (go-kure/launcher#784): a same-name pair deployed as one component, or, when several oci components in the document use the same artifact at the same interval, one shared ocirepository they all reference. So builtinComponentHandlers() must register ocirepository and fluxcd-kustomization, the kind-named projection of the Flux Kustomization, authorable on its own; the oci fixture under testdata/ builds the pair. The built-in application policy handlers are registered too (builtinPolicyHandlers() — dependency and placement, registered via RegisterPolicy). Every registered handler and rule declares a PropertySchema for its user-facing properties, so every authored component’s, trait’s and policy’s properties are validated against it before dispatch (a misspelt policy key such as teir fails the build). A policy type with no built-in handler — including app-dependency, which orders one application after others and has nothing to order against in a single-application build — fails with no handler for policy type. The reconciliation and health-checks policies and the fluxcd-patches and fluxcd-postbuild traits configure how Flux delivers an application, which launcher leaves to the consumer that delivers it (go-kure/launcher#781): build has no handler for them, and the no handler for policy type or no handler for trait type error says so. Policies shape the bundle tree, which kurel build’s manifest output does not include; see Policy Handlers. See Component Handlers and Trait Handlers for the full catalogue; the deployment component — the kind-named projection of appsv1.Deployment, alongside the role-named webservice and worker — the service component — the kind-named projection of corev1.Service, emitting only a Service in front of pods another component owns — the job component — a run-to-completion workload sharing the whole JobSpec-level surface with cronjob’s job template — and the security-context trait were added in this release. The topology-spread trait (launcher’s default spread constraints on any typed Deployment a component generates, from its post-policy replica count) is registered the same way. The force-replace trait (opt-in: it lets the delivering engine replace an object on an immutable-field change, e.g. so a job can be updated in place) is registered in both builtinTraitHandlers() and pkg/oam’s trait allowlist, and force_replace_build_test.go builds a job with and without it. The kind-named Flux source components — helmrepository, ocirepository, gitrepository and bucket (go-kure/launcher#347), and helmchart (go-kure/launcher#351), each emitting exactly one source CR — are registered in both builtinComponentHandlers() and pkg/oam’s component allowlist; the flux-sources fixture under testdata/ builds all five. The cnpg-cluster component — the full-fidelity, opinion-free projection of a CloudNativePG Cluster — is registered in builtinComponentHandlers() and pkg/oam’s component allowlist; the cnpg-cluster-minimal and cnpg-cluster-full fixtures build it. Its siblings cnpg-pooler, cnpg-database and cnpg-objectstore (one CloudNativePG Pooler, Database or Barman Cloud ObjectStore each) are registered the same way; the cnpg-<kind>-minimal and cnpg-<kind>-full fixtures build each. The kind components serviceaccount, persistentvolumeclaim and configmap (go-kure/launcher#702) are registered the same way. The secret trait (go-kure/launcher#786), which emits one Secret beside its component, is registered in both builtinTraitHandlers() and pkg/oam’s trait allowlist; helm_secret_values_test.go builds it authored and as the helm component’s secretValues lowering. Fixtures with the same names build each one, and the pvc-volume-claimname fixture mounts a persistentvolumeclaim through a pvc volume’s claimName.

The kind components of go-kure/launcher#790 are registered the same way. Each but secret is built by the fixture named after it, <type>-component. The table has one row per type, in the order of the types; a new kind’s row goes at its position.

typeWhat the fixture builds
alertmanagerAn Alertmanager in the build namespace, and nothing else, since the operator runs the pods. What its spec says of those pods is held to the environment policy; no capability is required to build it.
apiserviceTwo APIServices with no namespace, one named by the component, <version>.<group>, and one by objectName, each handing its group and version to a Service of the metrics namespace. Only the environment policy’s object kind rules apply to it.
artifactgeneratorTwo ArtifactGenerators in the build namespace, no Flux namespace being set for the build, one named by objectName, with a pathPattern and a source of another namespace. No capability is required to build it.
backendtlspolicyA BackendTLSPolicy in the build namespace. No capability is required of the cluster profile to build it.
certificateA Certificate in the build namespace. No capability is required of the cluster profile to build it; the certificate trait, which shares the kind’s name, still requires its own.
cilium-bgpadvertisementA CiliumBGPAdvertisement with no namespace. No capability is required to build it.
cilium-bgpclusterconfigA CiliumBGPClusterConfig with no namespace. No capability is required to build it.
cilium-bgpnodeconfigoverrideA CiliumBGPNodeConfigOverride with no namespace. No capability is required to build it.
cilium-bgppeerconfigA CiliumBGPPeerConfig with no namespace. No capability is required to build it.
cilium-cidrgroupA CiliumCIDRGroup with no namespace. No capability is required to build it.
cilium-clusterwidenetworkpolicyTwo CiliumClusterwideNetworkPolicy objects with no namespace, one with a rule for nodes under spec, one named by objectName with two rules for endpoints under specs. No capability is required to build it.
cilium-egressgatewaypolicyA CiliumEgressGatewayPolicy with no namespace. No capability is required to build it.
cilium-loadbalancerippoolA CiliumLoadBalancerIPPool with no namespace. No capability is required to build it.
cilium-localredirectpolicyA CiliumLocalRedirectPolicy in the build namespace. No capability is required to build it.
cilium-networkpolicyThe authored spec and specs. The kind refuses a policy Cilium would reject when it reads it.
cilium-nodeconfigA CiliumNodeConfig in the build namespace. No capability is required to build it.
clusterexternalsecretA ClusterExternalSecret with no namespace. No capability is required of the cluster profile to build it, and it does not read the profile’s external-secret capability, which gives the external-secret trait its store.
clusterissuerA ClusterIssuer with no namespace. No capability is required of the cluster profile to build it.
clusterroleA ClusterRole with a rule of non-resource URLs and an aggregated one. No capability is required to build it, and no environment policy restricts what it grants. TestObjectName_CollidesWithAGeneratedName holds that a component of this type and an rbac trait that names the same object are refused.
clusterrolebindingA ClusterRoleBinding with no namespace. No capability is required to build it, and no environment policy restricts what it grants. TestObjectName_CollidesWithAGeneratedName holds that a component of this type and an rbac trait that names the same object are refused.
clustersecretstoreA ClusterSecretStore with no namespace. No capability is required of the cluster profile to build it, and it does not read the profile’s external-secret capability, which gives the external-secret trait its store.
cnpg-backupTwo Backup objects in the build namespace, the second named by objectName. No capability is required to build it.
cnpg-clusterimagecatalogTwo ClusterImageCatalog objects with no namespace, the second named by objectName. No capability is required to build it.
cnpg-databaseroleTwo DatabaseRole objects in the build namespace, the second named by objectName. The fixture authors a validUntil with an offset and expects it in UTC. No capability is required to build it.
cnpg-imagecatalogTwo ImageCatalog objects in the build namespace, the second named by objectName. No capability is required to build it.
cnpg-publicationTwo Publication objects in the build namespace, the second named by objectName. No capability is required to build it.
cnpg-scheduledbackupTwo ScheduledBackup objects in the build namespace, the second named by objectName. No capability is required to build it.
cnpg-subscriptionTwo Subscription objects in the build namespace, the second named by objectName. No capability is required to build it.
csidriverEach component emits one object, named after the component unless objectName names it, with no namespace.
endpointsliceA Service named by objectName, an EndpointSlice in the build namespace whose authored kubernetes.io/service-name label holds that name as a literal, and a slice that authors only its address type.
externalsecretAn ExternalSecret in the build namespace. No capability is required of the cluster profile to build it, and it does not read the profile’s external-secret capability, which gives the external-secret trait its store.
fluxcd-alertTwo Alerts in the build namespace, no Flux namespace being set for the build, one named by objectName and reading the events of another namespace’s Kustomizations. No capability is required to build it.
fluxcd-providerTwo Providers in the build namespace, no Flux namespace being set for the build, a chat provider and a git provider named by objectName, with its three Secrets, an address, a commit status expression and a timeout of ninety minutes, written 90m0s. No capability is required to build it.
fluxcd-receiverTwo Receivers in the build namespace, no Flux namespace being set for the build, a GitHub receiver with its Secret and a generic-oidc receiver named by objectName, reconciling every labelled OCIRepository of another namespace, with an OIDC provider and an interval of two hours, written 2h0m0s. No capability is required to build it.
gatewayA Gateway in the build namespace. No capability is required of the cluster profile to build it.
gatewayclassA GatewayClass with no namespace. No capability is required of the cluster profile to build it.
grpcrouteA GRPCRoute in the build namespace attaching to a Gateway of another namespace, one rule matching a method and one splitting its traffic over two backends. No capability is required of the cluster profile to build it.
horizontalpodautoscalerA HorizontalPodAutoscaler in the build namespace, holding what was authored.
httprouteThe authored object and, unlike the trait of the same name, no NetworkPolicy allow rule.
imagepolicyTwo ImagePolicies in the build namespace, no Flux namespace being set for the build, one named by objectName and selecting from the ImageRepository of another namespace. No capability is required to build it.
imagerepositoryTwo ImageRepositories in the build namespace, no Flux namespace being set for the build, one named by objectName, with its three Secrets, an ACL that opens it to the namespaces of one team and a timeout of ninety minutes, written 90m0s. No capability is required to build it.
imageupdateautomationTwo ImageUpdateAutomations in the build namespace, no Flux namespace being set for the build, one named by objectName, committing through the GitRepository of another namespace with a signing key and pushing to a branch of its own. No capability is required to build it.
ingressThe authored object and, unlike the trait of the same name, no NetworkPolicy allow rule.
ingressclassEach component emits one object, named after the component unless objectName names it, with no namespace.
issuerAn Issuer in the build namespace. No capability is required of the cluster profile to build it.
limitrange
listenersetA ListenerSet in the build namespace. No capability is required of the cluster profile to build it.
metallb-bfdprofileTwo BFDProfile objects in the build namespace, one with every field, an authored echoMode: false among them, and one that authors nothing but its objectName. No capability is required to build it.
metallb-bgpadvertisementThree BGPAdvertisement objects in the build namespace: one that rolls addresses up, one with a service selector alone, and one that authors nothing but its objectName. No capability is required to build it.
metallb-bgppeerTwo BGPPeer objects in the build namespace, at metallb.io/v1beta2: one with its address, its timers and the Secret of its password, and an unnumbered one named by objectName, which is written with the passwordSecret: {} the upstream type always encodes. No capability is required to build it.
metallb-communityTwo Community objects in the build namespace, one with three aliases, one of them a value the writer quotes (64512:10, which YAML 1.1 reads as a base-60 number where it is not quoted), and one that authors nothing but its objectName. No capability is required to build it.
metallb-ipaddresspoolTwo IPAddressPool objects in the build namespace, one with every field, one named by objectName with its addresses alone. No capability is required to build it.
metallb-l2advertisementTwo L2Advertisement objects in the build namespace, one with every field, one named by objectName that authors nothing else and is written with an empty spec. No capability is required to build it.
mutatingwebhookconfigurationTwo MutatingWebhookConfigurations with no namespace: a pod-injecting webhook with every field the fixture authors, reinvocationPolicy among them, and one named by objectName that holds no webhook. Only the environment policy’s object kind rules apply to it.
namespace
networkpolicyThe authored spec. Unlike the trait of the same name, the kind selects every pod of the namespace when no podSelector is written.
persistentvolume
podThe authored spec and the app label. Not one of the five pod kinds named below.
poddisruptionbudgetA PodDisruptionBudget in the build namespace, holding what was authored.
podmonitorA PodMonitor in the build namespace. No capability is required of the cluster profile to build it.
podtemplateThe authored template, with no app label. Not one of the five pod kinds named below.
priorityclassEach component emits one object, named after the component unless objectName names it, with no namespace.
prometheusA Prometheus in the build namespace, its externalLabels under the spec’s own name, a Thanos sidecar image, and an excluded-from-enforcement entry with no group written with the operator’s one group. Its pods, those of every shard, are held to the environment policy as the Alertmanager’s are; no capability is required to build it.
prometheus-probeA Probe in the build namespace. No capability is required of the cluster profile to build it.
prometheusruleA PrometheusRule in the build namespace. No capability is required of the cluster profile to build it.
referencegrantA ReferenceGrant in the build namespace. No capability is required of the cluster profile to build it.
replicasetThe authored spec, with the app label on the pod template. Not one of the five pod kinds named below.
replicationcontrollerThe authored spec, with the app label on the pod template. Not one of the five pod kinds named below.
replicationdestinationTwo ReplicationDestination objects in the build namespace, a Restic restore and an rsync-over-TLS receiver. No capability is required of the cluster profile to build them.
replicationsourceTwo ReplicationSource objects in the build namespace, a Restic backup on a schedule and a Syncthing source. No capability is required of the cluster profile to build them.
resourcequota
resourcesetinputproviderTwo ResourceSetInputProviders in the build namespace, no Flux namespace being set for the build, a GitHub pull-request provider with its Secret, a filter and a schedule whose window of ninety minutes is written 1h30m0s, and an ExternalArtifact provider named by objectName, listing the labelled ExternalArtifacts of every namespace. No capability is required to build it.
roleA Role with two rules and one that authors none (rules: null). No capability is required to build it, and no environment policy restricts what it grants. TestObjectName_CollidesWithAGeneratedName holds that a component of this type and an rbac trait that names the same object are refused.
rolebindingTwo RoleBindings in the build namespace, one of them without roleRef.apiGroup (written apiGroup: ""). No capability is required to build it, and no environment policy restricts what it grants. TestObjectName_CollidesWithAGeneratedName holds that a component of this type and an rbac trait that names the same object are refused.
runtimeclassEach component emits one object, named after the component unless objectName names it, with no namespace.
secretNo fixture, which would be a Secret manifest with entries: secret_twin_test.go builds it through kurel build instead. The kind is the secret trait’s twin: it emits the same Secret from the same properties, under the component’s name, and is refused under a policy that forbids explicit secrets.
secretstoreA SecretStore in the build namespace. No capability is required of the cluster profile to build it, and it does not read the profile’s external-secret capability, which gives the external-secret trait its store.
servicecidrA ServiceCIDR with no namespace, holding what was authored.
servicemonitorA ServiceMonitor in the build namespace. No capability is required of the cluster profile to build it.
storageclassEach component emits one object, named after the component unless objectName names it, with no namespace.
tcprouteTwo TCPRoutes in the build namespace, one with a single backend, one named by objectName that attaches to a Gateway of another namespace and splits its traffic over two backends, one of them in another namespace. No capability is required of the cluster profile to build them.
thanosrulerA ThanosRuler in the build namespace, its Prometheus external labels authored as externalLabels and its own labels as labels, and an excluded-from-enforcement entry with no group written with the operator’s one group. Its pods are held to the environment policy as the Alertmanager’s are; no capability is required to build it.
tlsrouteTwo TLSRoutes as the tcproute fixture’s, each naming its host names, one of them a wildcard. No capability is required of the cluster profile to build them.
udprouteTwo UDPRoutes as the tcproute fixture’s. No capability is required of the cluster profile to build them.
validatingwebhookconfigurationTwo ValidatingWebhookConfigurations with no namespace: one whose webhook a Service serves, with a rule, a selector and a match condition, and one named by objectName whose webhook a URL serves. Only the environment policy’s object kind rules apply to it.
volumeattributesclassEach component emits one object, named after the component unless objectName names it, with no namespace.

The webservice-pvc-volumes and worker-pvc-volumes fixtures pin the claims both role components generate, byte-identical to before the serviceaccount member and the synthesized pvc traits. The five pod kinds generate no ServiceAccount and no claim: their fixtures emit the workload alone, with automountServiceAccountToken: false on the pod when no account is authored.

TestLabelReach_EveryFieldIsHeldOrListed (label_reach_test.go) holds the kind components to the component label and the reserved metadata keys of go-kure/launcher#790. It walks the API type of the object each kind builds from its fixture and finds every field through which labels and annotations reach what the cluster creates from the object: one that holds labels and annotations, and a map of strings named for labels or annotations. Each such field is either refused through by both checks, which a passthrough object of the kind shows; or refused through by the reserved keys alone, as metadata an operator copies onto objects that are no pods, and listed in labelReachReservedOnly with what it reaches; or listed in labelReachNotRead with its reason. A field a dependency bump adds fails the test until it is one of them, and so does a listed field no kind has any more. A field whose name and type say neither is not found; the test lists those by hand.

Because a lowering rule may claim types the parser would otherwise reject, build constructs the transformer BEFORE parsing the Application: newBuiltinTransformer() runs first, and its LowerableTypes() (the kinds/component-types/trait-types claimed by its registered lowering rules — worker, webservice, postgresql, helm and expose today) is passed into oam.ParseWithExtraTypes alongside the --capability-def-supplied custom trait types. See the OAM model’s Parsing and Lowering sections for the general mechanism.

Once the application is parsed and the profile evaluated, build calls ValidateAuthoredPropertiesWithCapabilities with the evaluated bindings, so a component or trait property no handler declares is a build error naming the field and the allowed set, rather than being silently dropped (go-kure/launcher#408). The bindings are what let a trait leave a nested required key to the capability rendering (go-kure/launcher#765):

Error: validating application file "app.yaml": component "web": trait "expose": properties: unsupported field "tls" (allowed: allowedGroups, allowedHostnameWildcard, annotations, authResponseHeaders, authSigninURL, authURL, certManagerClusterIssuer, controllerType, forceSslRedirect, gatewayName, gatewayNamespace, hostnames, ingressClassName, name, networkPolicy, rules, scope, secretName, serviceName, servicePort, sslRedirect)

The same check type-checks every declared property, so a value of the wrong YAML type fails the build instead of being coerced. A handler that reads a string property with a lenient type assertion turns a non-string into "" and then treats it as absent, so on such a handler alone a wrongly typed value silently becomes the default. Through build it is rejected (go-kure/launcher#325):

Error: validating application file "app.yaml": component "podinfo" (type "helmrelease"): properties.interval: expected string, got int

In package mode this runs after parameter resolution, because an authored ${...} placeholder is a bare string until it is substituted — checking a typed property before that point would reject a document that is correct. See the OAM model’s Property schemas section for what the check does and does not cover.

Platform key domain

kurel derives its platform label/annotation keys under the launcher.gokure.dev domain: the tier annotation is launcher.gokure.dev/tier, and synthesized NetworkPolicies select pods via launcher.gokure.dev/component, valued at the component’s label value (the name itself at 63 characters or fewer, a projection beyond — ComponentLabelValue in the OAM model). Every object a component owns and each of its pod templates carries that label in the build output, and a HelmRelease carries a post-renderer that sets it on the chart’s pod templates, so a synthesized policy selects its component’s pods as emitted (go-kure/launcher#788); a generated source shared by the application carries none. This is kurel’s fixed choice over the launcher library default (gokure.dev); other embedders set their own domain through TransformContext.Domain. See the OAM model for the derivation and precedence rules.

FlagDescription
--profilePath to the ClusterProfile YAML. Required unless --environment is set; the two are mutually exclusive.
--environmentNamed environment whose profile and values stand in for --profile/--values (see Named environments). Mutually exclusive with --profile and --values.
--environmentsEnvironmentSet file declaring the --environment names (default: environments.yaml next to app.yaml). Requires --environment.
-o, --outputOutput directory (default: stdout).
-n, --namespaceNamespace override; must be a DNS-1123 label (at most 63 characters, no dots), like metadata.namespace.
--cluster-idCluster identifier (default local).
--valuesPath to a values YAML file (requires a kurel.yaml package). The only flag that can supply an array or object parameter.
--set key=valueSet a parameter value (repeatable; requires kurel.yaml). Scalars only: an array or object parameter set this way is refused; use --values or the parameter’s default.
--capability-defAdditional CapabilityDefinition file (repeatable).
--strict-capabilitiesError (instead of warn) on unvalidated custom capabilities.

With --output, the written file is named <app.Metadata.Name>.yaml inside that directory. Metadata.Name is safe to use unescaped here because parsing already rejects any Application whose name fails validation.IsDNS1123Subdomain (see the OAM model’s Parsing section) before build ever reaches the write step, so the filename can’t carry a / or .. path-traversal segment.

Named environments

An environments file binds a name to a ClusterProfile and, optionally, a values file, so kurel build --environment staging replaces a script that pairs --profile with --values by hand (go-kure/launcher#291):

apiVersion: launcher.gokure.dev/v1alpha1
kind: EnvironmentSet
metadata:
  name: my-app-environments   # optional
spec:
  environments:
  - name: staging
    profile: profiles/staging.yaml
    values: values/staging.yaml
  - name: prod
    profile: profiles/prod.yaml
    values: values/prod.yaml

--environment <name> behaves exactly as if the bound --profile and --values had been passed: the output is byte-identical to that invocation. profile and values are relative to the environments file’s own directory, not the working directory, and may not leave it: an absolute path, a .. element, or a symlink whose target lies outside that directory is an error, because the file’s content (and, by default, its location inside the package) is not the operator’s own command line. Pass --profile/--values directly for a file elsewhere. Each name must be a unique DNS-1123 label; profile is required, values is optional (an Application without a kurel.yaml can still be bound to a profile, and a binding with values on such an Application fails the same way --values does). The file is strict-decoded and holds exactly one YAML document, so an unknown field or a trailing --- document is an error. An explicitly empty --environment= or --environments= (an unset variable in a wrapper script) is also an error, never read as absent.

--profile or --values together with --environment is an error rather than an override, so a build never silently mixes an environment’s half with an explicit flag. --set stays available and overrides the environment’s values key by key, as it overrides --values.

The file is a deployer input, deliberately separate from kurel.yaml: the package descriptor is the package author’s public API, while the profile belongs to whoever operates the target cluster. Bindings carry no policy, constraint or limit model — they name a profile+values pair and nothing more.

build generates the manifests it outputs directly from the transform result (oam.GenerateApplications), each application once, and refuses the document when two of its applications generate the same object (API group, kind, namespace and name): a component and another component’s trait, two components, or two traits, which would each deploy that object, the last applied winning. The error names the object and both producers, and nothing is written (go-kure/launcher#646). That generation never constructs or walks a kure layout.ManifestLayout. A component whose config implements the optional layout.LayoutAugmenter interface fails the build outright, naming the component, unless it also implements oam.LayoutAugmentationCoverage and its GenerateCoversAugmentLayout() returns true — meaning its plain Generate output is already a complete superset of whatever AugmentLayout would otherwise add, so skipping the layout walk loses nothing. The helmtemplate component (which only repartitions Generate’s own flat output into hook-group child layouts, adding no resources) opts in and builds normally, and so does a helm component under delivery: template, which lowers to it — see the Component Handlers helmtemplate section. Any other LayoutAugmenter that doesn’t implement oam.LayoutAugmentationCoverage at all still fails closed, the same as before this opt-out existed. A helm component under valuesMode: configMap is not a LayoutAugmenter either: its values ConfigMap comes from a configmap trait on the helmrelease it lowers to, ordinary trait output, so build emits it after the HelmRelease. The same holds for secretValues: its values Secret comes from a secret trait and is written to the output in clear form (base64), so a build’s output is as sensitive as the secretValues it was given.

Warnings

A build that renders no objects warns no resources generated on stderr and writes no <app>.yaml (one an earlier build wrote stays). A build also warns, on stderr and with unchanged output, once per PersistentVolume or PersistentVolumeClaim that carries the Flux force annotation itself or that the force-replace trait covers. One that carries the annotation is force-applied: Flux deletes and recreates it on an immutable-field change, and the warning lists the trait’s intent as a second reason where both hold. One under the trait’s intent alone gets a conditional warning: the output carries no mapping of that intent, so the warning describes what a consumer’s delivery workflow would do where it maps the intent, not what the output does (go-kure/launcher#720; force_warning_test.go).

No delivery output

build writes the application’s objects and nothing that delivers them. The --oci-repository and --oci-tag flags are gone, with the per-bundle artifact directories and the Flux OCIRepository and Kustomization objects they wrote (go-kure/launcher#781): how an application is delivered belongs to the consumer that delivers it, see docs/delivery-scope.md.

The prune-protection and force-replace traits state a delivery intent on the application (Application.Delivery, go-kure/launcher#782), which this output has no place for: the two traits no longer show in it. A consumer that applies the output through a Kustomization of its own loses the effect; to keep it, it builds through the library and reads Application.Delivery.

Global flags

Available on all commands (defined in pkg/cmd/shared/options):

FlagDescription
-c, --configConfig file (default $HOME/.kurel.yaml).
-v, --verboseVerbose output.
--debugDebug output (implies verbose).
--strictTreat warnings as errors.
-o, --outputOutput format: yaml|json|table|wide|name.
-f, --output-fileWrite output to a file instead of stdout.
--no-headers, --show-labels, --wideTable-output controls.
--dry-runPrint generated resources without writing files.
-n, --namespaceTarget namespace.

Examples

# Render to stdout using a cluster profile
kurel build ./app.yaml --profile profiles/minimal.yaml

# Render a parameterized package to a directory with overrides
kurel build ./mypackage --profile profiles/prod.yaml -o out/ \
  --values values.yaml --set replicas=3

# Render the prod environment declared in ./mypackage/environments.yaml
kurel build ./mypackage --environment prod -o out/