<?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>Forem: Agustín Abero</title>
    <description>The latest articles on Forem by Agustín Abero (@tico).</description>
    <link>https://forem.com/tico</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2803173%2F5a1c1363-9b8a-427f-9620-509b5019e5ce.jpg</url>
      <title>Forem: Agustín Abero</title>
      <link>https://forem.com/tico</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/tico"/>
    <language>en</language>
    <item>
      <title>Mapping the Territory</title>
      <dc:creator>Agustín Abero</dc:creator>
      <pubDate>Mon, 09 Mar 2026 13:07:12 +0000</pubDate>
      <link>https://forem.com/tico/mapping-the-territory-3n55</link>
      <guid>https://forem.com/tico/mapping-the-territory-3n55</guid>
      <description>&lt;p&gt;We thought the "Multi-Repo Verse" would save us from spaghetti code. Instead, we traded a tangled web of single files for a labyrinth of repositories, modules, and remote state. The boundaries were supposed to give us clarity, but suddenly, understanding a single &lt;code&gt;depends_on&lt;/code&gt; rule became an archaeological dig through half a dozen browser tabs. The code was perfectly structured, but the reality was invisible.&lt;/p&gt;




&lt;h2&gt;
  
  
  A quick recap
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Part 1&lt;/strong&gt; of the "Making Invisible Infrastructure Visible" series, I talked about "The Fog of Code": that overwhelming anxiety of flying blind when making changes to modern, distributed infrastructure. Tab Fatigue is real. The fear of the Butterfly Effect is real.&lt;/p&gt;

&lt;p&gt;To stop flying blind, I needed a map. Not just a text search across repositories, but a true semantic map of the territory. I needed to turn static syntax into a dynamic, queryable reality.&lt;/p&gt;

&lt;p&gt;Here is exactly how I built the foundation of Infra-Graph to do just that.&lt;/p&gt;

&lt;h2&gt;
  
  
  The harsh reality of parsing HCL
&lt;/h2&gt;

&lt;p&gt;When I first sat down to solve this, the plan felt straightforward: parse the &lt;code&gt;.tf&lt;/code&gt; files, find the references, and draw the lines. &lt;/p&gt;

&lt;p&gt;Then I actually looked at the Abstract Syntax Tree (AST). &lt;/p&gt;

&lt;p&gt;You open a file and see a seemingly simple string: &lt;code&gt;depends_on = [aws_security_group.web.id]&lt;/code&gt;. But to a machine, that’s just text. To build a visualization tool, you have to map every variable, module output, and resource attribute into a rigid, structured schema. &lt;/p&gt;

&lt;p&gt;I started using &lt;code&gt;python-hcl2&lt;/code&gt; to turn &lt;code&gt;.tf&lt;/code&gt; files into Python dictionaries. For simple files, it worked beautifully. But real-world infrastructure isn't simple. When dealing with nested module calls, interpolations, and dynamic blocks, regex fails spectacularly. The AST is a deeply nested, unforgiving nightmare of dictionaries and lists.&lt;/p&gt;

