<?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: Arshdeep Singh</title>
    <description>The latest articles on Forem by Arshdeep Singh (@iamarsh).</description>
    <link>https://forem.com/iamarsh</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%2F3688784%2F4088a929-0b92-4612-b110-631bd5cbe71c.png</url>
      <title>Forem: Arshdeep Singh</title>
      <link>https://forem.com/iamarsh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/iamarsh"/>
    <language>en</language>
    <item>
      <title>How I Added a Knowledge Graph to My AI Architecture Analyzer (and What I Learned About Graph Thinking)</title>
      <dc:creator>Arshdeep Singh</dc:creator>
      <pubDate>Tue, 24 Feb 2026 03:50:29 +0000</pubDate>
      <link>https://forem.com/iamarsh/how-i-added-a-knowledge-graph-to-my-ai-architecture-analyzer-and-what-i-learned-about-graph-543</link>
      <guid>https://forem.com/iamarsh/how-i-added-a-knowledge-graph-to-my-ai-architecture-analyzer-and-what-i-learned-about-graph-543</guid>
      <description>&lt;p&gt;So I built &lt;a href="https://tesseric.ca" rel="noopener noreferrer"&gt;Tesseric&lt;/a&gt; to analyze AWS architectures using Claude via Bedrock. You describe your system, it returns structured findings with security risks and remediation steps. Standard stuff.&lt;/p&gt;

&lt;p&gt;Then something weird happened.&lt;/p&gt;

&lt;p&gt;I was testing it with a 3-tier web app description - ALB in front, EC2 instances in the middle, RDS at the bottom. The analysis came back with findings like "EC2 instances in single AZ" and "RDS encryption disabled." Good. But I kept scrolling between findings thinking "wait, which layer was that again?"&lt;/p&gt;

&lt;p&gt;I was mentally reconstructing the architecture diagram from the text I'd just submitted.&lt;/p&gt;

&lt;p&gt;That felt backward. The AI clearly understood my architecture - it was extracting service names, understanding relationships, identifying which components had issues. So why was I stuck staring at a list?&lt;/p&gt;

&lt;p&gt;What if I could &lt;strong&gt;see&lt;/strong&gt; the architecture? Not just read about it.&lt;/p&gt;




&lt;h2&gt;
  
  
  The First Graph: Knowledge Accumulation
&lt;/h2&gt;

&lt;p&gt;Before I get to the fun part, let me rewind to where this started.&lt;/p&gt;

&lt;p&gt;After running a few dozen test reviews, I noticed patterns. Every finding mentioned AWS services. Reviews kept touching the same services. I started asking questions like "if EC2 has issues, does RDS usually have problems too?" or "which services appear together in high-severity findings?"&lt;/p&gt;

&lt;p&gt;I was doing graph traversal in my head on flat JSON responses.&lt;/p&gt;

&lt;p&gt;That's when I added Neo4j. Not for the individual reviews - for cross-analysis pattern detection. The schema is simple:&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="ss"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;:Analysis&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;:HAS_FINDING&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;:Finding&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;:INVOLVES_SERVICE&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;:AWSService&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The magic trick is &lt;code&gt;MERGE&lt;/code&gt;. In SQL, if EC2 appears in 50 analyses, you have 50 rows. In Neo4j, EC2 becomes &lt;strong&gt;one node&lt;/strong&gt;, and every analysis just adds another relationship to it.&lt;/p&gt;

&lt;p&gt;Query for service co-occurrence:&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;s1:&lt;/span&gt;&lt;span class="n"&gt;AWSService&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="py"&gt;r:&lt;/span&gt;&lt;span class="n"&gt;CO_OCCURS_WITH&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="py"&gt;s2:&lt;/span&gt;&lt;span class="n"&gt;AWSService&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;RETURN&lt;/span&gt; &lt;span class="n"&gt;s1.name&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;s2.name&lt;/span&gt;&lt;span class="ss"&gt;,&lt;/span&gt; &lt;span class="n"&gt;r.count&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="n"&gt;r.count&lt;/span&gt; &lt;span class="k"&gt;DESC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Result: "EC2 and RDS co-occur in 23 analyses. RDS and S3 in 17."&lt;/p&gt;

&lt;p&gt;That pattern only emerges from accumulated data. After a few dozen reviews, the graph starts telling you things about architecture patterns you didn't explicitly ask for.&lt;/p&gt;

&lt;p&gt;Graph writes happen async with &lt;code&gt;asyncio.create_task()&lt;/code&gt; so the core analysis stays fast. If Neo4j is down, the user never knows. Graceful degradation, not cascading failures.&lt;/p&gt;

&lt;p&gt;But here's where it got interesting.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Second Graph: Your Architecture, Visualized
&lt;/h2&gt;

&lt;p&gt;Once I had Neo4j working, I kept thinking "this is cool for meta-analysis, but users don't care about cross-analysis patterns for their first review."&lt;/p&gt;

&lt;p&gt;Then it hit me: the AI is already extracting AWS services. It knows EC2 connects to RDS. It knows the ALB sits in front. That's &lt;strong&gt;topology information&lt;/strong&gt;, not just a list.&lt;/p&gt;

&lt;p&gt;What if I asked Claude to return the actual architecture structure?&lt;/p&gt;

&lt;p&gt;I updated the Bedrock prompt:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Extract the architecture topology: which services exist, how they connect, what layer they're in. Return as a structured graph."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It worked. First try.&lt;/p&gt;

&lt;p&gt;Submit "ALB in front of two EC2 instances connecting to an RDS database" and Claude returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"services"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alb-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ALB"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"layer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"presentation"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ec2-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"EC2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"layer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"application"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rds-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"RDS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"layer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"connections"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"alb-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ec2-1"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"from"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ec2-1"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"to"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"rds-1"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now I could draw it. React-Flow + dagre for auto-layout. Color-code by layer (blue for frontend, green for backend, purple for data). Add borders based on severity (red if service has HIGH findings, orange for MEDIUM).&lt;/p&gt;

