<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.10.0">Jekyll</generator><link href="https://bbortt.github.io/snow-white/feed.xml" rel="self" type="application/atom+xml" /><link href="https://bbortt.github.io/snow-white/" rel="alternate" type="text/html" /><updated>2026-09-13T18:24:25+00:00</updated><id>https://bbortt.github.io/snow-white/feed.xml</id><title type="html">Snow-White</title><subtitle>Connect OpenAPI specifications with OpenTelemetry traces to unlock endpoint coverage insights, quality gates, and performance analysis — a ground-truth guardrail for agentic and AI-assisted development.
</subtitle><author><name>Timon Borter</name><email>timon.borter@gmx.ch</email></author><entry><title type="html">Release 1.10.0: agentic CLI mode, the skill as an APM package, and Tempo v2</title><link href="https://bbortt.github.io/snow-white/2026/09/12/agentic-mode-and-apm-skill-package.html" rel="alternate" type="text/html" title="Release 1.10.0: agentic CLI mode, the skill as an APM package, and Tempo v2" /><published>2026-09-12T00:00:00+00:00</published><updated>2026-09-12T00:00:00+00:00</updated><id>https://bbortt.github.io/snow-white/2026/09/12/agentic-mode-and-apm-skill-package</id><content type="html" xml:base="https://bbortt.github.io/snow-white/2026/09/12/agentic-mode-and-apm-skill-package.html"><![CDATA[<p>The upcoming 1.10.0 release is about closing the loop between Snow-White and the coding agents
that increasingly write the code it’s supposed to be checking.</p>

<h2 id="snow-white-calculate---agentic"><code class="language-plaintext highlighter-rouge">snow-white calculate --agentic</code></h2>

<p>The CLI’s <code class="language-plaintext highlighter-rouge">calculate</code> command has always been usable in CI, but its output was designed for a
human watching a terminal: progress logs, colored checkmarks, a final pass/fail line.
Fine for a
pipeline log, useless for a coding agent trying to decide what to fix next.</p>

<p>The new <code class="language-plaintext highlighter-rouge">--agentic</code> flag replaces all of that with a single line of structured JSON:</p>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>snow-white calculate <span class="se">\</span>
  <span class="nt">--config-file</span> snow-white.json <span class="se">\</span>
  <span class="nt">--agentic</span>
</code></pre></div></div>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"schemaVersion"</span><span class="p">:</span><span class="w"> </span><span class="s2">"1"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"FAILED"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"calculationId"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span><span class="p">,</span><span class="w">
  </span><span class="nl">"qualityGateConfigName"</span><span class="p">:</span><span class="w"> </span><span class="s2">"default"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"apiLocation"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://snow-white.example.com/api/rest/v1/reports/..."</span><span class="p">,</span><span class="w">
  </span><span class="nl">"initiatedAt"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-09-12T08:00:00.000Z"</span><span class="p">,</span><span class="w">
  </span><span class="nl">"summary"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"apiCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="p">,</span><span class="w"> </span><span class="nl">"failedApiCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">3</span><span class="p">,</span><span class="w"> </span><span class="nl">"qualityGateFailureCount"</span><span class="p">:</span><span class="w"> </span><span class="mi">5</span><span class="w"> </span><span class="p">},</span><span class="w">
  </span><span class="nl">"interfaces"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w"> </span><span class="err">...</span><span class="w"> </span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div>

<p>No progress logs to strip out, no ANSI colors to parse around — one JSON object naming exactly
which interfaces failed and why.
It’s mutually exclusive with <code class="language-plaintext highlighter-rouge">--async</code>, since agentic mode
needs the finished result to report and async mode returns before one exists.
Full shape and an
example are documented on the <a href="/cli/#calculate">CLI Reference</a>.</p>

<p>This is also the flag the <a href="/claude-skill/">Claude Code skill</a> is built around: instead of
scraping a JUnit XML report meant for humans, the skill (or any agent) can invoke <code class="language-plaintext highlighter-rouge">--agentic</code> and
get a backlog it can act on directly.</p>

<h2 id="the-skill-becomes-an-apm-package">The skill becomes an APM package</h2>

<p>Speaking of the skill — installing it used to mean copying <code class="language-plaintext highlighter-rouge">SKILL.md</code> into your repo by hand.
It’s moving to <a href="https://microsoft.github.io/apm">APM</a> (Agent Package Manager), so it can be
declared as a dependency and updated like one:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># apm.yml</span>
<span class="na">dependencies</span><span class="pi">:</span>
  <span class="na">apm</span><span class="pi">:</span>
    <span class="pi">-</span> <span class="s">bbortt/snow-white/.apm/skills/snow-white#v1.10.0</span>
</code></pre></div></div>

<div class="language-shell highlighter-rouge"><div class="highlight"><pre class="highlight"><code>apm <span class="nb">install</span>
</code></pre></div></div>

<p><code class="language-plaintext highlighter-rouge">.apm/skills/snow-white/</code> becomes the source of truth in the repository; <code class="language-plaintext highlighter-rouge">.claude/skills/snow-white/</code>
stays as a generated, committed copy so Claude Code sessions working inside this repo keep
working without the APM CLI installed.
Manual copying remains an option if you’d rather not add
APM as a dependency — see the <a href="/claude-skill/">Claude Code Skill</a> page for both paths.</p>

<h2 id="grafana-tempo-migrating-to-the-v2-trace-api">Grafana Tempo: migrating to the v2 trace API</h2>

