<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Gatt Geng</title>
    <description>The latest articles on DEV Community by Gatt Geng (@gatt_geng_ce6a8f5b3886c67).</description>
    <link>https://dev.to/gatt_geng_ce6a8f5b3886c67</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3996021%2Fdc258edd-3a28-4562-812d-7ca3187ffccc.jpg</url>
      <title>DEV Community: Gatt Geng</title>
      <link>https://dev.to/gatt_geng_ce6a8f5b3886c67</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/gatt_geng_ce6a8f5b3886c67"/>
    <language>en</language>
    <item>
      <title>HelmSharp v1.1.0: making Helm compatibility inspectable</title>
      <dc:creator>Gatt Geng</dc:creator>
      <pubDate>Wed, 01 Jul 2026 09:23:17 +0000</pubDate>
      <link>https://dev.to/gatt_geng_ce6a8f5b3886c67/helmsharp-v110-making-helm-compatibility-inspectable-307o</link>
      <guid>https://dev.to/gatt_geng_ce6a8f5b3886c67/helmsharp-v110-making-helm-compatibility-inspectable-307o</guid>
      <description>&lt;p&gt;In the first post, I introduced HelmSharp as a managed .NET SDK for rendering Helm charts from .NET without calling the &lt;code&gt;helm&lt;/code&gt; executable at runtime.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;First post:&lt;br&gt;&lt;br&gt;
&lt;a href="https://dev.to/gatt_geng_ce6a8f5b3886c67/helmsharp-render-helm-charts-from-net-without-shelling-out-to-helm-1gng"&gt;HelmSharp: render Helm charts from .NET without shelling out to helm&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Docs:&lt;br&gt;&lt;br&gt;
&lt;a href="https://gattgeng.github.io/HelmSharp/" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsaruky31usvrhinz7pmc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fsaruky31usvrhinz7pmc.png" alt="HelmSharp documentation homepage" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What changed since the first post
&lt;/h2&gt;

&lt;p&gt;The first milestone was about proving that HelmSharp could render realistic charts without falling over.&lt;/p&gt;

&lt;p&gt;That was useful, but it was also an incomplete definition of compatibility.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;So the work after the first post focused on the boring details that make compatibility real.&lt;/p&gt;

&lt;h3&gt;
  
  
  Whitespace and trim behavior
&lt;/h3&gt;

&lt;p&gt;Helm templates are Go &lt;code&gt;text/template&lt;/code&gt; templates with Helm-specific objects and functions on top.&lt;/p&gt;

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

&lt;p&gt;This became one of the main areas of work in v1.1.0:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;block right-trim behavior&lt;/li&gt;
&lt;li&gt;define-body trimming&lt;/li&gt;
&lt;li&gt;indentation around action lines&lt;/li&gt;
&lt;li&gt;newline preservation in places where Helm keeps it&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;indent&lt;/code&gt; / &lt;code&gt;nindent&lt;/code&gt; behavior around trimmed actions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are small rules, but they compound. A renderer that is "mostly right" here produces noisy diffs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sprig and Helm function behavior
&lt;/h3&gt;

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

&lt;p&gt;The v1.1.0 work closed remaining gaps around functions such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;empty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;keys&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mergeOverwrite&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;regex helpers&lt;/li&gt;
&lt;li&gt;string slicing edge cases&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;trunc&lt;/code&gt; and &lt;code&gt;substr&lt;/code&gt; behavior&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h3&gt;
  
  
  YAML edge cases
&lt;/h3&gt;

&lt;p&gt;Some of the remaining differences were not parser problems at all. They were YAML behavior problems.&lt;/p&gt;

&lt;p&gt;Examples included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;YAML tags&lt;/li&gt;
&lt;li&gt;octal values&lt;/li&gt;
&lt;li&gt;merge keys&lt;/li&gt;
&lt;li&gt;block scalars&lt;/li&gt;
&lt;li&gt;comment trimming&lt;/li&gt;
&lt;li&gt;key ordering in &lt;code&gt;toYaml&lt;/code&gt; output&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  Helm as oracle, not dependency
&lt;/h2&gt;

&lt;p&gt;One design rule has stayed the same:&lt;/p&gt;

&lt;p&gt;Helm CLI is allowed in tests.&lt;br&gt;&lt;br&gt;
Helm CLI is not allowed as an SDK runtime dependency.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;This distinction matters.&lt;/p&gt;

&lt;p&gt;If HelmSharp simply called &lt;code&gt;helm template&lt;/code&gt; 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.&lt;/p&gt;

&lt;p&gt;So Helm remains the reference implementation, not the execution engine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why I built a documentation site
&lt;/h2&gt;