&lt;p&gt;To give you an idea of what I was looking at, a simple 6-line resource block like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.project_name}-alb-${var.environment}"&lt;/span&gt;
  &lt;span class="nx"&gt;internal&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;subnets&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;...becomes this deeply nested list-of-dictionaries format in &lt;code&gt;python-hcl2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;resource&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;aws_lb&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${var.project_name}-alb-${var.environment}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;internal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;load_balancer_type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;security_groups&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${aws_security_group.alb.id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;subnets&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;${aws_subnet.public.id}&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The realization hit hard: translating disjointed, human-written infrastructure code into a rigid database schema wasn't going to be a quick hack. It was going to be technical trench warfare.&lt;/p&gt;

&lt;h2&gt;
  
  
  Designing the Schema
&lt;/h2&gt;

&lt;p&gt;To map the territory, I needed a database that understood relationships natively. Relational databases, with their rigid tables and expensive JOINs, were the wrong tool for a system defined by its interconnectedness. I chose Neo4j because it is built from the ground up for graph traversal, allowing me to naturally model and query recursive dependencies like &lt;code&gt;depends_on&lt;/code&gt; chains without writing thousands of lines of SQL CTEs.&lt;/p&gt;

&lt;p&gt;I designed the graph schema around three core Neo4j entities:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Nodes:&lt;/strong&gt; These represent the blocks of HCL. 

&lt;ul&gt;
&lt;li&gt;  A &lt;code&gt;Resource&lt;/code&gt; (e.g., &lt;code&gt;aws_instance&lt;/code&gt;) uniquely identified by its &lt;code&gt;file_path&lt;/code&gt; and &lt;code&gt;logical_name&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  A &lt;code&gt;Module&lt;/code&gt; uniquely identified by its &lt;code&gt;module_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;Variable&lt;/code&gt; and &lt;code&gt;Provider&lt;/code&gt; nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Properties:&lt;/strong&gt; The metadata attached to nodes, housing the actual configuration (names, files, line numbers, and AWS-specific attributes).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Relationships:&lt;/strong&gt; This is the wiring: 

&lt;ul&gt;
&lt;li&gt;  &lt;code&gt;[:DEPENDS_ON]&lt;/code&gt; connects explicit resource references.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;[:USES_VAR]&lt;/code&gt; connects resources and modules to the variables they consume.&lt;/li&gt;
&lt;li&gt;  &lt;code&gt;[:CONTAINS]&lt;/code&gt; links modules to their internal components.
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="c1"&gt;// The explicit wiring of the Multi-Repo Verse&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Module&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;id:&lt;/span&gt; &lt;span class="s2"&gt;"vpc"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:CONTAINS&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"aws_subnet"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:USES_VAR&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Variable&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"region"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="s2"&gt;"aws_instance"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:PROVIDED_BY&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Provider&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;name:&lt;/span&gt; &lt;span class="s2"&gt;"aws"&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It looks clean on a whiteboard. In practice, it required an intense normalization logic (an internal mapping script) to flatten the chaotic HCL dictionaries into clean, standardized dataclasses before they ever touched the database.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Mechanical Grind
&lt;/h2&gt;

&lt;p&gt;Populating the graph brought its own set of friction. It wasn't enough to just &lt;code&gt;CREATE&lt;/code&gt; nodes. If you run a scan twice, you don't want a duplicated infrastructure graph. &lt;/p&gt;

&lt;p&gt;Writing the Cypher ingestion queries was an exercise in idempotency. I lived and breathed the &lt;code&gt;MERGE&lt;/code&gt; clause, ensuring the graph updated existing nodes rather than cloning them. I batched transactions to handle hundreds of resources without locking up the database.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cypher"&gt;&lt;code&gt;&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;source:&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;id:&lt;/span&gt; &lt;span class="n"&gt;$sid&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;MATCH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="py"&gt;target:&lt;/span&gt;&lt;span class="n"&gt;Resource&lt;/span&gt; &lt;span class="ss"&gt;{&lt;/span&gt;&lt;span class="py"&gt;type:&lt;/span&gt; &lt;span class="n"&gt;$ttype&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="py"&gt;name:&lt;/span&gt; &lt;span class="n"&gt;$tname&lt;/span&gt;&lt;span class="ss"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;MERGE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;source&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="ss"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;:DEPENDS_ON&lt;/span&gt;&lt;span class="ss"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="n"&gt;target&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It was a mechanical, unglamorous grind. Traversing the ASTs, writing the parsing logic, and meticulously wiring the explicit pointers across files felt farther from "saving DevOps" than I had hoped. I was just moving data from text files into a graph. &lt;/p&gt;

&lt;h2&gt;
  
  
  Connecting the Dots
&lt;/h2&gt;

&lt;p&gt;And then came the moment that made it all worth it.&lt;/p&gt;

&lt;p&gt;After days of wrestling with dictionaries and Cypher queries, I wrapped the Neo4j database with a FastAPI backend and built an interactive Angular frontend using D3.js. &lt;/p&gt;

&lt;p&gt;I pointed the parser at a sprawling, complex Terraform directory, the kind that normally requires six open editor windows to mentally model, and initiated the first full infrastructure scan.&lt;/p&gt;

&lt;p&gt;When the web interface finally rendered, the result was immediate. The unreadable chaos of HCL text files organized itself into a clear visual model. The nodes snapped into a physics-based, force-directed graph. Solid lines perfectly connected the explicit &lt;code&gt;depends_on&lt;/code&gt; rules, variable references, and module outputs. &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.amazonaws.com%2Fuploads%2Farticles%2Fnie16tv8epqri7zrewny.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.amazonaws.com%2Fuploads%2Farticles%2Fnie16tv8epqri7zrewny.png" alt="Infra-Graph Frontend UI Screenshot" width="800" height="477"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Selecting a node instantly populated the sidebar with its exact configuration, pulling its properties directly from the local Neo4j instance. &lt;/p&gt;

&lt;p&gt;The "Tab Fatigue" vanished. The sprawling "Multi-Repo Verse" was no longer an invisible labyrinth; it was a single, zoomable UI. I could trace an interconnected path from an API Gateway to a subnet, without opening a single text file.&lt;/p&gt;

&lt;p&gt;I had mapped the territory. &lt;/p&gt;

&lt;p&gt;But as I stared at the perfect structural map, I realized something was missing. The map only showed what was &lt;em&gt;written&lt;/em&gt;. It didn't show what it was &lt;em&gt;meant&lt;/em&gt;. It didn't connect a security group port 80 to the load balancer that implicitly relied on it. It was strictly &lt;strong&gt;explicit&lt;/strong&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next up in Part 3: how I integrated local AI to discover the hidden truth.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Invisible Infrastructure Visible series index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-fog-of-code-4mcn"&gt;Part 1: The Fog of Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/mapping-the-territory-3n55"&gt;Part 2: Mapping the territory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-oracle-4kc3"&gt;Part 3: The Oracle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>infrastructureascode</category>
      <category>graph</category>
    </item>
    <item>
      <title>The Oracle</title>
      <dc:creator>Agustín Abero</dc:creator>
      <pubDate>Thu, 05 Mar 2026 02:57:45 +0000</pubDate>
      <link>https://forem.com/tico/the-oracle-4kc3</link>
      <guid>https://forem.com/tico/the-oracle-4kc3</guid>
      <description>&lt;p&gt;I thought I was done. After days of wrestling with Neo4j and flattening deeply nested Terraform ASTs, I finally had a beautiful, physics-based graph of my entire infrastructure. It was a masterpiece of explicit dependencies. But when I looked at the graph and asked myself a simple question: &lt;em&gt;Is my database actually exposed to the internet?&lt;/em&gt; My masterpiece couldn't show me the answer. It just stared silently back at me, rendering explicit syntax while missing the semantic truth.&lt;/p&gt;

&lt;p&gt;I had built a perfect map of my code, but code is not reality. &lt;/p&gt;




&lt;h2&gt;
  
  
  A quick recap
&lt;/h2&gt;

&lt;p&gt;In &lt;strong&gt;Part 1&lt;/strong&gt;, I talked about that overwhelming anxiety of flying blind when making changes to modern, distributed infrastructure. Tab Fatigue is real. The fear of the Butterfly Effect is real. To stop flying blind, I needed a map. In &lt;strong&gt;Part 2&lt;/strong&gt;, I showed you how I built that map. I created a Terraform parser that flattens deeply nested ASTs into a clean, normalized JSON format. I then imported that data into Neo4j, creating a physics-based graph where every resource is a node and every dependency is an edge and built a D3.js frontend that renders this graph in real-time, allowing me to visually trace connections across repositories and services.&lt;/p&gt;

&lt;p&gt;It was beautiful. It was explicit. And it was &lt;strong&gt;incomplete&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Limits of the "Perfect" Graph
&lt;/h2&gt;

&lt;p&gt;My Neo4j graph meticulously plotted every &lt;code&gt;depends_on&lt;/code&gt; block and every explicitly passed variable. If an ECS task definition referenced a specific Subnet ID, the D3.js frontend drew a solid, satisfying line between them. But modern infrastructure is defined just as much by what &lt;em&gt;isn't&lt;/em&gt; explicitly linked. &lt;/p&gt;

&lt;p&gt;When I configure a Security Group to allow inbound traffic on port 80, I am implicitly connecting it to a Load Balancer or a web server. To a human engineer, that dependency is obvious:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight hcl"&gt;&lt;code&gt;&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_security_group"&lt;/span&gt; &lt;span class="s2"&gt;"alb"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.project_name}-alb-sg"&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"Controls access to the ALB"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;

  &lt;span class="nx"&gt;ingress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"tcp"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;egress&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"-1"&lt;/span&gt;
    &lt;span class="nx"&gt;from_port&lt;/span&gt;   &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;to_port&lt;/span&gt;     &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="nx"&gt;cidr_blocks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"0.0.0.0/0"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb"&lt;/span&gt; &lt;span class="s2"&gt;"main"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;               &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.project_name}-alb-${var.environment}"&lt;/span&gt;
  &lt;span class="nx"&gt;internal&lt;/span&gt;           &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"application"&lt;/span&gt;
  &lt;span class="nx"&gt;security_groups&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_security_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;alb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="nx"&gt;subnets&lt;/span&gt;            &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;aws_subnet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;public&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb_target_group"&lt;/span&gt; &lt;span class="s2"&gt;"app"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;name&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"${var.project_name}-tg"&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;        &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;80&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;    &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;
  &lt;span class="nx"&gt;vpc_id&lt;/span&gt;      &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_vpc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
  &lt;span class="nx"&gt;target_type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"ip"&lt;/span&gt;

  &lt;span class="nx"&gt;health_check&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"/health"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;resource&lt;/span&gt; &lt;span class="s2"&gt;"aws_lb_listener"&lt;/span&gt; &lt;span class="s2"&gt;"front_end"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;load_balancer_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="nx"&gt;port&lt;/span&gt;              &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"80"&lt;/span&gt;
  &lt;span class="nx"&gt;protocol&lt;/span&gt;          &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"HTTP"&lt;/span&gt;

  &lt;span class="nx"&gt;default_action&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;type&lt;/span&gt;             &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"forward"&lt;/span&gt;
    &lt;span class="nx"&gt;target_group_arn&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;aws_lb_target_group&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;arn&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To my parser, they were just two isolated nodes floating in the void. An explicit map could tell me the database existed, but it couldn't trace the complex web of routing tables, internet gateways, and security groups to tell me if that database was bleeding data to the public internet.&lt;/p&gt;

