DEV Community

Gatt Geng
Gatt Geng

Posted on

HelmSharp v1.1.0: making Helm compatibility inspectable

In the first post, I introduced HelmSharp as a managed .NET SDK for rendering Helm charts from .NET without calling the helm executable at runtime.

Since then, the project has moved from "the renderer can get through real charts" to something more useful: compatibility work that is easier to inspect, reproduce, and challenge.

HelmSharp v1.1.0 completes the first rendering-parity milestone, but this post is not really about a scorecard. The more important part is the process behind it: using Helm as an oracle, tightening the parts of the renderer where small differences matter, and building a docs site with a Live Compare tool so users can test their own charts instead of trusting a claim in a README.

First post:

HelmSharp: render Helm charts from .NET without shelling out to helm

Docs:

https://gattgeng.github.io/HelmSharp/

HelmSharp documentation homepage

What changed since the first post

The first milestone was about proving that HelmSharp could render realistic charts without falling over.

That was useful, but it was also an incomplete definition of compatibility.

A renderer can avoid exceptions and still be wrong. It can produce valid YAML with different whitespace. It can evaluate a function almost like Helm, but not quite. It can serialize YAML in a way Kubernetes accepts, while still producing output that makes a diff-based deployment workflow noisy.

So the work after the first post focused on the boring details that make compatibility real.

Whitespace and trim behavior

Helm templates are Go text/template templates with Helm-specific objects and functions on top.

That means trim markers are not cosmetic. In a chart, the difference between {{ ... }}, {{- ... }}, {{ ... -}}, and {{- ... -}} can change the output in ways that show up directly in manifests.

This became one of the main areas of work in v1.1.0:

  • block right-trim behavior
  • define-body trimming
  • indentation around action lines
  • newline preservation in places where Helm keeps it
  • indent / nindent behavior around trimmed actions

These are small rules, but they compound. A renderer that is "mostly right" here produces noisy diffs.

Sprig and Helm function behavior

Helm charts rely heavily on Sprig functions. Not just common helpers like default, quote, toYaml, and nindent, but also functions that show up only when a chart starts doing more dynamic work.

The v1.1.0 work closed remaining gaps around functions such as:

  • empty
  • keys
  • mergeOverwrite
  • regex helpers
  • string slicing edge cases
  • trunc and substr behavior

The point is not that every function is interesting on its own. The point is that Helm charts treat this function set as part of the language. If the SDK exposes Helm-style rendering, the function behavior has to be treated as compatibility surface.

YAML edge cases

Some of the remaining differences were not parser problems at all. They were YAML behavior problems.

Examples included:

  • YAML tags
  • octal values
  • merge keys
  • block scalars
  • comment trimming
  • key ordering in toYaml output

These are exactly the kinds of details that small handcrafted examples miss. Real charts contain years of accumulated Helm idioms, YAML tricks, and formatting assumptions.

That is why I keep using public charts as compatibility input. They are not perfect coverage, but they are much better than only testing charts designed for the test suite.

Helm as oracle, not dependency

One design rule has stayed the same:

Helm CLI is allowed in tests.

Helm CLI is not allowed as an SDK runtime dependency.

The golden tests run Helm and HelmSharp against the same chart input, then compare the rendered output. That gives the project a concrete oracle without making consumer applications install or ship Helm.

This distinction matters.

If HelmSharp simply called helm template internally, the library would be much easier to build, but it would not solve the original problem. The whole reason I started this project was to remove the runtime dependency from .NET services, operators, preview APIs, and deployment tools.

So Helm remains the reference implementation, not the execution engine.

Why I built a documentation site

The README was becoming the wrong shape for the project.

At first, a README was enough: install package, render chart, show compatibility notes.

But once the SDK started covering more than one workflow, the documentation needed routing by intent:

  • "I want to render my first chart."
  • "I want to build a preview API."
  • "I need to understand values precedence."
  • "I want to compare Helm and HelmSharp output."
  • "I want generated API reference pages."

A flat README cannot serve all of those well.

So the docs moved into a VitePress site:

https://gattgeng.github.io/HelmSharp/

It includes guide pages, examples, package pages, generated API references, compatibility notes, and Simplified Chinese localization.

The README still exists, but it is now an entry point instead of the whole manual.

The part I care about most: Live Compare

The Live Compare page is the most important new documentation feature.

Instead of asking users to believe that HelmSharp behaves like Helm, it lets them check.

Open:

https://gattgeng.github.io/HelmSharp/compare

You can upload a packaged Helm chart (.tgz), optionally provide custom values, and run a comparison against the real Helm CLI.

Helm Compare upload screen

There is also a Quick Examples modal with public charts, so users can try the tool without preparing anything locally.

Helm Compare quick examples

The result page shows Helm CLI output and HelmSharp output side by side.

Helm Compare result screen

This is the trust model I want for HelmSharp.

A compatibility table is useful, but it is still a claim from the maintainer. A live diff is better. It gives users a way to bring their own chart, their own values, and their own expectations.

If the output matches, great.

If it does not, the diff is already the beginning of a bug report.

What this changes for users

For render-only scenarios, HelmSharp is now much easier to evaluate.

You do not have to read through the implementation to decide whether it is worth trying. You can:

  1. Open Live Compare.
  2. Upload your chart.
  3. Add values if needed.
  4. Inspect the Helm CLI and HelmSharp output side by side.

That is a much better starting point than "please trust this compatibility paragraph."

The documentation site also changes how the project explains itself. The README remains the entry point, but deeper topics now have their own pages: first render, values precedence, template behavior, release workflows, Kubernetes operations, compatibility notes, and API reference.

What is next

M1 focused on Helm template parity.

The next work is about expanding the surrounding SDK surface:

  • chart packaging and repository behavior
  • dependency and subchart workflows
  • release lifecycle behavior
  • Kubernetes apply and wait semantics
  • OCI and provenance work
  • continued API and documentation hardening

No hard dates. I am keeping the project driven by reproducible cases and real usage rather than trying to declare broad compatibility too early.

What I am looking for

If you use Helm from .NET tooling today, try the Live Compare page with one of your own charts:

https://gattgeng.github.io/HelmSharp/compare

If it matches, that is useful signal.

If it does not match, that is more useful. Open an issue with the chart, values input, Helm command, HelmSharp output, and the observed difference.

Small reproducible charts are the most helpful. They turn compatibility from a vague report into an engineering task.

If you were replacing helm template inside a .NET service, what would you need to verify before trusting a managed SDK?


GitHub: https://github.com/GaTTGeng/HelmSharp

Docs: https://gattgeng.github.io/HelmSharp/

Live Compare: https://gattgeng.github.io/HelmSharp/compare

NuGet: https://www.nuget.org/packages/HelmSharp.Action

License: MIT

Top comments (0)