Accepted by kro
Every RGD is checked offline with kro's own admission schema and graph builder before it is written. chart2kro never writes an RGD kro would reject.
Helm chart kro ResourceGraphDefinition
chart2kro converts a Helm chart into a kro ResourceGraphDefinition: a Kubernetes API whose instances deploy what the chart deploys. Every input is verified against Helm with kro's own runtime, and every value it does not expose comes with a reason.
brew install hupe1980/tap/chart2kroOr go install github.com/hupe1980/chart2kro/cmd/chart2kro@latest, or the GitHub Action. Single static binary; no Helm, kubectl or cluster needed to convert. Output runs on kro v0.9.2 or newer.
$ chart2kro convert oci://ghcr.io/…/podinfo -o podinfo/ podinfo 6.15.0 → Podinfo.kro.run/v1alpha1: 3 resources, 29 exposed, 33 frozen, 0 failed, 60 unused (256 witnesses, kro v0.9.4, Kubernetes 1.37) frozen: changes-structure 15 frozen: toggles-fields 8 frozen: transformed 6 frozen: unknown-kind 4 unused: affects-only-dropped-objects 11 $ kubectl apply -f podinfo/rgd.yaml $ kubectl apply -f podinfo/instance.yaml podinfo.kro.run/podinfo created
A Helm chart is a template program: a value can end up in one field, in five, inside a string, behind a condition, or nowhere. Rewriting that as a kro ResourceGraphDefinition means deciding, value by value, what is safe to expose and how. chart2kro makes those decisions by experiment, checks each one with kro's own code, and tells you why it decided.
Every RGD is checked offline with kro's own admission schema and graph builder before it is written. chart2kro never writes an RGD kro would reject.
An instance with the defaults deploys what helm template deploys for that release name and namespace.
A value becomes an input only after kro's runtime, run offline, reproduced Helm's output for it. Loops over lists become kro collections.
Inputs carry the chart's own values.yaml docs. Values that are not exposed are listed with a stable reason code and what to do about it.
Names come from the instance and namespaces from where it is created. Selectors never reach another instance's pods.
Secrets you pass with -f never become defaults. Passwords the chart would generate become required inputs, never derived from public data.
The chart is rendered in memory with the Helm v4 SDK, exactly like helm template.
Each value is rendered again with typed probe values to see which fields it controls, and how.
Mappings become CEL expressions, includeWhen conditions and schema fields. kro's own code validates the result.
kro's runtime instantiates the RGD offline and compares it with Helm's render. Any mismatch freezes the value.
values.yaml to an API# values.yaml
replicaCount: 1
image:
repository: nginx
tag: "1.27"
# templates/deployment.yaml
metadata:
name: {{ .Release.Name }}-nginx
spec:
replicas: {{ .Values.replicaCount }}
template:
spec:
containers:
- image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"spec:
schema:
kind: Nginx
spec:
replicaCount: integer | default=1
image:
repository: string | default="nginx"
tag: string | default="1.27"
resources:
- id: deployment
template:
metadata:
name: ${schema.metadata.name}-nginx
spec:
replicas: ${schema.spec.replicaCount}
template:
spec:
containers:
- image: ${schema.spec.image.repository}:${schema.spec.image.tag}Instances are named after themselves and isolated by an added selector label. Booleans that switch whole resources become includeWhen.
Set platform opinions with Helm's own -f, choose the knobs with --expose. Exposure is strict: CI fails if a knob cannot be verified.
chart2kro convert ./app \
-f platform.yaml \
--expose 'image.tag,replicaCount' \
--group apps.example.com -o api/One step in a pull request: fail when the committed RGD is stale or a chart upgrade would break existing instances.
- uses: hupe1980/chart2kro@v0.2.0
with:
chart: charts/app
output-dir: apiTurn the values of a running Helm release into an instance of the new API. Unexposed values fail loudly instead of disappearing.
helm get values web -o yaml > web.yaml
chart2kro instance ./app \
--from web.yaml --name webNo. Loading, rendering, validation and verification all run in-process. You only need a cluster with kro to apply the result.
The generated RGDs need kro v0.9.2 or newer. chart2kro validates with the kro v0.9.4 libraries, and its end-to-end tests run on both v0.9.2 and v0.9.4.
They stay at their default in every instance and are listed with a reason, for example transformed when the chart passes the value through upper. See Limitations and Troubleshooting.
No tool can prove that for arbitrary templates. chart2kro validates each exposed value at concrete witnesses (the report counts them) and freezes anything that did not match Helm. It never guesses.
Yes: oci:// references, repo/chart from your Helm repositories.yaml, --repo URLs, basic auth and TLS client certificates. Credentials are never written or logged.
Yes, it is plain YAML. Most teams keep it generated instead: commit the output, and let convert --check and diff guard it in CI.
Install the binary, point it at a chart, apply the result.