&lt;p&gt;The frustration hit hard. I didn't just want to look at my infrastructure; I wanted to understand it. I realized that if I wanted answers to the richest, most critical questions, I couldn't just stare at a static map. Who better to explain the infrastructure to me than the infrastructure itself? What if I could &lt;em&gt;talk&lt;/em&gt; to it?&lt;/p&gt;

&lt;p&gt;The structural map was built, but it needed an intelligence layer. It needed an Oracle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Building the Oracle
&lt;/h2&gt;

&lt;p&gt;To build this intelligence layer, I knew I needed an LLM capable of deep semantic reasoning. But I also knew it had to be completely local. The entire point of Infra-Graph is sovereign visibility. I wasn't about to start piping my infrastructure blueprints to a third-party API, at least not yet. So, I integrated Ollama running Llama 3 locally.&lt;/p&gt;

&lt;p&gt;First, I tasked the LLM with uncovering the hidden semantic reality. I built an async pipeline that fed isolated resources to the model. Suddenly, the graph woke up. Dotted lines appeared in the UI.  &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.amazonaws.com%2Fuploads%2Farticles%2Fe4iilz8v0oj8utwoj3yk.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.amazonaws.com%2Fuploads%2Farticles%2Fe4iilz8v0oj8utwoj3yk.png" alt="Screenshot of explicit (gray) and semantic (green) relantionships" width="800" height="574"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The AI recognized that an IAM policy granting &lt;code&gt;s3:GetObject&lt;/code&gt; implied a dependency on a storage bucket. It saw the port 80 ingress rule and confidently drew an inferred connection to the Load Balancer. It was finding the silent links that regex could never catch.&lt;/p&gt;