<p>A smaller but important fix for anyone using the Grafana Tempo integration introduced back in
1.7.0: <code class="language-plaintext highlighter-rouge">openapi-coverage-stream</code> queried Tempo’s trace-by-id endpoint at its original, unversioned
path (<code class="language-plaintext highlighter-rouge">/api/traces/{traceId}</code>).
That was never formally deprecated in Tempo’s docs, so we kept
assuming it would keep working — until testing 1.9.0 against a newer Grafana-managed Tempo
instance turned up one with no v1 endpoint exposed at all.</p>

<p>1.10.0 moves that query to the explicit <code class="language-plaintext highlighter-rouge">/api/v2/traces/{traceId}</code> endpoint, which is what
current and newer Grafana Tempo backends actually expect.
If you’re running Snow-White against a
recent Tempo instance and coverage calculation was silently failing to resolve trace details,
this release should fix it — no configuration changes required.</p>]]></content><author><name>Timon Borter</name><email>timon.borter@gmx.ch</email></author><category term="release" /><category term="agentic" /><category term="cli" /><category term="claude-code" /><summary type="html"><![CDATA[Snow-White now speaks a language coding agents can parse directly, the Claude Code skill installs as a proper APM package, and Grafana Tempo queries move to the v2 trace API for compatibility with newer backends.]]></summary></entry><entry><title type="html">Release 1.9.0: bring your own tracing backend, cut Kubernetes costs</title><link href="https://bbortt.github.io/snow-white/2026/09/05/cut-kubernetes-costs-disable-otel-ingestion.html" rel="alternate" type="text/html" title="Release 1.9.0: bring your own tracing backend, cut Kubernetes costs" /><published>2026-09-05T00:00:00+00:00</published><updated>2026-09-05T00:00:00+00:00</updated><id>https://bbortt.github.io/snow-white/2026/09/05/cut-kubernetes-costs-disable-otel-ingestion</id><content type="html" xml:base="https://bbortt.github.io/snow-white/2026/09/05/cut-kubernetes-costs-disable-otel-ingestion.html"><![CDATA[<p>Snow-White ships with its own OTel Collector, an <code class="language-plaintext highlighter-rouge">otel-event-filter-stream</code> deployment, and (by
default) an InfluxDB instance to store traces for coverage calculation.
That’s convenient for a
first install, but it’s redundant weight if your organization already runs a tracing backend
that your applications export to — you end up paying for two ingestion pipelines instead of one.</p>

<p><a href="https://github.com/bbortt/snow-white/releases/tag/v1.9.0">Release 1.9.0</a> fixes that for
operators.</p>

<h2 id="otelcollectordisableingestion"><code class="language-plaintext highlighter-rouge">otelCollector.disableIngestion</code></h2>

<p>Set this to <code class="language-plaintext highlighter-rouge">true</code> in your Helm values and Snow-White stops deploying its own ingestion path
altogether: the OTel Collector’s coverage-trace pipelines, the <code class="language-plaintext highlighter-rouge">otel-event-filter-stream</code>
Deployment, and the public <code class="language-plaintext highlighter-rouge">/v1/traces</code> route are no longer created.
Snow-White’s own
self-observability (its microservices’ internal telemetry) is unaffected — this only removes the
stack that exists to ingest <em>your applications’</em> traces for coverage analysis.</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">otelCollector</span><span class="pi">:</span>
  <span class="na">disableIngestion</span><span class="pi">:</span> <span class="no">true</span>
</code></pre></div></div>

<h2 id="query-grafana-tempo-directly">Query Grafana Tempo directly</h2>

<p>1.9.0 also lets <code class="language-plaintext highlighter-rouge">openapi-coverage-stream</code> read traces straight from an externally operated
Grafana Tempo instance instead of Snow-White’s bundled InfluxDB:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">snowWhite</span><span class="pi">:</span>
  <span class="na">openapiCoverageStream</span><span class="pi">:</span>
    <span class="na">tempo</span><span class="pi">:</span>
      <span class="na">endpoint</span><span class="pi">:</span> <span class="s1">'</span><span class="s">https://tempo.example.com'</span>
      <span class="na">token</span><span class="pi">:</span> <span class="s1">'</span><span class="s">your-bearer-token'</span>
</code></pre></div></div>

<p>Combine both settings and Snow-White no longer runs its own trace-ingestion pipeline or
datastore at all — it just queries the Tempo you’re already operating.
Fewer pods, less CPU and
memory reserved in the cluster, one less system to keep patched.</p>

<p>One thing Helm can’t infer for you: setting <code class="language-plaintext highlighter-rouge">disableIngestion: true</code> does <strong>not</strong> automatically
turn off the bundled InfluxDB subchart.
If you’re switching to Tempo, set <code class="language-plaintext highlighter-rouge">influxdb2.enabled:
false</code> yourself, or you’ll have an InfluxDB StatefulSet running unused.</p>

<p>See the <a href="/deployment/">Deployment Guide</a> for the full set of <code class="language-plaintext highlighter-rouge">otelCollector</code> and
<code class="language-plaintext highlighter-rouge">openapiCoverageStream</code> options.</p>]]></content><author><name>Timon Borter</name><email>timon.borter@gmx.ch</email></author><category term="release" /><category term="operators" /><category term="kubernetes" /><category term="opentelemetry" /><summary type="html"><![CDATA[Already running your own OpenTelemetry pipeline or Grafana Tempo? 1.9.0 lets you disable Snow-White's bundled ingestion stack entirely and point openapi-coverage-stream straight at your existing backend.]]></summary></entry></feed>