&lt;p&gt;The result: you describe your architecture in text or upload a diagram, and Tesseric &lt;strong&gt;draws it back to you&lt;/strong&gt; with visual problem indicators.&lt;/p&gt;

&lt;p&gt;That's the moment users go "oh shit, it actually understood."&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Matters (The Graph Thinking Part)
&lt;/h2&gt;

&lt;p&gt;Here's what I'm learning about graphs: they change &lt;strong&gt;how you think about your data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In SQL, you model entities. In graphs, you model relationships. That shift completely changes what questions feel natural to ask.&lt;/p&gt;

&lt;p&gt;With Neo4j knowledge graph, I can ask "show me all analyses where EC2 and RDS both appeared in HIGH severity findings" and get a visual cluster showing that risk pattern across time.&lt;/p&gt;

&lt;p&gt;With architecture topology, I can click an EC2 node and instantly see which findings affect it. Or click a finding card and watch the affected services highlight on the diagram. Bidirectional linking that feels spatial, not tabular.&lt;/p&gt;

&lt;p&gt;The architecture visualization isn't just prettier than a list - it's &lt;strong&gt;spatially encoded&lt;/strong&gt;. You see the ALB at the top, EC2 in the middle, RDS at the bottom, and your brain instantly knows "that's a 3-tier app." You don't have to read it, you just know.&lt;/p&gt;

&lt;p&gt;When three findings all point to the same EC2 node with a red border, you see the critical risk cluster without reading a single word.&lt;/p&gt;

&lt;p&gt;Humans are visual creatures. We're ridiculously good at pattern recognition when information is laid out spatially. A graph lets you leverage that.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Stack
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Backend:&lt;/strong&gt; FastAPI + Python 3.11, AWS Bedrock (Claude 3.5 Haiku/Sonnet), Neo4j AuraDB&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frontend:&lt;/strong&gt; Next.js 14, TypeScript, React-Flow, dagre for auto-layout&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cost:&lt;/strong&gt; ~$0.011 per text review, ~$0.028 per image analysis. Neo4j free tier. Railway + Vercel hosting ~$5/month. At 100 reviews/day, that's $33/month in AI costs.&lt;/p&gt;

&lt;p&gt;React-Flow is genuinely well-designed. Custom nodes, edges, built-in minimap. Got a working graph in a few hours. Dagre handles hierarchical layout for architecture topology, force-directed for knowledge graph.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Bigger Realization
&lt;/h2&gt;

&lt;p&gt;I thought I was building a knowledge graph to analyze trends across reviews. That was useful.&lt;/p&gt;

&lt;p&gt;But the architecture topology visualization - showing users their own system drawn back to them with problem indicators - that's the feature that makes people go "whoa."&lt;/p&gt;

&lt;p&gt;It's the difference between "here's a list of issues" and "here's your architecture, and here's exactly where the problems are."&lt;/p&gt;

&lt;p&gt;Spatial thinking beats text lists. Graphs give you that spatial encoding almost for free.&lt;/p&gt;

&lt;p&gt;If you're building something with interconnected entities - services, users, dependencies, networks - you're probably fighting SQL when a graph would make those queries trivial.&lt;/p&gt;

&lt;p&gt;And if you're analyzing architectures or anything with structure? Don't just return text. Draw it. Show it. Let people see the shape of the problem.&lt;/p&gt;

&lt;p&gt;That's when AI stops feeling like a chatbot and starts feeling like it actually understands.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try It
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Live demo:&lt;/strong&gt; &lt;a href="https://tesseric.ca" rel="noopener noreferrer"&gt;tesseric.ca&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Describe your AWS architecture or upload a diagram. Watch it draw your system back to you with visual problem indicators. Then explore the knowledge graph to see how services and findings connect across analyses.&lt;/p&gt;

&lt;p&gt;Built with AWS Bedrock, Neo4j AuraDB, FastAPI, Next.js, and React-Flow. Open source. Brutally honest feedback mode included.&lt;/p&gt;




&lt;p&gt;Check out the code at &lt;a href="https://github.com/iamarsh/tesseric" rel="noopener noreferrer"&gt;github.com/iamarsh/tesseric&lt;/a&gt;&lt;/p&gt;

</description>
      <category>neo4j</category>
      <category>aws</category>
      <category>nextjs</category>
      <category>graphdatabase</category>
    </item>
    <item>
      <title>Building a Config Drift Detector for AWS (with Snapshots, Lambdas, and a Next.js Dashboard)</title>
      <dc:creator>Arshdeep Singh</dc:creator>
      <pubDate>Mon, 19 Jan 2026 04:14:01 +0000</pubDate>
      <link>https://forem.com/iamarsh/building-a-config-drift-detector-for-aws-with-snapshots-lambdas-and-a-nextjs-dashboard-1k49</link>
      <guid>https://forem.com/iamarsh/building-a-config-drift-detector-for-aws-with-snapshots-lambdas-and-a-nextjs-dashboard-1k49</guid>
      <description>&lt;p&gt;Configuration drift is one of those problems that seems minor—until it isn’t.&lt;/p&gt;

&lt;p&gt;A “temporary” security group rule stays open for weeks.&lt;br&gt;&lt;br&gt;
A manual change fixes a production incident but never makes it back to Terraform.&lt;br&gt;&lt;br&gt;
An EC2 instance gets a one-off flag “just for now” and quietly becomes the special case nobody wants to touch.&lt;/p&gt;