&lt;p&gt;But finding the links wasn't enough. I wanted to ask questions.&lt;/p&gt;

&lt;p&gt;I built a conversational interface (a GraphRAG chatbot) directly into the UI. Now, when I asked, "Is my database exposed to the internet?", the system didn't just regurgitate text. It traversed the actual Neo4j graph, pulling the database, the attached security groups, the subnets, and the route tables into a tight, 1-hop context window. It fed that grounded, topological reality to the Llama 3 model.&lt;/p&gt;

&lt;p&gt;Because the LLM was grounded in the graph, hallucinations dropped to near-zero. It returned a precise, accurate answer, identifying the exact security group rule and trailing route that caused the exposure, along with actionable recommendations and security best practices to remediate it. &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.amazonaws.com%2Fuploads%2Farticles%2F7z3isdf2ov5n4tcokqly.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.amazonaws.com%2Fuploads%2Farticles%2F7z3isdf2ov5n4tcokqly.png" alt="Screenshot of a chat response from the LLM" width="414" height="616"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I no longer just had a map. I had an interactive test environment. Before I even ran a &lt;code&gt;terraform plan&lt;/code&gt;, I could ask my infrastructure: "If I delete this Security Group, what breaks down?" and get a deterministic answer translated into plain English. &lt;/p&gt;

