<?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: Anurag Sati</title>
    <description>The latest articles on DEV Community by Anurag Sati (@anurag_sati_5b77a6578f780).</description>
    <link>https://dev.to/anurag_sati_5b77a6578f780</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%2F3602291%2F786e1233-773e-4f3c-8c2a-d87444bc9656.jpg</url>
      <title>DEV Community: Anurag Sati</title>
      <link>https://dev.to/anurag_sati_5b77a6578f780</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/anurag_sati_5b77a6578f780"/>
    <language>en</language>
    <item>
      <title>My k6 run said 70% failed. SigNoz told me *why* — then my agent wrote the fix</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sat, 25 Jul 2026 18:40:58 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/my-k6-run-said-70-failed-signoz-told-me-why-then-my-agent-wrote-the-fix-18b9</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/my-k6-run-said-70-failed-signoz-told-me-why-then-my-agent-wrote-the-fix-18b9</guid>
      <description>&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%2F6vr84de1y3gm14ujfue5.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%2F6vr84de1y3gm14ujfue5.png" alt="omen cover" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was staring at a load-test number that looked decisive: &lt;strong&gt;~70% of requests failed&lt;/strong&gt;. Cool. Except that number alone is almost useless at 2am.&lt;/p&gt;

&lt;p&gt;Was it my new endpoint? Rate limiting? A bad client script? A flaky network? Or a real server bug?&lt;/p&gt;

&lt;p&gt;For &lt;a href="https://www.wemakedevs.org/hackathons/signoz" rel="noopener noreferrer"&gt;Agents of SigNoz&lt;/a&gt;, I built &lt;strong&gt;omen&lt;/strong&gt; — an agent that load-tests a code change with k6, correlates the same window against live SigNoz traces, names the root cause, and hands back a remediation diff. This post is what I actually learned wiring that loop on Windows with Gemini, Foundry, and the official SigNoz MCP server.&lt;/p&gt;

&lt;p&gt;Repo: &lt;a href="https://github.com/Satianurag/omen" rel="noopener noreferrer"&gt;github.com/Satianurag/omen&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem I kept hitting
&lt;/h2&gt;

&lt;p&gt;k6 is great at client-side truth: request count, p95, failure rate. It is terrible at answering “what broke &lt;em&gt;inside&lt;/em&gt; the service?”&lt;/p&gt;

&lt;p&gt;I planted a small FastAPI demo (&lt;code&gt;petclinic&lt;/code&gt;) with a bad write path:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;POST /api/visits&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SQLite with &lt;code&gt;BEGIN IMMEDIATE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;tiny timeout&lt;/li&gt;
&lt;li&gt;a fake sleep under lock&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Under concurrent load it fails hard. Client-side you see 5xx. Server-side, SigNoz sees the real error string: &lt;strong&gt;&lt;code&gt;database is locked&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That gap — client metrics vs server spans — is what omen exists for.&lt;/p&gt;




&lt;h2&gt;
  
  
  What omen is (short version)
&lt;/h2&gt;

&lt;p&gt;omen is a governed &lt;a href="https://github.com/apache/burr" rel="noopener noreferrer"&gt;Burr&lt;/a&gt; state machine served over MCP by &lt;a href="https://msradam.github.io/theodosia/" rel="noopener noreferrer"&gt;Theodosia&lt;/a&gt;. The driver sees one tool: &lt;code&gt;step&lt;/code&gt;. Illegal transitions get refused. Every step lands on a hash-chained ledger you can verify later.&lt;/p&gt;