&lt;p&gt;Over time, these tiny deviations compound into outages, security gaps, and a lot of “who changed what, when?” energy. This article walks through how I designed and built a lightweight &lt;strong&gt;Config Drift Detector&lt;/strong&gt; for AWS that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Takes regular snapshots of your infrastructure.&lt;/li&gt;
&lt;li&gt;Compares them against a moving baseline.&lt;/li&gt;
&lt;li&gt;Surfaces drift events in a &lt;strong&gt;Next.js dashboard&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Sends Slack alerts for high/critical changes.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  High-level architecture
&lt;/h2&gt;

&lt;p&gt;Here’s the architecture diagram used in this article:&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%2Fg6vgb1o83lqhb1t0t6zb.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%2Fg6vgb1o83lqhb1t0t6zb.png" alt="Config Drift Detector architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At a glance:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AWS Services&lt;/strong&gt; (e.g., EC2, Security Groups) are sampled on a schedule.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Snapshot Lambda&lt;/strong&gt; writes raw JSON snapshots to S3 and Supabase/PostgreSQL.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Detect Lambda&lt;/strong&gt; compares the latest snapshot to the previous baseline to detect drift.&lt;/li&gt;
&lt;li&gt;An &lt;strong&gt;Alert Lambda&lt;/strong&gt; writes drift events, updates baselines, and optionally sends Slack alerts.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;Next.js dashboard&lt;/strong&gt; polls a lightweight API backed by Supabase/PostgreSQL to show drifts and baselines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The rest of the article breaks this down from the perspective of an SRE/DevOps engineer who wants fast feedback, clear audit trails, and a UI that doesn’t feel like a side project.&lt;/p&gt;




&lt;h2&gt;
  
  
  Design goals and constraints
&lt;/h2&gt;

&lt;p&gt;When I scoped this project, I set a few explicit goals:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Detect meaningful drift&lt;/strong&gt;, not every single field that changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Keep the architecture boring and observable&lt;/strong&gt;: managed services over bespoke infra.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make the UI operator-friendly&lt;/strong&gt;: think SRE console, not toy dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Be small enough to build solo&lt;/strong&gt;, but credible enough to show to senior engineers or hiring managers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there, the architecture fell naturally into four pieces:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Snapshot pipeline.&lt;/li&gt;
&lt;li&gt;Drift detection engine.&lt;/li&gt;
&lt;li&gt;Alerting and audit trail.&lt;/li&gt;
&lt;li&gt;Web dashboard.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  1. Snapshot pipeline
&lt;/h2&gt;

&lt;h3&gt;
  
  
  What gets snapshotted?
&lt;/h3&gt;

&lt;p&gt;To start, I focused on a narrow but high-impact slice of AWS resources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;EC2 instances&lt;/strong&gt;: lifecycle, instance type, tags.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security groups&lt;/strong&gt;: inbound/outbound rules and attached resources.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are common sources of “quick fixes” and “just for debugging” changes that later turn into security and reliability problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  How snapshots flow through the system
&lt;/h3&gt;