&lt;p&gt;The "Multi-Repo Verse" was no longer a silent, anxiety-inducing labyrinth. I could finally converse with my infrastructure code, and testing configurations became as simple as asking a question.&lt;/p&gt;

&lt;p&gt;It's easy to trust the output of a &lt;code&gt;terraform plan&lt;/code&gt; to tell the whole story. But building &lt;strong&gt;the map&lt;/strong&gt; and integrating &lt;strong&gt;the Oracle&lt;/strong&gt; showed me that details are often hidden between the lines. What did I learned about the semantics of infrastructure code? What did this experiment in local, conversational infrastructure actually teach me about how we design and manage systems?&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next up in Part 4: we'll explore the practical lessons learned from this journey and discuss the real value of visual sovereignty.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Invisible Infrastructure Visible series index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-fog-of-code-4mcn"&gt;Part 1: The Fog of Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/mapping-the-territory-3n55"&gt;Part 2: Mapping the territory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-oracle-4kc3"&gt;Part 3: The Oracle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>infrastructureascode</category>
      <category>llm</category>
    </item>
    <item>
      <title>The Fog of Code</title>
      <dc:creator>Agustín Abero</dc:creator>
      <pubDate>Thu, 05 Mar 2026 02:51:35 +0000</pubDate>
      <link>https://forem.com/tico/the-fog-of-code-4mcn</link>
      <guid>https://forem.com/tico/the-fog-of-code-4mcn</guid>
      <description>&lt;p&gt;It starts with a simple question about a single Terraform variable. Soon, you're chasing configurations across dozens of browser tabs and scattered IDE folders, desperately trying to understand the reality of your infrastructure. You are flying blind in the 'Multi-Repo Verse,' and just when you think you've found a lifeline, you realize your AI copilot is confidently feeding you the wrong information.&lt;/p&gt;




&lt;h2&gt;
  
  
  Making Invisible Infrastructure Visible series introduction
&lt;/h2&gt;

&lt;p&gt;This post is Part 1 of the &lt;strong&gt;"Making Invisible Infrastructure Visible"&lt;/strong&gt; series. Over the next four posts, I will explore the complexity of managing large single or multi-repo Terraform coded infrastructure, the limitations of current tooling, and how I built &lt;strong&gt;Infra-Graph&lt;/strong&gt;, a local-first, AI-powered mapping tool, to bridge the gap between static code and its hidden semantic meaning. If you manage Terraform across multiple repositories, this series is for you.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigating the Fog of Code
&lt;/h2&gt;