&lt;p&gt;Rough walk:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Read a git diff (or an intent)&lt;/li&gt;
&lt;li&gt;Scaffold + generate a k6 script&lt;/li&gt;
&lt;li&gt;Validate and run it through Grafana’s k6 MCP&lt;/li&gt;
&lt;li&gt;Preflight the SigNoz service&lt;/li&gt;
&lt;li&gt;Correlate traces (&lt;code&gt;signoz_aggregate_traces&lt;/code&gt;, &lt;code&gt;signoz_search_traces&lt;/code&gt;, &lt;code&gt;signoz_get_trace_details&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Detect latency anomalies over the test window&lt;/li&gt;
&lt;li&gt;Analyze → groundedness screen → report + remediation&lt;/li&gt;
&lt;/ol&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%2Ftppi25gsbsbti6epc8r6.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%2Ftppi25gsbsbti6epc8r6.png" alt="omen state machine" width="800" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure: &lt;code&gt;omen render&lt;/code&gt; — 16 actions, legal edges only. Note &lt;code&gt;signoz_preflight&lt;/code&gt; after &lt;code&gt;run_test&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How I used SigNoz (not “I used observability”)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Self-hosted via Foundry
&lt;/h3&gt;

&lt;p&gt;I deployed SigNoz with Foundry from the repo’s &lt;code&gt;casting.yaml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;foundryctl cast &lt;span class="nt"&gt;-f&lt;/span&gt; casting.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That gave me:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Piece&lt;/th&gt;
&lt;th&gt;URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;UI&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://localhost:8080&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;OTLP gRPC&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://localhost:4317&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SigNoz MCP&lt;/td&gt;
&lt;td&gt;&lt;code&gt;http://localhost:8000/mcp&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;API key went into &lt;code&gt;.env&lt;/code&gt; as &lt;code&gt;OMEN_SIGNOZ_API_KEY&lt;/code&gt;. No inline comments on that line — that bit me once and silently broke auth.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Official OpenTelemetry on the target app
&lt;/h3&gt;

&lt;p&gt;Demo apps run under stock &lt;code&gt;opentelemetry-instrument&lt;/code&gt;. No custom shipper:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'petclinic'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'http://localhost:4317'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'grpc'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_TRACES_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'otlp'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opentelemetry-instrument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;examples/petclinic/app.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;serve&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a few omen runs, the SigNoz home page stopped looking empty:&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%2Fkgjyb3twdla2l1la9yjp.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%2Fkgjyb3twdla2l1la9yjp.png" alt="SigNoz home — petclinic ingestion" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure: Traces + metrics ingestion active. Services widget shows &lt;code&gt;petclinic&lt;/code&gt; with ~70% error rate and ~596ms p99 over the last 30 minutes.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That services row is the “something is on fire” view:&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%2Fxk5zotk593wbxqfkr3pk.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%2Fxk5zotk593wbxqfkr3pk.png" alt="SigNoz services table" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And the service overview shows the load spikes from the k6 runs as clear humps in rate and latency:&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%2Fq6hg3zft289zs6dpemqx.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%2Fq6hg3zft289zs6dpemqx.png" alt="petclinic latency and rate" width="800" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure: Two load bursts on &lt;code&gt;petclinic&lt;/code&gt; — same windows omen used for correlation.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Correlation through the SigNoz MCP (not hand-clicked UI)
&lt;/h3&gt;

&lt;p&gt;This was the interesting part for Track 01. omen does not scrape the UI. It talks to the official SigNoz MCP server during the run.&lt;/p&gt;

&lt;p&gt;On a real petclinic run (Gemini backend, local k6 MCP, SigNoz correlate), the phase stream looked like this:&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%2Fzez9rjlbf7uf07gw1i4x.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%2Fzez9rjlbf7uf07gw1i4x.png" alt="omen pilot correlate run" width="800" height="372"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Figure: Terminal output from a full omen run — cards for each phase, including SigNoz tools.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The numbers from that run (not invented for this blog):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;k6: &lt;strong&gt;3897 requests&lt;/strong&gt;, p95 &lt;strong&gt;547.59ms&lt;/strong&gt;, &lt;strong&gt;~72% failed&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;SigNoz preflight: &lt;code&gt;service petclinic, exists=True&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Correlate: &lt;code&gt;aggregate_traces&lt;/code&gt; ×9 + &lt;code&gt;search_traces&lt;/code&gt; + &lt;code&gt;get_trace_details&lt;/code&gt; ×3&lt;/li&gt;
&lt;li&gt;Worst path: &lt;code&gt;/api/visits&lt;/code&gt; &lt;strong&gt;72.1% 5xx&lt;/strong&gt;, top error &lt;strong&gt;&lt;code&gt;database is locked&lt;/code&gt;&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Guardian screen: &lt;strong&gt;grounded&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Verdict: server-side regression on &lt;code&gt;/api/visits&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Client p95 (~548ms) and server-side p95 (~543ms) lined up. That consistency mattered to me — if those numbers diverged wildly, I’d distrust the join.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. The agent publishes itself back into SigNoz
&lt;/h3&gt;

&lt;p&gt;After &lt;code&gt;report&lt;/code&gt;, omen emits &lt;code&gt;omen.run&lt;/code&gt; and &lt;code&gt;omen.step.*&lt;/code&gt; spans over OTLP (when &lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt; is set). So the &lt;em&gt;agent walk&lt;/em&gt; is visible in the same backend that observed the app. That self-observability loop is half the point of this track.&lt;/p&gt;




&lt;h2&gt;
  
  
  The fix it proposed (and why it wasn’t hand-wavy)
&lt;/h2&gt;

&lt;p&gt;omen didn’t stop at “SQLite is sad.” It returned a validated unified diff that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;raised the connect timeout (&lt;code&gt;0.25&lt;/code&gt; → &lt;code&gt;5.0&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;enabled &lt;code&gt;PRAGMA journal_mode=WAL&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;removed &lt;code&gt;BEGIN IMMEDIATE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;removed the artificial &lt;code&gt;time.sleep(0.015)&lt;/code&gt; under the lock&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s exactly the planted fault class. The Guardian check marked the analysis grounded against the cited telemetry before the verdict was sealed.&lt;/p&gt;

&lt;p&gt;Also: every stepped phase went through Theodosia’s mounted MCP &lt;code&gt;step&lt;/code&gt; tool, so the session wrote a real &lt;strong&gt;&lt;code&gt;ledger.jsonl&lt;/code&gt;&lt;/strong&gt;. &lt;code&gt;omen verify&lt;/code&gt; came back HMAC-keyed and intact — important if you’re going to claim “audited by construction” in a demo.&lt;/p&gt;




&lt;h2&gt;
  
  
  Gotchas I only learned by breaking things
&lt;/h2&gt;

&lt;p&gt;These are the details that bit me on a fresh clone:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Windows + Docker k6 is a trap.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;OMEN_K6_DOCKER=1&lt;/code&gt; with &lt;code&gt;--network host&lt;/code&gt; cannot reach &lt;code&gt;127.0.0.1&lt;/code&gt; demo apps on Windows. Local &lt;code&gt;k6 x mcp&lt;/code&gt; worked. Put &lt;code&gt;OMEN_K6_CMD=k6 x mcp&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; and leave Docker k6 off.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;uv run omen&lt;/code&gt;, not bare &lt;code&gt;omen&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
After &lt;code&gt;uv sync&lt;/code&gt;, the &lt;code&gt;omen&lt;/code&gt; entrypoint lives in &lt;code&gt;.venv&lt;/code&gt;. Use &lt;code&gt;uv run omen …&lt;/code&gt; (or activate the venv). Same for pytest and scripts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;opentelemetry-bootstrap&lt;/code&gt; needs pip in a uv venv.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;uv run opentelemetry-bootstrap --action=install&lt;/code&gt; failed here with &lt;code&gt;No module named pip&lt;/code&gt;. Fix with &lt;code&gt;uv run python -m ensurepip --upgrade&lt;/code&gt;, or skip it — &lt;code&gt;uv sync&lt;/code&gt; already installs FastAPI + OTLP packages the demos need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Runnable demos are on 8400–8404, not &lt;code&gt;:8000&lt;/code&gt; / &lt;code&gt;petstore&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;examples/petclinic&lt;/code&gt; serves &lt;code&gt;http://localhost:8400&lt;/code&gt;. &lt;code&gt;examples/petstore&lt;/code&gt; is OpenAPI-only (unit tests). SigNoz MCP itself is on &lt;code&gt;:8000/mcp&lt;/code&gt; — don’t confuse that with the app port.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;omen pilot&lt;/code&gt; ≠ Gemini by default (until I fixed it).&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Phase workers already respected &lt;code&gt;OMEN_LLM=gemini&lt;/code&gt;. The pilot &lt;em&gt;driver&lt;/em&gt; still assumed Ollama/Granite. I fixed the non-Ollama path to walk the same mounted MCP server deterministically so Gemini runs still seal the ledger. Banner now says &lt;code&gt;Gemini is reading.&lt;/code&gt; (honest: Burr/MCP walks the graph; Gemini authors the work inside phases).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bypassing &lt;code&gt;mount()&lt;/code&gt; drops your ledger.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Calling &lt;code&gt;build_application().arun()&lt;/code&gt; (what &lt;code&gt;verify_scenario.py&lt;/code&gt; uses for a fast live check) can leave you with a thin or empty multi-step ledger listing. Driving through MCP &lt;code&gt;step&lt;/code&gt; via &lt;code&gt;omen pilot&lt;/code&gt; writes a real &lt;code&gt;ledger.jsonl&lt;/code&gt; that &lt;code&gt;omen verify&lt;/code&gt; can HMAC-check. Use verify_scenario to prove k6+SigNoz; use pilot when you need the audited session story.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SigNoz API keys hate trailing comments.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;code&gt;OMEN_SIGNOZ_API_KEY=.... # note&lt;/code&gt; broke auth. Key alone on the line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Filename must be &lt;code&gt;.env&lt;/code&gt;, not &lt;code&gt;.env.txt&lt;/code&gt;.&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Windows “Save as text” bit me once. omen only loads &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What I’d tell myself on day one
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Instrument the &lt;em&gt;target&lt;/em&gt; first. If SigNoz Services doesn’t show your app with a nasty error rate after a load test, stop debugging the agent.&lt;/li&gt;
&lt;li&gt;Correlate on a wall-clock window from the k6 run — not “last 1 hour of everything.”&lt;/li&gt;
&lt;li&gt;Prefer MCP tools that return structured aggregates (&lt;code&gt;signoz_aggregate_traces&lt;/code&gt;) before you drown in individual spans.&lt;/li&gt;
&lt;li&gt;Keep the agent’s own walk on OTLP. Judges (and future-you) can see whether the FSM actually ran.&lt;/li&gt;
&lt;li&gt;Demo a failure k6 alone can’t explain cleanly. &lt;code&gt;database is locked&lt;/code&gt; from traces beats “high error rate” from a client report.&lt;/li&gt;
&lt;li&gt;On Windows, never start from &lt;code&gt;OMEN_K6_DOCKER=1&lt;/code&gt; — local k6 first.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Try the same path
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;omen&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;foundryctl&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cast&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;casting.yaml&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Copy-Item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;example&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;env&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# Edit .env: OMEN_SIGNOZ_API_KEY, GEMINI_API_KEY, OMEN_LLM=gemini, OMEN_K6_CMD=k6 x mcp&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# Do NOT set OMEN_K6_DOCKER=1 on Windows&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;omen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;warm-k6&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# optional (needs pip in the venv):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# uv run python -m ensurepip --upgrade&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="c"&gt;# uv run opentelemetry-bootstrap --action=install&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Fastest live proof (starts petclinic :8400 for you):&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scripts/verify_scenario.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;petclinic&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# Audited pilot path (full ledger) — terminal 1:&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_SERVICE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'petclinic'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'http://localhost:4317'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_EXPORTER_OTLP_PROTOCOL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'grpc'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="nn"&gt;env&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nv"&gt;OTEL_TRACES_EXPORTER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'otlp'&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;opentelemetry-instrument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;python&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;examples/petclinic/app.py&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;serve&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# terminal 2 — intent mode (or --ref HEAD~1 against a two-commit demo repo)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;omen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pilot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--intent&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"load test recording a new visit"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--repo-path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;examples/petclinic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--target-base-url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;http://127.0.0.1:8400&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;`
&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;--signoz-service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;petclinic&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;omen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;sessions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ls&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;uv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;omen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;verify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;app-id&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Open &lt;code&gt;http://localhost:8080&lt;/code&gt; → Services → &lt;code&gt;petclinic&lt;/code&gt;. If you see a fat error rate after the run, the loop is alive.&lt;/p&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;I didn’t learn that “observability is important.” I learned that a 70% k6 failure rate is a &lt;em&gt;question&lt;/em&gt;, and SigNoz traces are where the answer lives — especially when an agent can query those traces through MCP in the same window as the load test and come back with a grounded fix.&lt;/p&gt;

&lt;p&gt;That’s omen. Divines disaster, crafts the cure — but only because SigNoz made the server side legible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project: &lt;a href="https://github.com/Satianurag/omen" rel="noopener noreferrer"&gt;github.com/Satianurag/omen&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hackathon: &lt;a href="https://www.wemakedevs.org/hackathons/signoz" rel="noopener noreferrer"&gt;Agents of SigNoz&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SigNoz MCP docs: &lt;a href="https://signoz.io/docs/ai/signoz-mcp-server" rel="noopener noreferrer"&gt;signoz.io/docs/ai/signoz-mcp-server&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Blog guide I followed: &lt;a href="https://www.wemakedevs.org/hackathons/signoz/blog-guide" rel="noopener noreferrer"&gt;WeMakeDevs Blog Guide&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>signoz</category>
      <category>opentelemetry</category>
      <category>observability</category>
      <category>python</category>
    </item>
    <item>
      <title>Immich promised OpenTelemetry traces. SigNoz showed me metrics instead — and that's what found the 750ms spike</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sun, 19 Jul 2026 18:22:03 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/gbgfbgf-5c8j</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/gbgfbgf-5c8j</guid>
      <description>&lt;p&gt;I wanted one screenshot for a blog: Immich showing up under SigNoz &lt;strong&gt;Services&lt;/strong&gt;, with a nice flamegraph. I never got that screenshot.&lt;/p&gt;

&lt;p&gt;What I got instead was more useful — Immich's &lt;em&gt;real&lt;/em&gt; Prometheus histograms in SigNoz, a dashboard that showed album list p99 drop from ~25ms to ~7ms after warmup, and a thumbnail-generation spike at &lt;strong&gt;~750ms p95&lt;/strong&gt;. This is the path that actually works today, and the one people keep getting wrong.&lt;/p&gt;

&lt;p&gt;If you're trying to connect Immich → SigNoz right now, start here. Don't start with the NestJS auto-instrumentation guide.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Immich + SigNoz?
&lt;/h2&gt;

&lt;p&gt;Immich is the self-hosted Google Photos alternative a lot of us already run. It already uses OpenTelemetry (&lt;code&gt;nestjs-otel&lt;/code&gt;). SigNoz is the place I wanted those signals.&lt;/p&gt;

&lt;p&gt;Immich's own docs say Prometheus metrics are first-class, and that &lt;em&gt;exporting traces is also possible&lt;/em&gt; because of OpenTelemetry — then they document only Prometheus. That gap is exactly why &lt;a href="https://github.com/immich-app/immich/issues/14045" rel="noopener noreferrer"&gt;people open issues&lt;/a&gt; asking how to point Immich at SigNoz.&lt;/p&gt;

&lt;p&gt;I decided to stop reading and just run both stacks on one machine.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;My lab:&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;Piece&lt;/th&gt;
&lt;th&gt;Version / URL&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SigNoz&lt;/td&gt;
&lt;td&gt;v0.133.0 (self-hosted, Foundry) → &lt;code&gt;http://localhost:3301&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immich&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;release&lt;/code&gt; image (v3.0.3) → &lt;code&gt;http://localhost:2283&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bridge&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;otel/opentelemetry-collector-contrib:0.120.0&lt;/code&gt; scraping Immich &lt;code&gt;/metrics&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Mistake #1: treating Immich like a blank NestJS app
&lt;/h2&gt;

&lt;p&gt;SigNoz's NestJS docs (and half of Reddit) say: set &lt;code&gt;OTEL_EXPORTER_OTLP_ENDPOINT&lt;/code&gt;, then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;NODE_OPTIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"--require @opentelemetry/auto-instrumentations-node/register"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Immich that is a trap. Immich &lt;strong&gt;already&lt;/strong&gt; boots its own OpenTelemetry SDK for Prometheus. Adding auto-instrumentation gives you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: @opentelemetry/api: Attempted duplicate registration of API: trace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the same crash people hit in &lt;a href="https://github.com/immich-app/immich/issues/14045" rel="noopener noreferrer"&gt;immich#14045&lt;/a&gt;. I reproduced the shape of the problem by inspecting the running container: Immich ships &lt;code&gt;@opentelemetry/exporter-prometheus&lt;/code&gt;. It does &lt;strong&gt;not&lt;/strong&gt; ship an OTLP trace exporter. So env vars like &lt;code&gt;OTEL_TRACES_EXPORTER=otlp&lt;/code&gt; look correct and do almost nothing for traces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rule I wish I'd known on day one:&lt;/strong&gt; if the app initializes OTel itself, don't also &lt;code&gt;--require&lt;/code&gt; the Node auto-instrumentation pack.&lt;/p&gt;




&lt;h2&gt;
  
  
  What actually works: scrape Immich, export OTLP to SigNoz
&lt;/h2&gt;

&lt;p&gt;Immich exposes Prometheus on port &lt;code&gt;8081&lt;/code&gt; when you enable telemetry:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IMMICH_TELEMETRY_INCLUDE=all
IMMICH_API_METRICS_PORT=8081
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I put Immich and SigNoz on the same Docker network (&lt;code&gt;signoz-network&lt;/code&gt;), then ran a tiny collector that scrapes Immich and forwards OTLP to SigNoz's ingester:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# configs/otel-collector.yaml (trimmed)&lt;/span&gt;
&lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;config&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;scrape_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;job_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;immich-api-metrics&lt;/span&gt;
          &lt;span class="na"&gt;scrape_interval&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;15s&lt;/span&gt;
          &lt;span class="na"&gt;metrics_path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/metrics&lt;/span&gt;
          &lt;span class="na"&gt;static_configs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;targets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;immich-server:8081"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# service name, NOT container name&lt;/span&gt;

&lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;endpoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;signoz-ingester-1:4317&lt;/span&gt;
    &lt;span class="na"&gt;tls&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;insecure&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="na"&gt;service&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;pipelines&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metrics&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;receivers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;prometheus&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;processors&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;batch&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
      &lt;span class="na"&gt;exporters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;otlp&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Gotcha that wasted an evening
&lt;/h3&gt;

&lt;p&gt;My first scrape target was &lt;code&gt;immich_server:8081&lt;/code&gt; (container name). Collector logs said &lt;code&gt;Failed to scrape Prometheus endpoint&lt;/code&gt; forever. Docker DNS resolves the &lt;strong&gt;Compose service name&lt;/strong&gt; (&lt;code&gt;immich-server&lt;/code&gt;), not the &lt;code&gt;container_name&lt;/code&gt;. One hyphen later, the collector started printing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Metrics ... resource metrics: 1, metrics: 77, data points: 122
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then SigNoz Metrics Explorer lit up when I searched &lt;code&gt;immich&lt;/code&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%2Fyv30stwvt9r5aq6f5ib9.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%2Fyv30stwvt9r5aq6f5ib9.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1 — SigNoz Metrics Explorer autocomplete for `immich_&lt;/em&gt;` histograms.*&lt;/p&gt;




&lt;h2&gt;
  
  
  The part that still doesn't work (be honest)
&lt;/h2&gt;

&lt;p&gt;I opened &lt;strong&gt;Services&lt;/strong&gt;. Empty. &lt;strong&gt;Traces&lt;/strong&gt;. Empty. Service map? Nothing.&lt;/p&gt;

&lt;p&gt;That isn't SigNoz being broken. Services/APM in SigNoz are built from &lt;strong&gt;spans&lt;/strong&gt;. Immich's stock image only exports Prometheus metrics from its NodeSDK. No spans → no APM row.&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%2Fj3pw1qy9u62jjrld7q0r.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%2Fj3pw1qy9u62jjrld7q0r.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2 — SigNoz Services with no Immich traces. This is expected today.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;So if your blog (or your weekend) depends on a pretty Immich flamegraph from the official image alone: change the goal. Instrument a sidecar, fork Immich's telemetry bootstrap, or wait for native OTLP traces. Don't pretend env vars fixed it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Feature-rich SigNoz without traces: dashboard + Metrics Explorer
&lt;/h2&gt;

&lt;p&gt;I built a dashboard called &lt;strong&gt;Immich Observability&lt;/strong&gt; with six panels:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Album list p99
&lt;/li&gt;
&lt;li&gt;Thumbnail generation p95
&lt;/li&gt;
&lt;li&gt;CLIP encode p95
&lt;/li&gt;
&lt;li&gt;Face detection p95
&lt;/li&gt;
&lt;li&gt;Event bus emit p99
&lt;/li&gt;
&lt;li&gt;Thumbnail jobs / second
&lt;/li&gt;
&lt;/ol&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%2Ftkg2l865nm72lolr42h9.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%2Ftkg2l865nm72lolr42h9.png" alt=" " width="800" height="396"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 3 — Immich Observability dashboard in SigNoz.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The album panel was the first “okay, this is worth it” moment. Fresh after restart, album list p99 sat around &lt;strong&gt;~25ms&lt;/strong&gt;. After a few dozen API hits it settled near &lt;strong&gt;~7ms&lt;/strong&gt;. Same endpoint, same machine — warmup is not a myth when you can see it.&lt;/p&gt;

&lt;p&gt;Then thumbnail generation showed a &lt;strong&gt;p95 near 750ms&lt;/strong&gt; on a real upload path. Client-side curl for a cached thumbnail was ~6ms. Server-side &lt;em&gt;generation&lt;/em&gt; is a different animal. That distinction is exactly why repo-level histograms beat “the API felt slow.”&lt;/p&gt;




&lt;h2&gt;
  
  
  Numbers from the load I actually ran
&lt;/h2&gt;

&lt;p&gt;I hammered the Immich API with a script (warmup + repeated reads + photo upload). Client-side timings:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Endpoint&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/server/ping&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;60&lt;/td&gt;
&lt;td&gt;2.1ms&lt;/td&gt;
&lt;td&gt;3.2ms&lt;/td&gt;
&lt;td&gt;4.6ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/users/me&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;30&lt;/td&gt;
&lt;td&gt;4.6ms&lt;/td&gt;
&lt;td&gt;6.6ms&lt;/td&gt;
&lt;td&gt;9.8ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/albums&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;20&lt;/td&gt;
&lt;td&gt;6.1ms&lt;/td&gt;
&lt;td&gt;12.6ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;28.3ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/assets/{id}/thumbnail&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;25&lt;/td&gt;
&lt;td&gt;6.2ms&lt;/td&gt;
&lt;td&gt;9.0ms&lt;/td&gt;
&lt;td&gt;15.3ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;GET /api/assets/{id}&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;16.2ms&lt;/td&gt;
&lt;td&gt;31.2ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;56.6ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;POST /api/assets&lt;/code&gt; (upload)&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;44.6ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Server-side histograms after a second load batch (from &lt;code&gt;/metrics&lt;/code&gt;):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;avg&lt;/th&gt;
&lt;th&gt;count&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;immich_event_repository_emit&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;38.8ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;64&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;immich_asset_repository_create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;21.9ms&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;immich_asset_repository_upsert_exif&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;22.8ms&lt;/td&gt;
&lt;td&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;immich_machine_learning_repository_check&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;27.2ms&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Early in the session, before more traffic diluted the average, &lt;code&gt;event_repository_emit&lt;/code&gt; showed &lt;strong&gt;~252ms&lt;/strong&gt; on a tiny sample — the kind of spike you'd never notice from &lt;code&gt;curl&lt;/code&gt; alone if you only look at the happy path.&lt;/p&gt;

&lt;p&gt;None of these numbers are “production SLOs.” They're what my laptop + Docker setup produced on 2026-07-19. Your SSD and CPU will disagree. The &lt;em&gt;method&lt;/em&gt; is what transfers.&lt;/p&gt;




&lt;h2&gt;
  
  
  Minimal Immich override (copy-paste)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# docker-compose.override.yml&lt;/span&gt;
&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;immich-server&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;signoz-network&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;2283:2283"&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8081:8081"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;IMMICH_TELEMETRY_INCLUDE&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;all&lt;/span&gt;
      &lt;span class="na"&gt;IMMICH_API_METRICS_PORT&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8081&lt;/span&gt;

  &lt;span class="na"&gt;immich-prometheus-scraper&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;otel/opentelemetry-collector-contrib:0.120.0&lt;/span&gt;
    &lt;span class="na"&gt;command&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;--config=/etc/otelcol/config.yaml"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./configs/otel-collector.yaml:/etc/otelcol/config.yaml:ro&lt;/span&gt;
    &lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;signoz-network&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;depends_on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;immich-server&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;networks&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;signoz-network&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;external&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bring SigNoz up first so &lt;code&gt;signoz-network&lt;/code&gt; and &lt;code&gt;signoz-ingester-1:4317&lt;/code&gt; exist. Then &lt;code&gt;docker compose up -d&lt;/code&gt; in the Immich folder.&lt;/p&gt;

&lt;p&gt;Working configs from this write-up live under &lt;code&gt;configs/&lt;/code&gt; in the companion repo (dashboard JSON export included).&lt;/p&gt;




&lt;h2&gt;
  
  
  What I'd tell myself last week
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Don't chase the Services page first.&lt;/strong&gt; For stock Immich, Metrics Explorer + a custom dashboard is the win.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Never stack two OTel SDKs.&lt;/strong&gt; Skip &lt;code&gt;NODE_OPTIONS=--require @opentelemetry/...&lt;/code&gt; on Immich.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Name DNS correctly.&lt;/strong&gt; &lt;code&gt;immich-server&lt;/code&gt;, not &lt;code&gt;immich_server&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Look at histograms, not vibes.&lt;/strong&gt; Album list warmup (~25ms → ~7ms) and thumbnail generation (~750ms p95) are the kind of findings that change how you size a homelab box.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Document the failure.&lt;/strong&gt; The missing traces story is half the value. Someone else will burn a weekend on the same env vars.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  Closing
&lt;/h2&gt;

&lt;p&gt;Immich's docs weren't lying when they said OpenTelemetry is in the tree. They just didn't tell you the exporter story. SigNoz didn't need me to invent a new photo app — it needed an honest scrape pipeline and a dashboard that charts the metrics Immich already emits.&lt;/p&gt;

&lt;p&gt;I still want native Immich → OTLP traces. Until then, this is the setup I'll leave running: Immich for photos, SigNoz for the slow bits that aren't the thumbnails I already cached.&lt;/p&gt;




&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Immich monitoring docs: &lt;a href="https://docs.immich.app/features/monitoring/" rel="noopener noreferrer"&gt;https://docs.immich.app/features/monitoring/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Immich OTel / SigNoz discussion: &lt;a href="https://github.com/immich-app/immich/discussions/14062" rel="noopener noreferrer"&gt;https://github.com/immich-app/immich/discussions/14062&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;SigNoz: &lt;a href="https://signoz.io" rel="noopener noreferrer"&gt;https://signoz.io&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>signoz</category>
      <category>opentelemetry</category>
      <category>immich</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>f</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sun, 15 Feb 2026 07:18:31 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/f-4ibn</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/f-4ibn</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-01-21"&gt;GitHub Copilot CLI Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot CLI
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>cli</category>
      <category>githubcopilot</category>
    </item>
    <item>
      <title>t</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sun, 08 Feb 2026 13:46:12 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/t-2ah</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/t-2ah</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/algolia"&gt;Algolia Agent Studio Challenge&lt;/a&gt;: Consumer-Facing Conversational Experiences&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Used Algolia Agent Studio
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why Fast Retrieval Matters
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>algoliachallenge</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>Fg</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sat, 07 Feb 2026 17:21:26 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/fg-n0d</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/fg-n0d</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/algolia"&gt;Algolia Agent Studio Challenge&lt;/a&gt;: Consumer-Facing Conversational Experiences&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Used Algolia Agent Studio
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Why Fast Retrieval Matters
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>algoliachallenge</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>h</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sun, 01 Feb 2026 13:02:15 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/h-3dc9</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/h-3dc9</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/new-year-new-you-google-ai-2025-12-31"&gt;New Year, New You Portfolio Challenge Presented by Google AI&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  About Me
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Portfolio
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h2&gt;
  
  
  What I'm Most Proud Of
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>googleaichallenge</category>
      <category>portfolio</category>
      <category>gemini</category>
    </item>
    <item>
      <title>a</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Fri, 02 Jan 2026 07:41:18 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/a-904</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/a-904</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/mux-2025-12-03"&gt;DEV's Worldwide Show and Tell Challenge Presented by Mux&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  My Pitch Video
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The Story Behind It
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Technical Highlights
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Use of Mux (Additional Prize Category Participants Only)
&lt;/h3&gt;

</description>
      <category>devchallenge</category>
      <category>muxchallenge</category>
      <category>showandtell</category>
      <category>video</category>
    </item>
    <item>
      <title>g</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Mon, 15 Dec 2025 06:50:56 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/g-1g89</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/g-1g89</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/xano-2025-11-20"&gt;Xano AI-Powered Backend Challenge&lt;/a&gt;: Production-Ready Public API&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  API Documentation
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The AI Prompt I Used
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Refined the AI-Generated Code
&lt;/h2&gt;

&lt;h2&gt;
  
  
  My Experience with Xano
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>xanochallenge</category>
      <category>api</category>
      <category>backend</category>
    </item>
    <item>
      <title>f</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Sun, 14 Dec 2025 08:27:55 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/f-2n2n</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/f-2n2n</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/xano-2025-11-20"&gt;Xano AI-Powered Backend Challenge&lt;/a&gt;: Full-Stack, AI-First Application&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The AI Prompt I Used
&lt;/h2&gt;

&lt;h2&gt;
  
  
  How I Refined the AI-Generated Code
&lt;/h2&gt;

&lt;h2&gt;
  
  
  My Experience with Xano
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>xanochallenge</category>
      <category>ai</category>
      <category>backend</category>
    </item>
    <item>
      <title>an</title>
      <dc:creator>Anurag Sati</dc:creator>
      <pubDate>Mon, 08 Dec 2025 07:11:15 +0000</pubDate>
      <link>https://dev.to/anurag_sati_5b77a6578f780/a-5fef</link>
      <guid>https://dev.to/anurag_sati_5b77a6578f780/a-5fef</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/unoplatform"&gt;AI Challenge for Cross-Platform Apps&lt;/a&gt; - AI Acceleration&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;h2&gt;
  
  
  AI Tooling in Action
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Using App MCP and Uno Platform MCP
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Cross-Platform Reach
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Development Experience
&lt;/h2&gt;

</description>
      <category>devchallenge</category>
      <category>unoplatformchallenge</category>
      <category>dotnet</category>
      <category>crossplatform</category>
    </item>
  </channel>
</rss>