&lt;p&gt;The snapshot pipeline revolves around a scheduled Lambda:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trigger&lt;/strong&gt;: EventBridge rule runs every 30 minutes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Snapshot Lambda&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Calls AWS APIs to list EC2 instances and security groups.&lt;/li&gt;
&lt;li&gt;Normalizes the data into a stable JSON shape.&lt;/li&gt;
&lt;li&gt;Writes each snapshot to:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3&lt;/strong&gt;: raw, timestamped JSON (e.g., &lt;code&gt;YYYY-MM-DD/HH-MM-SS.json&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Supabase/PostgreSQL&lt;/strong&gt;: summarized snapshot metadata for faster queries later.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;cheap, append-only log&lt;/strong&gt; of the world as it looked at each point in time (S3).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;queryable state&lt;/strong&gt; for dashboards and drift detection (Postgres).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Drift detection engine
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Baselines vs snapshots
&lt;/h3&gt;

&lt;p&gt;The system uses a simple mental model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;snapshot&lt;/strong&gt; is “what the world looks like now”.&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;baseline&lt;/strong&gt; is “what we expect the world to look like”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time a new snapshot arrives, the &lt;strong&gt;Detect Lambda&lt;/strong&gt; compares it to the current baseline:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;For each resource (instance, security group, etc.):

&lt;ul&gt;
&lt;li&gt;Map by a stable identifier (e.g., instance ID).&lt;/li&gt;
&lt;li&gt;Compare relevant fields that matter for reliability/security.&lt;/li&gt;
&lt;li&gt;Ignore noisy, fast-changing fields (e.g., some timestamps).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The output is a set of &lt;strong&gt;drift events&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ADDED&lt;/code&gt;: resource exists in snapshot but not in baseline.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;REMOVED&lt;/code&gt;: resource exists in baseline but not in snapshot.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;MODIFIED&lt;/code&gt;: resource exists in both, but relevant fields differ.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each drift event carries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Resource metadata (ID, type, environment).&lt;/li&gt;
&lt;li&gt;Which fields changed (before vs after).&lt;/li&gt;
&lt;li&gt;A severity classification (more on that below).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once detection is done, the baseline is &lt;strong&gt;updated forward&lt;/strong&gt; so the system tracks drift incrementally rather than replaying from the beginning every time.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. Alerting and severity
&lt;/h2&gt;

&lt;p&gt;Not all drift is created equal. Changing a tag is not the same as opening SSH to the world.&lt;/p&gt;

&lt;p&gt;To make alerts meaningful, drift events are classified by severity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CRITICAL&lt;/strong&gt;: Security group changes that materially expand exposure (e.g., &lt;code&gt;0.0.0.0/0&lt;/code&gt; on sensitive ports).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;HIGH&lt;/strong&gt;: EC2 changes that alter lifecycle or network placement in risky ways.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MEDIUM&lt;/strong&gt;: Configuration changes that might affect behavior but aren’t obviously dangerous.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LOW&lt;/strong&gt;: Tag-only changes and other low-risk metadata updates.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;strong&gt;Alert Lambda&lt;/strong&gt; is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Writing drift events into Supabase/PostgreSQL for later querying.&lt;/li&gt;
&lt;li&gt;Sending Slack notifications for &lt;strong&gt;HIGH&lt;/strong&gt; and &lt;strong&gt;CRITICAL&lt;/strong&gt; drifts:

&lt;ul&gt;
&lt;li&gt;Channel: e.g., &lt;code&gt;#infra-alerts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Message includes: resource, environment, severity, and a short description.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This keeps the Slack noise under control while still providing a tight feedback loop for changes that actually matter.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. The Next.js dashboard
&lt;/h2&gt;

&lt;p&gt;The dashboard is intentionally simple, but optimized for SRE/DevOps workflows rather than demos.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key views
&lt;/h3&gt;

&lt;p&gt;The app exposes three main pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Dashboard&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;High-level stats: number of active drifts, baselines, and monitored environments.&lt;/li&gt;
&lt;li&gt;Recent drifts, sorted by time and severity.&lt;/li&gt;
&lt;li&gt;Baseline overview (which environments are covered, which baselines are stale).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Drifts&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Table of drift events with:&lt;/li&gt;
&lt;li&gt;Severity chips.&lt;/li&gt;
&lt;li&gt;Resource and environment.&lt;/li&gt;
&lt;li&gt;Type of drift (&lt;code&gt;ADDED&lt;/code&gt;, &lt;code&gt;REMOVED&lt;/code&gt;, &lt;code&gt;MODIFIED&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Detected time.&lt;/li&gt;
&lt;li&gt;Filters for severity, status, and environment.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Baselines&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;List of baselines with:&lt;/li&gt;
&lt;li&gt;Name, environment.&lt;/li&gt;
&lt;li&gt;Status (Active / Stale / Archived).&lt;/li&gt;
&lt;li&gt;Last updated time.&lt;/li&gt;
&lt;li&gt;Links into the Drifts view filtered by baseline.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  Data flow
&lt;/h3&gt;

&lt;p&gt;The dashboard queries Supabase/PostgreSQL via a light API layer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Fetch lists of drifts and baselines.&lt;/li&gt;
&lt;li&gt;Support simple aggregation for dashboard metrics (e.g., count of active drifts).&lt;/li&gt;
&lt;li&gt;Polls frequently enough to make the UI feel “live” without hammering the backend.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The focus is on &lt;strong&gt;operational clarity&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It should be easy to answer:

&lt;ul&gt;
&lt;li&gt;“What changed recently?”&lt;/li&gt;
&lt;li&gt;“Is this environment drifting more than others?”&lt;/li&gt;
&lt;li&gt;“Which baselines are out of date?”&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why this architecture?
&lt;/h2&gt;

&lt;p&gt;This design deliberately avoids premature complexity:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Serverless for cadence-based work&lt;/strong&gt;: Lambdas plus an EventBridge scheduler are a natural fit for “run every N minutes and compare snapshots”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;S3 + Postgres&lt;/strong&gt; gives both durability and queryability:

&lt;ul&gt;
&lt;li&gt;S3 for raw history.&lt;/li&gt;
&lt;li&gt;Postgres for fast reads and simple aggregations.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Next.js dashboard&lt;/strong&gt;:

&lt;ul&gt;
&lt;li&gt;Easy to deploy.&lt;/li&gt;
&lt;li&gt;Easy to iterate on UX.&lt;/li&gt;
&lt;li&gt;Pairs well with Supabase as a backend.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;At the same time, it leaves room to grow:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add more resource types beyond EC2 and security groups.&lt;/li&gt;
&lt;li&gt;Introduce per-environment baselines and multi-account support.&lt;/li&gt;
&lt;li&gt;Expand the dashboard with timelines, diff views, and richer filters.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Future improvements
&lt;/h2&gt;

&lt;p&gt;There are several natural extensions to this architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Better diff views&lt;/strong&gt;: show structured diffs (field-level before/after) in the UI, not just “modified”.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Alert policies&lt;/strong&gt;: configurable rules to decide which drifts should alert where (Slack, email, etc.).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-cloud support&lt;/strong&gt;: abstract snapshot/detect logic to handle other providers.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drift remediation hooks&lt;/strong&gt;: for certain classes of drift, trigger runbooks or automated remediation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The current version focuses on the basics: detect, classify, alert, and visualize. That’s already enough to catch the most painful “someone changed prod” issues and to tell a coherent story in a portfolio or blog post.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;Config Drift Detector started as a way to make configuration changes more visible, but it also became a nice exercise in &lt;strong&gt;small, focused architecture&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;One clear data flow from AWS → snapshots → drift detection → alerts → dashboard.&lt;/li&gt;
&lt;li&gt;Minimal moving parts, each doing one job well.&lt;/li&gt;
&lt;li&gt;A UI that reflects how operators actually investigate and respond to drift.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re interested in configuration management, SRE tooling, or just want a portfolio project that goes beyond CRUD, building something like this is a great way to explore the intersection of &lt;strong&gt;cloud architecture&lt;/strong&gt;, &lt;strong&gt;observability&lt;/strong&gt;, and &lt;strong&gt;developer experience&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>devops</category>
      <category>typescript</category>
      <category>sre</category>
    </item>
    <item>
      <title>Stop Drawing Stacks: Seeing Drupal on AWS as a Graph</title>
      <dc:creator>Arshdeep Singh</dc:creator>
      <pubDate>Sat, 17 Jan 2026 23:01:30 +0000</pubDate>
      <link>https://forem.com/iamarsh/stop-drawing-stacks-seeing-drupal-on-aws-as-a-graph-1j1b</link>
      <guid>https://forem.com/iamarsh/stop-drawing-stacks-seeing-drupal-on-aws-as-a-graph-1j1b</guid>
      <description>&lt;p&gt;Every architecture diagram you've ever drawn is a graph. The boxes are nodes; the arrows are edges. Yet most teams treat those diagrams as static documentation rather than a working model they can reason about mathematically. Once you start applying graph theory to how Drupal and AWS actually behave at runtime, hard problems—latency budgets, failure blast radius, refactoring priorities—become graph problems you already know how to solve.&lt;/p&gt;

&lt;h2&gt;
  
  
  Your platform is a graph
&lt;/h2&gt;

&lt;p&gt;A graph is simply a set of nodes (vertices) connected by edges. In a Drupal-on-AWS platform:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Drupal nodes&lt;/strong&gt;: content types, configuration entities, services in the container, event subscribers, routes, caches.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AWS nodes&lt;/strong&gt;: VPCs, subnets, security groups, ALBs, ECS tasks, Lambda functions, RDS clusters, S3 buckets, SQS queues, external SaaS (Auth0, Salesforce).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edges&lt;/strong&gt;: "calls API", "publishes to queue", "allowed by security group", "replicates to region", "feeds dashboard".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once you accept this framing, you stop asking vague questions like "Is this architecture clean?" and start asking precise questions like "What's the shortest failure path from this AWS primitive to a broken SLO?"&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%2Fma3bx2jz0c0y74k0allh.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%2Fma3bx2jz0c0y74k0allh.png" alt="AWS as an infrastructure graph" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Drupal as a dependency graph
&lt;/h2&gt;

&lt;p&gt;Drupal is usually described in terms of content types, views, and modules. Operationally, it behaves like several overlapping directed graphs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration graph
&lt;/h3&gt;

&lt;p&gt;Entity types, bundles, fields, field formatters, views, and access rules form a dependency graph. Change a field storage definition and you can cascade through displays, views, REST resources, and integrations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Runtime call graph
&lt;/h3&gt;

&lt;p&gt;The Symfony service container, event subscribers, and middleware stack define a call graph. Every HTTP request walks a specific path through this graph—touching routing, access checking, entity loading, rendering, and caching nodes in sequence.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permission graph
&lt;/h3&gt;

&lt;p&gt;Roles, permissions, and route access callbacks form yet another graph. Model "who can reach what" as directed edges and you can visualize privilege-escalation risks as unexpectedly short paths between low-privilege and high-privilege nodes.&lt;/p&gt;

&lt;p&gt;A single anonymous page view is actually a walk through all three subgraphs simultaneously. Understanding that walk is the first step to optimizing 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%2Fmvmqklt7aur23tse7e8z.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%2Fmvmqklt7aur23tse7e8z.png" alt="Drupal as a dependency graph" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  AWS as an infrastructure graph
&lt;/h2&gt;

&lt;p&gt;AWS architectures are already drawn as graphs; graph theory just makes the math explicit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network topology graph
&lt;/h3&gt;

&lt;p&gt;VPCs, subnets, route tables, security groups, and NACLs form a reachability graph. Two nodes can only communicate if there's a valid path through this graph—no path, no packets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data-flow graph
&lt;/h3&gt;

&lt;p&gt;S3, Kinesis, SQS, SNS, Lambda, and analytics services form directed acyclic graphs (DAGs) of data transformations. Your ETL pipeline, event-driven workflows, and observability stack are all DAGs whether you drew them that way or not.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service dependency graph
&lt;/h3&gt;

&lt;p&gt;ECS services, Lambda functions, RDS, ElastiCache, and external APIs form a runtime dependency graph. Traces and flow logs let you infer this graph from production traffic rather than relying on outdated documentation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Four graph concepts that sharpen your thinking
&lt;/h2&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%2F3emrmfpzn66zlyva2woa.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%2F3emrmfpzn66zlyva2woa.png" alt="Graph theory concepts in software architecture" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Paths and latency
&lt;/h3&gt;

&lt;p&gt;User-perceived latency is the weighted sum of edges along the shortest path from browser to data and back. CDN, WAF, ALB, PHP-FPM, Redis, RDS—each hop adds weight.&lt;/p&gt;

&lt;p&gt;Reducing latency means either removing nodes from the path (for example, serving from edge cache) or reducing edge weights (for example, connection pooling, read replicas). Frame every performance optimization as a path-shortening or weight-reduction exercise.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Minimum cuts and resilience
&lt;/h3&gt;

&lt;p&gt;A minimum cut is the smallest set of nodes or edges whose removal disconnects the graph. In infrastructure terms, it's your single points of failure: the lone RDS writer, the shared Redis cluster, the internal auth service everything depends on.&lt;/p&gt;

&lt;p&gt;High-availability design is the art of making minimum cuts large and expensive. Multi-AZ RDS, stateless Drupal behind multiple ALBs, and regional failover all increase the size of the cut an outage must hit.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Centrality and hotspots
&lt;/h3&gt;

&lt;p&gt;Betweenness centrality measures how often a node sits on the shortest path between other nodes. High-centrality nodes are chokepoints: an API gateway every request flows through, a monolithic "integration" module in Drupal, a single SQS queue feeding multiple consumers.&lt;/p&gt;

&lt;p&gt;Focus observability, rate limiting, and capacity planning on high-centrality nodes. Their failure has a disproportionate blast radius. If you can't eliminate centrality, at least instrument it.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Strongly connected components and coupling
&lt;/h3&gt;

&lt;p&gt;A strongly connected component (SCC) is a subset of nodes where every node is reachable from every other. In practice, SCCs represent tightly coupled subsystems: Drupal plus a specific internal API, a queue, and a Lambda that all depend on each other.&lt;/p&gt;

&lt;p&gt;Changes to one node in an SCC risk breaking the others. Identify SCCs before refactoring; break them apart by introducing explicit, versioned contracts—APIs, schemas, events—rather than implicit runtime dependencies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using graph thinking day to day
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architecture reviews
&lt;/h3&gt;

&lt;p&gt;Instead of subjective "Is this clean?", ask:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's the longest path in the critical user journey?&lt;/li&gt;
&lt;li&gt;What's the minimum cut between the user and the SLO?&lt;/li&gt;
&lt;li&gt;Which node has the highest centrality?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Incident analysis
&lt;/h3&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%2Fg67ypvf3pc23wf7s8us6.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%2Fg67ypvf3pc23wf7s8us6.png" alt="Incident analysis as a graph walk" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Reconstruct failures as graph walks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which edge broke?&lt;/li&gt;
&lt;li&gt;What alternative paths existed (or didn't)?&lt;/li&gt;
&lt;li&gt;Which node's centrality amplified the blast radius?&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Modernization roadmaps
&lt;/h3&gt;

&lt;p&gt;Prioritize refactors by graph metrics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Decompose the highest-centrality Drupal module first.&lt;/li&gt;
&lt;li&gt;Replace a single massive integration edge with a message-driven subgraph.&lt;/li&gt;
&lt;li&gt;Break apart the largest SCC into independent, deployable units.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Where to start
&lt;/h2&gt;

&lt;p&gt;You don't need a graph database to benefit from graph thinking. Start with one exercise:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Pick a critical user journey (for example, authenticated page load, checkout, or form submission).&lt;/li&gt;
&lt;li&gt;Sketch it as a directed graph: every service, cache, database, and external API is a node; every call or dependency is an edge.&lt;/li&gt;
&lt;li&gt;Label edges with latency (p50, p99) and availability (historical uptime).&lt;/li&gt;
&lt;li&gt;Identify the minimum cut and the highest-centrality node.&lt;/li&gt;
&lt;li&gt;Use those findings to prioritize your next performance or reliability improvement.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Once you see your Drupal-on-AWS platform as a graph, decisions get crisper. You stop guessing at complexity and start operating on the structure that's actually there.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>drupal</category>
      <category>graphtheory</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Automating Performance Engineering with Claude Code and New Relic MCP</title>
      <dc:creator>Arshdeep Singh</dc:creator>
      <pubDate>Sun, 11 Jan 2026 21:52:26 +0000</pubDate>
      <link>https://forem.com/iamarsh/automating-performance-engineering-with-claude-code-and-new-relic-mcp-3j12</link>
      <guid>https://forem.com/iamarsh/automating-performance-engineering-with-claude-code-and-new-relic-mcp-3j12</guid>
      <description>&lt;p&gt;For a long time, my “performance engineering workflow” as a Tech Lead looked like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log into New Relic&lt;/li&gt;
&lt;li&gt;Run a handful of NRQL queries&lt;/li&gt;
&lt;li&gt;Inspect slow transactions and error traces&lt;/li&gt;
&lt;li&gt;Map issues back to Drupal code&lt;/li&gt;
&lt;li&gt;Estimate effort and impact&lt;/li&gt;
&lt;li&gt;Create JIRA tickets with enough context&lt;/li&gt;
&lt;li&gt;Post updates in Teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It’s valuable work, but it is also repetitive, mechanical, and very interrupt‑friendly. It was quietly costing me 2-3 hours every week.&lt;/p&gt;

&lt;p&gt;So I automated it.&lt;/p&gt;

&lt;p&gt;This post walks through the workflow I built using &lt;strong&gt;Claude Code&lt;/strong&gt;, the &lt;strong&gt;New Relic MCP&lt;/strong&gt;, &lt;strong&gt;Jira&lt;/strong&gt;, and &lt;strong&gt;Microsoft Teams&lt;/strong&gt; to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Continuously analyze performance and error data&lt;/li&gt;
&lt;li&gt;Generate structured root cause analysis with code references&lt;/li&gt;
&lt;li&gt;Create and prioritize Jira tickets&lt;/li&gt;
&lt;li&gt;Notify the team with severity‑specific alerts&lt;/li&gt;
&lt;li&gt;Optionally draft pull requests for straightforward fixes&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Why This Was Worth Automating
&lt;/h2&gt;

&lt;p&gt;As a Tech Lead on a large Drupal platform, my time is best spent on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Architecture and design decisions&lt;/li&gt;
&lt;li&gt;Reviewing high‑impact changes&lt;/li&gt;
&lt;li&gt;Mentoring and unblocking engineers&lt;/li&gt;
&lt;li&gt;Shaping priorities with product and leadership&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But performance issues don’t care about calendars.&lt;/p&gt;

&lt;p&gt;Every incident or regression forced me back into the same manual loop: query New Relic, decipher traces, reverse‑engineer root causes, and turn them into actionable tickets. It was important, but it wasn’t leverage.&lt;/p&gt;

&lt;p&gt;The workflow in this post exists to do one thing: &lt;strong&gt;remove the mechanical part of performance engineering while keeping the judgment and risk decisions in human hands&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  High‑Level Architecture
&lt;/h2&gt;

&lt;p&gt;At a high level, the system looks like this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;New Relic&lt;/strong&gt; collects APM metrics, traces, and error data from our Drupal application.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Claude Code&lt;/strong&gt; (via the New Relic MCP) pulls that data, analyzes it, and decides what’s worth acting on.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Jira&lt;/strong&gt; receives structured issues with metrics, root causes, effort estimates, and links back to New Relic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Microsoft Teams&lt;/strong&gt; gets severity‑color‑coded notifications so the right people see the right issues at the right time.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub&lt;/strong&gt; (optionally) receives draft pull requests for straightforward fixes the AI can safely propose.&lt;/li&gt;
&lt;/ul&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%2Fmj8j7mqy0b6saqco01jq.webp" 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%2Fmj8j7mqy0b6saqco01jq.webp" alt="Automating Performance Engineering with Claude Code and New Relic MCP" width="800" height="343"&gt;&lt;/a&gt; &lt;br&gt;
See full resolution image &lt;a href="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mj8j7mqy0b6saqco01jq.webp" rel="noopener noreferrer"&gt;here&lt;/a&gt;. This architecture keeps responsibilities clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New Relic is the source of truth.&lt;/li&gt;
&lt;li&gt;AI is used for interpretation and orchestration.&lt;/li&gt;
&lt;li&gt;Jira and Teams are where work and communication actually happen.&lt;/li&gt;
&lt;li&gt;Humans stay firmly in the decision loop.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Workflow End‑to‑End
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Phase 1: Data Collection from New Relic
&lt;/h3&gt;

&lt;p&gt;On demand (or via a scheduled script), the workflow starts with a single instruction, e.g.:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Execute New Relic performance analysis for production last 1 hour”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Behind the scenes, Claude Code uses the New Relic MCP to run a focused set of NRQL queries:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Slow transactions&lt;/strong&gt;: endpoints with response time above a threshold&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error rates&lt;/strong&gt;: exception types, messages, and affected routes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Database performance&lt;/strong&gt;: slow queries and N+1‑style patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Open incidents and application health&lt;/strong&gt;: alerts, Apdex, throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The goal here is not to recreate the entire dashboard - it’s to pull just enough data for a useful decision.&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%2Ftivq70njkpgvteal36mb.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%2Ftivq70njkpgvteal36mb.png" alt="Claude Code workflow performation automation" width="800" height="437"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 2: AI‑Powered Root Cause Analysis
&lt;/h3&gt;

&lt;p&gt;Claude Code then takes that raw telemetry and turns it into something my team can act on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Groups slow transactions into meaningful units (e.g., &lt;code&gt;/reports/latest&lt;/code&gt;, specific admin pages)&lt;/li&gt;
&lt;li&gt;Connects issues to Drupal modules, controllers, or custom code paths&lt;/li&gt;
&lt;li&gt;Distinguishes between:

&lt;ul&gt;
&lt;li&gt;one‑off spikes vs. consistent degradation,&lt;/li&gt;
&lt;li&gt;user‑facing vs. admin‑only issues,&lt;/li&gt;
&lt;li&gt;backend jobs vs. interactive requests&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Hypothesizes root causes:

&lt;ul&gt;
&lt;li&gt;N+1 queries&lt;/li&gt;
&lt;li&gt;missing cache tags/contexts&lt;/li&gt;
&lt;li&gt;heavy external API calls&lt;/li&gt;
&lt;li&gt;misconfigured database access patterns&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;The important part: &lt;strong&gt;this analysis is always explainable&lt;/strong&gt;. If the suggestion is wrong, it is wrong in a way that is obvious when you read the ticket.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 3: Priority, Impact, and Story Points
&lt;/h3&gt;

&lt;p&gt;Performance work always competes with feature work, so the system needs to express impact in a language the team understands.&lt;/p&gt;

&lt;p&gt;The workflow classifies each issue as &lt;strong&gt;Critical&lt;/strong&gt;, &lt;strong&gt;High&lt;/strong&gt;, or &lt;strong&gt;Medium&lt;/strong&gt; based on thresholds like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Response time ranges&lt;/li&gt;
&lt;li&gt;Error rate percentages&lt;/li&gt;
&lt;li&gt;Whether the issue is user‑visible&lt;/li&gt;
&lt;li&gt;Whether functionality is partially or fully degraded&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From there, it estimates story points (1/2/3/5/8) using a simple heuristic:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complexity (single query tweak vs. cross‑module change)&lt;/li&gt;
&lt;li&gt;Scope (one endpoint vs. a subsystem)&lt;/li&gt;
&lt;li&gt;Risk (low‑risk cache change vs. behavior‑changing refactor)&lt;/li&gt;
&lt;li&gt;Effort (hours vs days)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are not perfect, but they are consistent – which is often more useful than “perfect but ad hoc”.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 4: Jira Ticket Generation
&lt;/h3&gt;

&lt;p&gt;For every actionable issue, the workflow calls the Jira API to create a ticket in the current active sprint.&lt;/p&gt;

&lt;p&gt;Each ticket includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A descriptive title (e.g. &lt;code&gt;[Performance] /reports/latest endpoint – 650% response time increase&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;A summary of the issue and affected environment&lt;/li&gt;
&lt;li&gt;Metrics:

&lt;ul&gt;
&lt;li&gt;average and p95 response time&lt;/li&gt;
&lt;li&gt;error rate&lt;/li&gt;
&lt;li&gt;timeframe and estimated impact&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Root cause analysis in plain language&lt;/li&gt;

&lt;li&gt;Affected code (modules, file paths, and line numbers where possible)&lt;/li&gt;

&lt;li&gt;Suggested fix (cache changes, query optimizations, config sync, etc.)&lt;/li&gt;

&lt;li&gt;Deep links back to the relevant New Relic views&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;This is the difference between “we should look into that spike” and “here is an actionable story ready for a sprint board”.&lt;/p&gt;




&lt;h3&gt;
  
  
  Phase 5: Teams Notifications and Optional PRs
&lt;/h3&gt;

&lt;p&gt;Once tickets are created, the workflow posts an Adaptive Card to the right Teams channel:&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%2Figokz1q4u9abh3gfygf5.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%2Figokz1q4u9abh3gfygf5.png" alt="MS Teams notification adaptive card" width="663" height="1273"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Every card includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Short description of the issue&lt;/li&gt;
&lt;li&gt;Key metrics (response time, error rate, environment)&lt;/li&gt;
&lt;li&gt;Link to the Jira ticket (and through that, to New Relic)&lt;/li&gt;
&lt;li&gt;Story points and priority&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For certain well‑scoped cases (like adding cache metadata or adjusting a specific query), there is also an &lt;strong&gt;optional&lt;/strong&gt; step:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Yes, attempt to fix this issue”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When I explicitly opt in, Claude Code will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the relevant files&lt;/li&gt;
&lt;li&gt;Propose a code change&lt;/li&gt;
&lt;li&gt;Run local commands/tests where available&lt;/li&gt;
&lt;li&gt;Open a draft PR linked to the Jira ticket&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nothing merges automatically. Manual review and CI are still required.&lt;/p&gt;




&lt;h2&gt;
  
  
  Guardrails and Risk Management
&lt;/h2&gt;

&lt;p&gt;The part that made this usable in a real production environment was not “more automation”; it was &lt;strong&gt;more guardrails&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Some of the key ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No confidential data in prompts or artifacts&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;No Jira IDs in public logs or documentation&lt;/li&gt;
&lt;li&gt;No customer identifiers or business metrics&lt;/li&gt;
&lt;li&gt;No secrets, URLs, or internal hostnames&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;New Relic as source of truth&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;The AI analyzes existing metrics; it does not invent data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Human‑in‑the‑loop by design&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Every ticket is reviewed before the team sees it&lt;/li&gt;
&lt;li&gt;PRs are suggestions, not actions&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Opinionated thresholds&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;Hard lines for Critical / High / Medium to avoid alert fatigue&lt;/li&gt;
&lt;li&gt;The system prefers fewer, higher‑quality tickets to a noisy firehose&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;These are boring details, but they are also the difference between “cool demo” and “thing we actually trust”.&lt;/p&gt;




&lt;h2&gt;
  
  
  ROI: What This Changed in Practice
&lt;/h2&gt;

&lt;p&gt;In terms of time:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Manual performance checks and ticket creation went from ~2–3 hours/week down to about 15 minutes of review.&lt;/li&gt;
&lt;li&gt;Incident response is faster because there is less friction between “we saw something weird in New Relic” and “there is a ticket with a clear owner and plan”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In terms of quality:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We miss fewer issues, especially slow degradations.&lt;/li&gt;
&lt;li&gt;Tickets come with better context and suggested fixes.&lt;/li&gt;
&lt;li&gt;Standups focus more on trade‑offs (“Do we take this now or next sprint?”) and less on “What exactly is going on?”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And in terms of team dynamics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developers can pick up performance work without having to live in New Relic.&lt;/li&gt;
&lt;li&gt;The platform feels more “observed” without feeling more “surveilled”.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Implementation Notes
&lt;/h2&gt;

&lt;p&gt;At a high level, this stack uses:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Application&lt;/strong&gt;: Drupal on Acquia&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt;: New Relic APM, NRQL queries, incidents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;AI&lt;/strong&gt;: Claude Code with the &lt;strong&gt;New Relic MCP&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ticketing&lt;/strong&gt;: Jira Cloud (REST API v3)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Communication&lt;/strong&gt;: Microsoft Teams (incoming webhooks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version Control&lt;/strong&gt;: GitHub (for optional PR automation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From a configuration perspective, the main work is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Wiring the New Relic account and NRQL queries into the MCP&lt;/li&gt;
&lt;li&gt;Wiring Jira, Teams, and GitHub credentials through environment variables&lt;/li&gt;
&lt;li&gt;Defining thresholds and ticket templates that reflect your actual workflow&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact code in my setup is specific to our environment and not open‑sourced (yet), but the pattern is portable to any stack where you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Structured telemetry&lt;/li&gt;
&lt;li&gt;A programmable AI agent&lt;/li&gt;
&lt;li&gt;A ticketing system&lt;/li&gt;
&lt;li&gt;A chat/notification channel&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Credits
&lt;/h2&gt;

&lt;p&gt;This workflow only exists because of the people around me.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Shannon Lal&lt;/strong&gt;, our CTO, pushed us to adopt Claude Code and gave me the runway to experiment with this in a real system.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Maria Parra Pino&lt;/strong&gt; and &lt;strong&gt;Ruslana Zagrai&lt;/strong&gt;, two of the developers on the team, were the ones stress‑testing the idea, calling out edge cases, and helping refine it into something that is actually usable day‑to‑day.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And of course, thanks to &lt;strong&gt;New Relic&lt;/strong&gt; for building a platform and MCP integration that made it possible to treat APM data as something to automate &lt;em&gt;against&lt;/em&gt;, not just stare at.&lt;/p&gt;




&lt;h2&gt;
  
  
  When This Pattern Makes Sense
&lt;/h2&gt;

&lt;p&gt;In my experience, this kind of automation works well when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The workflow is repeatable and well‑understood.&lt;/li&gt;
&lt;li&gt;The inputs are observable and reliable (like APM telemetry).&lt;/li&gt;
&lt;li&gt;The outputs can be expressed as structured work (tickets, PRs, notifications).&lt;/li&gt;
&lt;li&gt;You are willing to keep humans in the loop.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you’re running New Relic and Jira already, the leap from “manual checks” to “AI‑assisted performance engineering” is more about design and guardrails than about exotic technology.&lt;/p&gt;

&lt;p&gt;If you end up building a variant of this, I’d genuinely love to hear what worked, what broke, and what you did differently.&lt;/p&gt;

</description>
      <category>newrelic</category>
      <category>mcp</category>
      <category>drupal</category>
      <category>claudecode</category>
    </item>
  </channel>
</rss>