&lt;p&gt;The README was becoming the wrong shape for the project.&lt;/p&gt;

&lt;p&gt;At first, a README was enough: install package, render chart, show compatibility notes.&lt;/p&gt;

&lt;p&gt;But once the SDK started covering more than one workflow, the documentation needed routing by intent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;"I want to render my first chart."&lt;/li&gt;
&lt;li&gt;"I want to build a preview API."&lt;/li&gt;
&lt;li&gt;"I need to understand values precedence."&lt;/li&gt;
&lt;li&gt;"I want to compare Helm and HelmSharp output."&lt;/li&gt;
&lt;li&gt;"I want generated API reference pages."&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A flat README cannot serve all of those well.&lt;/p&gt;

&lt;p&gt;So the docs moved into a VitePress site:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gattgeng.github.io/HelmSharp/" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It includes guide pages, examples, package pages, generated API references, compatibility notes, and Simplified Chinese localization.&lt;/p&gt;

&lt;p&gt;The README still exists, but it is now an entry point instead of the whole manual.&lt;/p&gt;

&lt;h2&gt;
  
  
  The part I care about most: Live Compare
&lt;/h2&gt;

&lt;p&gt;The Live Compare page is the most important new documentation feature.&lt;/p&gt;

&lt;p&gt;Instead of asking users to believe that HelmSharp behaves like Helm, it lets them check.&lt;/p&gt;

&lt;p&gt;Open:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gattgeng.github.io/HelmSharp/compare" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/compare&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can upload a packaged Helm chart (&lt;code&gt;.tgz&lt;/code&gt;), optionally provide custom values, and run a comparison against the real Helm CLI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fscjcz6tuqyqm718fv5zx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fscjcz6tuqyqm718fv5zx.png" alt="Helm Compare upload screen" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also a Quick Examples modal with public charts, so users can try the tool without preparing anything locally.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztj9b40go2nlc0nnrosa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fztj9b40go2nlc0nnrosa.png" alt="Helm Compare quick examples" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The result page shows Helm CLI output and HelmSharp output side by side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F348zvh7jhivntgpkcqr3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F348zvh7jhivntgpkcqr3.png" alt="Helm Compare result screen" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the trust model I want for HelmSharp.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;If the output matches, great.&lt;/p&gt;

&lt;p&gt;If it does not, the diff is already the beginning of a bug report.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this changes for users
&lt;/h2&gt;

&lt;p&gt;For render-only scenarios, HelmSharp is now much easier to evaluate.&lt;/p&gt;

&lt;p&gt;You do not have to read through the implementation to decide whether it is worth trying. You can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open Live Compare.&lt;/li&gt;
&lt;li&gt;Upload your chart.&lt;/li&gt;
&lt;li&gt;Add values if needed.&lt;/li&gt;
&lt;li&gt;Inspect the Helm CLI and HelmSharp output side by side.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That is a much better starting point than "please trust this compatibility paragraph."&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is next
&lt;/h2&gt;

&lt;p&gt;M1 focused on Helm template parity.&lt;/p&gt;

&lt;p&gt;The next work is about expanding the surrounding SDK surface:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;chart packaging and repository behavior&lt;/li&gt;
&lt;li&gt;dependency and subchart workflows&lt;/li&gt;
&lt;li&gt;release lifecycle behavior&lt;/li&gt;
&lt;li&gt;Kubernetes apply and wait semantics&lt;/li&gt;
&lt;li&gt;OCI and provenance work&lt;/li&gt;
&lt;li&gt;continued API and documentation hardening&lt;/li&gt;
&lt;/ul&gt;

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

&lt;h2&gt;
  
  
  What I am looking for
&lt;/h2&gt;

&lt;p&gt;If you use Helm from .NET tooling today, try the Live Compare page with one of your own charts:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gattgeng.github.io/HelmSharp/compare" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/compare&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If it matches, that is useful signal.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Small reproducible charts are the most helpful. They turn compatibility from a vague report into an engineering task.&lt;/p&gt;

&lt;p&gt;If you were replacing &lt;code&gt;helm template&lt;/code&gt; inside a .NET service, what would you need to verify before trusting a managed SDK?&lt;/p&gt;