&lt;p&gt;We’ve all been there. You open your IDE to make what should be a straightforward change: perhaps adjusting an ingress rule on an AWS Security Group. But in modern infrastructure, nothing exists in isolation. &lt;/p&gt;

&lt;p&gt;You find the resource block, but the security group ID is passed as a variable. You follow the variable to a &lt;code&gt;terraform.tfvars&lt;/code&gt; file, only to realize the actual value is sourced from a remote state data block defined in an entirely different repository. This is the reality of the "Multi-Repo Verse." It’s an architectural pattern designed to enforce boundaries, but the operational reality is a labyrinth. &lt;/p&gt;

&lt;p&gt;Within ten minutes, your screen is an overwhelming mosaic of browser tabs, GitHub search results, and overlapping VS Code workspaces. This phenomenon isn't just "context switching", it's &lt;strong&gt;Tab Fatigue&lt;/strong&gt;. It’s the mental exhaustion of trying to hold an entire, fragmented infrastructure state in your short-term memory. And beneath that exhaustion lies a deeper professional anxiety: the fear of the &lt;strong&gt;"Butterfly Effect."&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time you type &lt;code&gt;terraform apply&lt;/code&gt;, you brace yourself. &lt;em&gt;If I change this output here, what downstream service in another repository am I going to break?&lt;/em&gt; The check-in culture has given us version control, but it has hidden the semantic reality of our infrastructure behind walls of distributed text files. You are an architect, expected to design resilient systems, but on a daily basis, you are flying blind.&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.amazonaws.com%2Fuploads%2Farticles%2Foo2bt5awvxq6lfi56vnf.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.amazonaws.com%2Fuploads%2Farticles%2Foo2bt5awvxq6lfi56vnf.png" alt="Adrift in the multi-repo verse" width="800" height="350"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So, you do what any modern developer does: you reach for an AI copilot. You paste snippets of your &lt;code&gt;.tf&lt;/code&gt; files into the prompt, or maybe you even rely on an advanced copilot with repository-wide visibility, asking, &lt;em&gt;"Is it safe to remove port 80?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The AI responds immediately, with perfect grammar and absolute confidence. It explains why the change is safe, analyzing the code it has access to. For a brief second, you feel relief. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Then comes the Reality Check.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;You realize the AI didn't, &lt;em&gt;couldn't&lt;/em&gt;, know about the undocumented legacy load balancer defined in a separate AWS account's repository that relies on that exact port. The AI wasn't helping; it was hallucinating. It was telling you a beautiful, dangerous lie because it lacked the one thing that matters in infrastructure: &lt;em&gt;grounded truth&lt;/em&gt;. &lt;/p&gt;

&lt;p&gt;LLMs are powerful reasoning engines, but when fed fragmented text files, they are just creative guessers. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"They understand syntax, but they don't understand meaning."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They don't know that an open port implicitly connects two disparate resources. &lt;/p&gt;

&lt;p&gt;That was the turning point. I realized that if I wanted to stop flying blind, and if I wanted to actually harness AI without the risk of taking down production, I didn't need a better prompt. I needed a better map. I needed a way to ground the AI, and myself, in the actual reality of the infrastructure.&lt;/p&gt;

&lt;p&gt;In short, I needed a semantic map. In the next post, I will show you exactly what that map looks like and why it changes everything.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Next up in Part 2: how I mapped the terraform infrastructure territory, or so I thought...&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Making Invisible Infrastructure Visible series index
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-fog-of-code-4mcn"&gt;Part 1: The Fog of Code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/mapping-the-territory-3n55"&gt;Part 2: Mapping the territory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/tico/the-oracle-4kc3"&gt;Part 3: The Oracle&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>ai</category>
      <category>devops</category>
      <category>infrastructureascode</category>
      <category>agentic</category>
    </item>
  </channel>
</rss>