&lt;p&gt;GitHub: &lt;a href="https://github.com/GaTTGeng/HelmSharp" rel="noopener noreferrer"&gt;https://github.com/GaTTGeng/HelmSharp&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Docs: &lt;a href="https://gattgeng.github.io/HelmSharp/" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/&lt;/a&gt;&lt;br&gt;&lt;br&gt;
Live Compare: &lt;a href="https://gattgeng.github.io/HelmSharp/compare" rel="noopener noreferrer"&gt;https://gattgeng.github.io/HelmSharp/compare&lt;/a&gt;&lt;br&gt;&lt;br&gt;
NuGet: &lt;a href="https://www.nuget.org/packages/HelmSharp.Action" rel="noopener noreferrer"&gt;https://www.nuget.org/packages/HelmSharp.Action&lt;/a&gt;&lt;br&gt;&lt;br&gt;
License: MIT&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>opensource</category>
      <category>kubernetes</category>
      <category>devops</category>
    </item>
    <item>
      <title>HelmSharp: render Helm charts from .NET without shelling out to helm</title>
      <dc:creator>Gatt Geng</dc:creator>
      <pubDate>Mon, 22 Jun 2026 03:47:32 +0000</pubDate>
      <link>https://dev.to/gatt_geng_ce6a8f5b3886c67/helmsharp-render-helm-charts-from-net-without-shelling-out-to-helm-1gng</link>
      <guid>https://dev.to/gatt_geng_ce6a8f5b3886c67/helmsharp-render-helm-charts-from-net-without-shelling-out-to-helm-1gng</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; I built a .NET library that renders Helm charts and drives Kubernetes releases without shelling out to the &lt;code&gt;helm&lt;/code&gt; CLI. 129/129 templates across ingress-nginx, cert-manager, external-dns, podinfo, and metrics-server now render successfully. The main entry point is HelmSharp.Action, with lower-level packages available for chart loading, rendering, Kubernetes operations, and release storage. MIT licensed, looking for feedback and early adopters.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why I Built This
&lt;/h2&gt;

&lt;p&gt;At work, our .NET services deploy to Kubernetes through Helm. Every Docker image had to bundle the &lt;code&gt;helm&lt;/code&gt; binary — another dependency to manage, another layer in the image, another surface for CVEs. I wanted to cut that out entirely and do Helm-style rendering directly in-process.&lt;/p&gt;

&lt;p&gt;The .NET ecosystem doesn't really have this. There are YAML libraries. There are Kubernetes client libraries. There are template engines. But nothing ties them together the way &lt;code&gt;helm template&lt;/code&gt; does — values merging, named templates, &lt;code&gt;include&lt;/code&gt;, &lt;code&gt;range&lt;/code&gt;, &lt;code&gt;toYaml&lt;/code&gt;, the whole Sprig function set, all wired into a single render pipeline. So I started building one. (This is also my first real open source project — I'd spent years consuming OSS without contributing back, and HelmSharp is what came out of deciding to change that.)&lt;/p&gt;

&lt;h2&gt;
  
  
  What HelmSharp Does
&lt;/h2&gt;

&lt;p&gt;HelmSharp is a multi-package .NET SDK (net8.0 / net9.0 / net10.0) that covers:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Action&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;High-level Helm client — &lt;code&gt;TemplateAsync&lt;/code&gt;, &lt;code&gt;UpgradeInstallAsync&lt;/code&gt;, &lt;code&gt;RollbackAsync&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Chart&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chart loading from directories and &lt;code&gt;.tgz&lt;/code&gt;, values merging, &lt;code&gt;--set&lt;/code&gt; / &lt;code&gt;--set-json&lt;/code&gt; style overrides&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Engine&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Helm-style template rendering — 100+ Sprig/Helm functions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Kube&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Kubernetes apply, delete, and wait (no &lt;code&gt;kubectl&lt;/code&gt; needed)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Release&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Release history stored in Kubernetes Secrets (Helm-compatible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HelmSharp.Repo&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Chart repository index, pull, and search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Plus &lt;code&gt;Registry&lt;/code&gt;, &lt;code&gt;Storage&lt;/code&gt;, &lt;code&gt;PostRenderer&lt;/code&gt; extension points&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Here's the lower-level rendering API — no result objects, no stdout strings, just in-process template evaluation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;chart&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;HelmChartLoader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/charts/my-chart"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;HelmValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;BuildAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"image"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Dictionary&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt;&lt;span class="p"&gt;?&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"tag"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"1.2.3"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"replicaCount"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ct&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HelmTemplateRenderer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;chart&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"my-app"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"production"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;values&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;manifests&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Render&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// manifests is a string of valid YAML — feed it to kubectl apply, store it,&lt;/span&gt;
&lt;span class="c1"&gt;// diff it, whatever you'd do with `helm template` output.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No &lt;code&gt;helm&lt;/code&gt; binary. No &lt;code&gt;Process.Start&lt;/code&gt;. Values are native .NET objects, not &lt;code&gt;--set&lt;/code&gt; strings. The output is just a string — you decide what to do with it.&lt;/p&gt;

&lt;p&gt;There's also a higher-level &lt;code&gt;HelmClient&lt;/code&gt; API (&lt;code&gt;TemplateAsync&lt;/code&gt;, &lt;code&gt;UpgradeInstallAsync&lt;/code&gt;, &lt;code&gt;RollbackAsync&lt;/code&gt;) that mirrors the Helm CLI workflow if you prefer that shape.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where We Are Now (v1.0.3)
&lt;/h2&gt;

&lt;p&gt;This week I hit a milestone I'm genuinely proud of: &lt;strong&gt;129 out of 129 templates across 5 real-world public charts now render without a single parser exception.&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Chart&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Templates&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ingress-nginx&lt;/td&gt;
&lt;td&gt;4.12.1&lt;/td&gt;
&lt;td&gt;42/42 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cert-manager&lt;/td&gt;
&lt;td&gt;1.17.1&lt;/td&gt;
&lt;td&gt;41/41 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;external-dns&lt;/td&gt;
&lt;td&gt;1.21.1&lt;/td&gt;
&lt;td&gt;7/7 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;podinfo&lt;/td&gt;
&lt;td&gt;6.14.0&lt;/td&gt;
&lt;td&gt;21/21 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;metrics-server&lt;/td&gt;
&lt;td&gt;3.13.1&lt;/td&gt;
&lt;td&gt;18/18 ✅&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This was blocked by two parser bugs that took a while to track down — one in pipeline splitting where &lt;code&gt;|&lt;/code&gt; inside parenthesized expressions like &lt;code&gt;(empty .x)&lt;/code&gt; was incorrectly treated as a pipeline separator, and one in else-if chain reconstruction where C# string interpolation was silently producing single braces instead of double braces. The kind of bug where you stare at it for hours, then the fix is four characters.&lt;/p&gt;

&lt;p&gt;The test suite is at &lt;strong&gt;214 tests&lt;/strong&gt; across three target frameworks, with a golden-test harness that runs &lt;code&gt;helm template&lt;/code&gt; as the oracle and diffs the output document-by-document against HelmSharp's renderer.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's Next
&lt;/h2&gt;

&lt;p&gt;The project follows numbered milestones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;M1 (in progress):&lt;/strong&gt; Helm template parity — functions, whitespace, built-in objects, control flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M2:&lt;/strong&gt; Subchart and dependency resolution&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M3:&lt;/strong&gt; Release lifecycle (install/upgrade/rollback/uninstall with hook execution)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M4:&lt;/strong&gt; Kubernetes resource lifecycle hardening&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M5:&lt;/strong&gt; OCI registry and provenance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;M6:&lt;/strong&gt; API polish, XML docs, stable surface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;No hard dates — I'm pushing forward steadily (you can see the cadence in the &lt;a href="https://github.com/GaTTGeng/HelmSharp/commits/master" rel="noopener noreferrer"&gt;commit history&lt;/a&gt;). That said, if someone needs a specific feature, I'm happy to re-prioritize. Open source moves faster when real use cases drive it.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I'm Looking For
&lt;/h2&gt;

&lt;p&gt;If you're writing a .NET Kubernetes operator, a CD pipeline, or any tooling that currently shells out to &lt;code&gt;helm&lt;/code&gt; — this is for you. &lt;code&gt;dotnet add package HelmSharp.Action&lt;/code&gt; and render one of your charts. If it works, great. If it breaks, I want to know exactly how — open an issue with the chart and template that failed, and I'll fix it.&lt;/p&gt;

&lt;p&gt;If you find it useful, a star is appreciated — but stars are earned, not asked for. What I really want is feedback, bug reports, and feature requests from people who actually deploy things to Kubernetes.&lt;/p&gt;

&lt;p&gt;Contributions are welcome too. The golden-test harness makes it easy to verify template fixes — add a chart fixture, run the test, see the diff.&lt;/p&gt;

&lt;p&gt;If you use Helm in .NET-based tooling today, what would you expect from a managed SDK like this?&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;GitHub:&lt;/strong&gt; &lt;a href="https://github.com/GaTTGeng/HelmSharp" rel="noopener noreferrer"&gt;github.com/GaTTGeng/HelmSharp&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;NuGet:&lt;/strong&gt; &lt;a href="https://www.nuget.org/packages/HelmSharp.Action/" rel="noopener noreferrer"&gt;nuget.org/packages/HelmSharp.Action&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;License:&lt;/strong&gt; MIT&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>dotnet</category>
      <category>devops</category>
      <category>opensource</category>
    </item>
  </channel>
</rss>
