<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Vinothsingh Elumalai</title>
    <description>The latest articles on DEV Community by Vinothsingh Elumalai (@velumal09).</description>
    <link>https://dev.to/velumal09</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3990085%2Fd45a344f-6547-41e7-a287-d0a81ae20d42.jpg</url>
      <title>DEV Community: Vinothsingh Elumalai</title>
      <link>https://dev.to/velumal09</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/velumal09"/>
    <language>en</language>
    <item>
      <title>🧟🤖 How I Led an AI-Native Cleanup of 120K+ dormant SaaS Tenants &amp; Zero Customer Impact</title>
      <dc:creator>Vinothsingh Elumalai</dc:creator>
      <pubDate>Mon, 14 Sep 2026 13:45:30 +0000</pubDate>
      <link>https://dev.to/velumal09/how-i-led-an-ai-native-cleanup-of-120k-dormant-saas-tenants-zero-customer-impact-57ng</link>
      <guid>https://dev.to/velumal09/how-i-led-an-ai-native-cleanup-of-120k-dormant-saas-tenants-zero-customer-impact-57ng</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Names, identifiers, infrastructure paths, dates, and selected implementation details have been generalized or rounded to protect confidential information. The architecture, failure modes, engineering decisions, and outcomes are real.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Cleanup Nobody Wanted to Own&lt;/li&gt;
&lt;li&gt;Why Deleting an Account Was Not a Delete&lt;/li&gt;
&lt;li&gt;The Plan: Start Small, Learn, Then Scale&lt;/li&gt;
&lt;li&gt;The First Warning: A Database Under Pressure&lt;/li&gt;
&lt;li&gt;The Hidden Side Effects&lt;/li&gt;
&lt;li&gt;The Silent Telemetry Failure&lt;/li&gt;
&lt;li&gt;The Account That Would Not Finish&lt;/li&gt;
&lt;li&gt;The Independent Review That Changed the Design&lt;/li&gt;
&lt;li&gt;How AI-Native Operations Changed the Execution Model&lt;/li&gt;
&lt;li&gt;The Outcome&lt;/li&gt;
&lt;li&gt;What I Would Build Differently&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Cleanup Nobody Wanted to Own &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The request sounded simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Retire a large population of inactive tenants that had accumulated over several years.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;They included abandoned trials, expired subscriptions, and dormant free accounts. They consumed storage, increased backup volume, complicated retention compliance, and left millions of related records distributed across the platform.&lt;/p&gt;

&lt;p&gt;The approved scope covered &lt;strong&gt;more than 120,000 tenants and approximately 1.4 million user records&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I understood the operational goal and the risks, but I was not the author of the legacy Rails application or an expert in every callback hidden inside its account-deletion path. I also could not pause normal production activity while studying the codebase for months.&lt;/p&gt;

&lt;p&gt;What I did have was:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Platform and infrastructure fundamentals&lt;/li&gt;
&lt;li&gt;Access to subject-matter experts for review and approvals&lt;/li&gt;
&lt;li&gt;An AI operations environment connected to source control, observability, cloud infrastructure, ticketing, and automation systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination changed what was possible.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
This was not a story about asking AI to blindly delete data. It was a story about using AI to accelerate discovery, implementation, monitoring, and documentation while humans retained control over scope, risk, approvals, and production decisions.&lt;br&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Why Deleting an Account Was Not a Delete &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;At first glance, account retirement looked like a database operation. In reality, one model-level delete initiated a distributed workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Retire tenant
  ├── Remove user-dependent records
  ├── Disable application provisioning
  ├── Run model destruction callbacks
  ├── Generate audit events
  ├── Publish asynchronous cleanup messages
  ├── Notify dependent services
  ├── Remove remaining orphan records
  └── Record progress and verification evidence
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;A path that is acceptable for one interactive deletion can become dangerous when repeated continuously at scale.&lt;/p&gt;

&lt;p&gt;The important engineering question was not:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;How quickly can I delete rows?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Which synchronous and asynchronous side effects will amplify when this operation runs thousands of times?&lt;/p&gt;
&lt;/blockquote&gt;


&lt;h2&gt;
  
  
  The Plan: Start Small, Learn, Then Scale &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I divided the approved work into risk-based phases rather than attempting one enormous execution.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pilot phase&lt;/strong&gt; — a few hundred low-risk accounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Expanded trial phase&lt;/strong&gt; — a few thousand accounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bulk low-risk phase&lt;/strong&gt; — tens of thousands of dormant trial accounts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Free-account phase&lt;/strong&gt; — another large population with additional validation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Higher-risk terminated and paid-account populations remained outside the approved scope pending further business review.&lt;/p&gt;

&lt;p&gt;The execution tooling included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSV-driven account selection&lt;/li&gt;
&lt;li&gt;Dry-run mode enabled by default&lt;/li&gt;
&lt;li&gt;Preflight checks&lt;/li&gt;
&lt;li&gt;Bulk cleanup of high-volume dependent rows&lt;/li&gt;
&lt;li&gt;Per-account checkpoints&lt;/li&gt;
&lt;li&gt;An append-only operational audit trail&lt;/li&gt;
&lt;li&gt;A circuit breaker for consecutive failures&lt;/li&gt;
&lt;li&gt;Progress metrics and events&lt;/li&gt;
&lt;li&gt;A resumable batch runner&lt;/li&gt;
&lt;li&gt;Independent post-run database verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pilot completed cleanly. That gave me confidence to proceed.&lt;/p&gt;

&lt;p&gt;Then the second large execution exposed what the pilot could not.&lt;/p&gt;


&lt;h2&gt;
  
  
  The First Warning: A Database Under Pressure &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;During an early production batch, an internal database alert fired. CPU on the events datastore had climbed to a critical level and remained elevated.&lt;/p&gt;

&lt;p&gt;There was no customer-facing outage, but the signal was serious enough to stop and investigate.&lt;/p&gt;

&lt;p&gt;The database team identified a family of expensive range-scan queries. I compared the account identifiers in those queries with the active cleanup batch.&lt;/p&gt;

&lt;p&gt;Every sampled identifier matched.&lt;/p&gt;

&lt;p&gt;The deletion process was not directly querying the events database, so the immediate question was:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What did the account-deletion path trigger indirectly?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That question took me into the legacy callback chain.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Hidden Side Effects &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I found two separate paths affecting the events datastore.&lt;/p&gt;
&lt;h3&gt;
  
  
  Path 1: Audit-event generation
&lt;/h3&gt;

&lt;p&gt;Deleting an account cascaded into users, roles, directories, and other objects. Multiple callbacks generated audit records during that cascade.&lt;/p&gt;

&lt;p&gt;One deletion might produce a manageable amount of work. Thousands of continuous deletions created a sustained write workload and fed additional downstream processing.&lt;/p&gt;
&lt;h3&gt;
  
  
  Path 2: Asynchronous historical-event cleanup
&lt;/h3&gt;

&lt;p&gt;A model callback also published an asynchronous message requesting historical-event deletion for each retired account. A downstream worker consumed those messages and performed large range scans.&lt;/p&gt;

&lt;p&gt;The main cleanup process appeared healthy while the message queue continuously generated expensive work elsewhere.&lt;/p&gt;

&lt;p&gt;That distinction mattered:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Visible process: account retirement is progressing normally
Hidden process: asynchronous workers are saturating another database
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  The controlled mitigation
&lt;/h3&gt;

&lt;p&gt;For the approved low-risk phases, I suppressed these two side effects &lt;strong&gt;inside the one-shot cleanup process only&lt;/strong&gt;, after review with the relevant stakeholders.&lt;/p&gt;

&lt;p&gt;Conceptually:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simplified example — not production source&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AuditWriter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;record&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# Suppressed only inside this one-shot maintenance process&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Tenant&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;enqueue_historical_event_cleanup&lt;/span&gt;
    &lt;span class="c1"&gt;# Deferred to a separately controlled database cleanup&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The patches did not modify the deployed application, its containers, or other workers. They existed only inside the Ruby process executing the maintenance task and disappeared when that process exited.&lt;/p&gt;

&lt;p&gt;I preserved a separate operational audit trail and created a tracked follow-up for controlled removal of orphaned historical events during maintenance windows.&lt;/p&gt;

&lt;p&gt;The result: events-database utilization returned to a stable baseline while the tenant cleanup continued.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
The decision was not "skip cleanup forever." It was "separate two high-risk operations so each can be rate-limited, observed, and verified independently."&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Silent Telemetry Failure &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The next failure was quieter.&lt;/p&gt;

&lt;p&gt;The cleanup logs showed accounts being retired successfully, but the progress dashboard showed no data. The task also claimed that metric publishing had completed.&lt;/p&gt;

&lt;p&gt;The problem was an API-version mismatch. The code sent a payload shaped for one metrics API to another version. The monitoring service returned an HTTP client error, but the implementation only treated exceptions as failures. Since the HTTP library returned a response object instead of raising, the task reported success.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Work completed:             yes
Metric request transmitted: yes
Metric accepted:            no
Exception raised:           no
Agent narrative:            progress appears normal
Independent dashboard:      no data
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The dashboard's disagreement with the task logs exposed the issue.&lt;/p&gt;

&lt;p&gt;I corrected the payload and, more importantly, changed the design rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A successful network call is not a successful outcome. Parse the response, validate the result, and read back the effect from an independent system.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This became one of the most important lessons from the entire operation.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Account That Would Not Finish &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A later batch encountered an extreme outlier.&lt;/p&gt;

&lt;p&gt;The planning spreadsheet showed only one enabled user, but the live database contained an unexpectedly large population of historical user records plus a large association graph.&lt;/p&gt;

&lt;p&gt;The high-volume user rows were removed, but the remaining model cascade did not finish. The process continued consuming CPU without crashing, exiting, or producing new logs.&lt;/p&gt;

&lt;p&gt;From the outside, the runner looked dead.&lt;/p&gt;

&lt;p&gt;Someone started a replacement runner. The original process was still alive.&lt;/p&gt;

&lt;p&gt;For an extended period, one runner was stuck while another continued healthy work.&lt;/p&gt;

&lt;p&gt;The miss was surprisingly mundane: the process search looked for the rake-task name, while the operating system displayed the Ruby executable. The stopped log was interpreted as evidence that the process had died.&lt;/p&gt;

&lt;p&gt;The prevention controls were straightforward:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Simplified guardrail&lt;/span&gt;
&lt;span class="no"&gt;Timeout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_account_seconds&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt;
  &lt;span class="n"&gt;retire_account&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;account&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Simplified single-instance guard&lt;/span&gt;
&lt;span class="k"&gt;if &lt;/span&gt;another_runner_exists&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Another runner is active; refusing to start."&lt;/span&gt;
  &lt;span class="nb"&gt;exit &lt;/span&gt;1
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also added:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A PID lockfile&lt;/li&gt;
&lt;li&gt;Process-tree checks&lt;/li&gt;
&lt;li&gt;Live database row-count validation for outliers&lt;/li&gt;
&lt;li&gt;A hard threshold requiring separate review for exceptionally large accounts&lt;/li&gt;
&lt;li&gt;A heartbeat/progress-age monitor so silence becomes an alert&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
A dead process and a hung process can look identical in a log: neither writes new lines. Liveness must be measured independently from log activity.&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Independent Review That Changed the Design &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I shared the implementation with a senior architecture reviewer, who used a separate AI-assisted review process to challenge the design.&lt;/p&gt;

&lt;p&gt;The review identified issues that had been easy to miss under operational pressure:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A credential supplied in an unsafe way&lt;/li&gt;
&lt;li&gt;A database timeout setting with a broader scope than intended&lt;/li&gt;
&lt;li&gt;Missing transactional boundaries around per-account work&lt;/li&gt;
&lt;li&gt;Compliance implications of suppressing normal audit events&lt;/li&gt;
&lt;li&gt;The need to assign ownership and deadlines to deferred cleanup&lt;/li&gt;
&lt;li&gt;Risks in a partial method stub&lt;/li&gt;
&lt;li&gt;The absence of proof that process-local patches had actually loaded&lt;/li&gt;
&lt;li&gt;Poor visibility of behavior-changing patches in startup logs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I addressed the findings by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Rotating and relocating credentials to managed configuration&lt;/li&gt;
&lt;li&gt;Limiting database settings to explicit transactions&lt;/li&gt;
&lt;li&gt;Adding per-account transactional protection where safe&lt;/li&gt;
&lt;li&gt;Documenting the approved alternate audit trail&lt;/li&gt;
&lt;li&gt;Creating a separately owned database cleanup task&lt;/li&gt;
&lt;li&gt;Making the stub defensive against interface changes&lt;/li&gt;
&lt;li&gt;Verifying patched method source locations at startup&lt;/li&gt;
&lt;li&gt;Printing a prominent banner showing every process-local override&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The value of the second AI review was not that it was automatically correct. It generated a rigorous second set of questions for me and the relevant specialists to evaluate.&lt;/p&gt;




&lt;h2&gt;
  
  
  How AI-Native Operations Changed the Execution Model &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;I understood infrastructure, operational risk, and what a safe outcome needed to look like. I was not a specialist in the legacy application's Ruby internals or every API involved in the workflow.&lt;/p&gt;

&lt;p&gt;AI bridged that specific knowledge gap.&lt;/p&gt;

&lt;h3&gt;
  
  
  Building the first version
&lt;/h3&gt;

&lt;p&gt;I described the operational contract:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read account identifiers from a controlled input, default to dry run, checkpoint after each item, stop after repeated failures, emit progress, and preserve an audit trail.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent produced a first implementation. I reviewed the workflow and validated it with application owners before execution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Investigating the database signal
&lt;/h3&gt;

&lt;p&gt;I asked the agent to compare database evidence with the active cleanup population, trace the relevant callback paths, and explain how a foreground delete could trigger work in another datastore.&lt;/p&gt;

&lt;p&gt;It helped connect application code, queue behavior, and database telemetry into one causal chain.&lt;/p&gt;

&lt;h3&gt;
  
  
  Debugging missing telemetry
&lt;/h3&gt;

&lt;p&gt;I described the disagreement between successful cleanup logs and an empty dashboard. The agent inspected the metrics-publishing code, compared it with the API contract, and identified the payload mismatch.&lt;/p&gt;

&lt;h3&gt;
  
  
  Diagnosing the hung execution
&lt;/h3&gt;

&lt;p&gt;I asked it to inspect process state rather than rely on the stopped log. It helped identify the still-running child process and generated the restart and single-instance protections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operating the long-running job
&lt;/h3&gt;

&lt;p&gt;Throughout the execution, the same session could answer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How many accounts are complete?&lt;/li&gt;
&lt;li&gt;Has progress stalled?&lt;/li&gt;
&lt;li&gt;Is database utilization stable?&lt;/li&gt;
&lt;li&gt;Did a batch produce errors?&lt;/li&gt;
&lt;li&gt;What is the estimated completion window?&lt;/li&gt;
&lt;li&gt;Which follow-up tasks require another team?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It queried the automation system, observability platform, ticketing system, and cloud environment without requiring me to switch among multiple consoles.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
AI did not replace platform fundamentals or production judgment. The fundamentals let me define safe constraints, question suspicious results, and recognize when two systems disagreed. AI accelerated the implementation details and cross-system analysis in a codebase and toolchain I did not know deeply.&lt;br&gt;

&lt;/div&gt;


&lt;p&gt;This is the broader AI-native operations pattern:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A human defines the goal, constraints, and acceptable risk.&lt;/li&gt;
&lt;li&gt;The agent gathers live evidence and proposes implementation steps.&lt;/li&gt;
&lt;li&gt;Deterministic controls constrain execution.&lt;/li&gt;
&lt;li&gt;Independent systems verify the result.&lt;/li&gt;
&lt;li&gt;Humans review exceptions and authorize higher-risk phases.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That pattern is transferable to migrations, cost optimization, compliance audits, incident response, and many other operational workflows.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Outcome &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Across the four approved phases:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Outcome&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Dormant tenants retired&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;More than 120,000&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Associated user records removed&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Approximately 1.4 million&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execution duration&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Under two weeks&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer impact&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None observed&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer-facing incidents&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;None&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Independent verification&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Completed against the production database&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Higher-risk phases&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Held for additional business approval&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The project also left behind reusable operational capabilities:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A resumable maintenance-runner pattern&lt;/li&gt;
&lt;li&gt;Independent verification practices&lt;/li&gt;
&lt;li&gt;Process-local safety checks&lt;/li&gt;
&lt;li&gt;Better telemetry validation&lt;/li&gt;
&lt;li&gt;A clear owner and process for deferred historical-data cleanup&lt;/li&gt;
&lt;li&gt;A stronger review model combining AI analysis with human architecture oversight&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  What I Would Build Differently &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Make independent verification part of version one
&lt;/h3&gt;

&lt;p&gt;The layer doing the work should not be the only layer declaring success. Every important action needs a deterministic read-back from the system it changed.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Treat callbacks as distributed architecture
&lt;/h3&gt;

&lt;p&gt;A model callback can publish messages, call external services, and create work in another database. At scale, callback analysis is capacity planning.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Validate live cardinality, not spreadsheet summaries
&lt;/h3&gt;

&lt;p&gt;An account with one enabled user may still contain tens of thousands of historical rows. Selection data is a planning snapshot; the production database is ground truth.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Detect absence of progress
&lt;/h3&gt;

&lt;p&gt;Errors are not the only failure signal. A process can remain alive while accomplishing nothing. Track heartbeat age, last completed item, and work rate.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Keep high-risk operations separable
&lt;/h3&gt;

&lt;p&gt;Retiring tenants and purging years of historical events did not need to happen in the same transaction or maintenance window. Separation made both safer.&lt;/p&gt;

&lt;h3&gt;
  
  
  6. Use AI to extend expertise, not bypass it
&lt;/h3&gt;

&lt;p&gt;AI made it possible to move quickly through unfamiliar application internals. The project remained safe because experienced engineers defined the constraints, challenged outputs, and verified results independently.&lt;/p&gt;




&lt;p&gt;The surprising part was not that AI could generate Ruby or shell commands.&lt;/p&gt;

&lt;p&gt;The surprising part was that one AI-integrated operations session could maintain context across application code, database telemetry, automation logs, cloud infrastructure, and project tracking for the duration of a complex production program.&lt;/p&gt;

&lt;p&gt;That cross-signal continuity was the real force multiplier.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Vinothsingh Elumalai, a Platform Engineering leader building AI-native operations at enterprise scale. I write about using AI to extend engineering expertise across unfamiliar systems while keeping deterministic controls and humans in the loop.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is part of my &lt;a href="https://dev.to/velumal09/series/ai-native-sre"&gt;AI-Native SRE&lt;/a&gt; series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/velumal09" class="crayons-btn crayons-btn--primary"&gt;Follow for more AI-native operations stories&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>platform</category>
      <category>cloudops</category>
      <category>ruby</category>
      <category>ai</category>
    </item>
    <item>
      <title>💀 The Most Dangerous Deletions Don't Break the Build. They Break the Deploy. An AI-Assisted Recovery Story 🤖</title>
      <dc:creator>Vinothsingh Elumalai</dc:creator>
      <pubDate>Sat, 08 Aug 2026 20:30:26 +0000</pubDate>
      <link>https://dev.to/velumal09/the-most-dangerous-deletions-dont-break-the-build-they-break-the-deploy-an-ai-assisted-3bk7</link>
      <guid>https://dev.to/velumal09/the-most-dangerous-deletions-dont-break-the-build-they-break-the-deploy-an-ai-assisted-3bk7</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The PR That Looked Harmless&lt;/li&gt;
&lt;li&gt;Five Minutes to 503&lt;/li&gt;
&lt;li&gt;The Revert That Couldn't Land&lt;/li&gt;
&lt;li&gt;Down the SSH Rabbit Hole&lt;/li&gt;
&lt;li&gt;The Workaround&lt;/li&gt;
&lt;li&gt;The Proper Fix&lt;/li&gt;
&lt;li&gt;What We Learned&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The PR That Looked Harmless &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It started with a well-intentioned pull request.&lt;/p&gt;

&lt;p&gt;We were migrating our public developer documentation site from a legacy PHP CMS to a modern static site generator. The migration PR deleted the old PHP application from the main branch and replaced it with the new stack.&lt;/p&gt;

&lt;p&gt;Clean, right? CI passed. Reviews approved. Merge.&lt;/p&gt;




&lt;h2&gt;
  
  
  Five Minutes to 503 &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;What nobody had documented: &lt;strong&gt;the production servers deploy directly from &lt;code&gt;main&lt;/code&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They run a cron job every two minutes that does a &lt;code&gt;git pull&lt;/code&gt;. The moment that PR merged, both servers pulled down the change, the PHP app disappeared, and the load balancer's health check endpoint vanished with it.&lt;/p&gt;

&lt;p&gt;Within minutes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both backends failed health checks&lt;/li&gt;
&lt;li&gt;The load balancer had nowhere to send traffic&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;503 for everyone&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
The migration itself was fine. The code was correct. The new static site worked beautifully in staging. What broke wasn't the application — it was the &lt;strong&gt;deployment plumbing&lt;/strong&gt; that nobody thought to preserve.&lt;br&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  The Revert That Couldn't Land &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The team caught it fast. A revert PR was raised and merged within &lt;strong&gt;thirteen minutes&lt;/strong&gt; — the PHP app was back on &lt;code&gt;main&lt;/code&gt; in GitHub.&lt;/p&gt;

&lt;p&gt;Problem solved, right?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Wrong.&lt;/strong&gt; The servers couldn't pull.&lt;/p&gt;

&lt;p&gt;The deploy key — the SSH key that gave the servers read access to the repo — had been &lt;strong&gt;removed during the migration work&lt;/strong&gt;. It was treated as cleanup. Something belonging to the old system.&lt;/p&gt;

&lt;p&gt;But it was infrastructure. Without it, &lt;code&gt;git pull&lt;/code&gt; returned:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Repository not found.
fatal: Could not read from remote repository.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The revert existed on GitHub. The servers couldn't reach it. The site stayed down.&lt;/p&gt;


&lt;h2&gt;
  
  
  Down the SSH Rabbit Hole &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;No problem, we thought. Generate a new key, add it to the repo, pull. Simple.&lt;/p&gt;

&lt;p&gt;Except it wasn't.&lt;/p&gt;
&lt;h3&gt;
  
  
  Problem 1: Wrong Identity
&lt;/h3&gt;

&lt;p&gt;The server had multiple SSH keys in &lt;code&gt;~/.ssh/&lt;/code&gt;. SSH kept offering the &lt;strong&gt;wrong one first&lt;/strong&gt;. One key authenticated as a puppet automation user that had no access to this repo.&lt;/p&gt;

&lt;p&gt;We tried:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;IdentitiesOnly yes&lt;/code&gt; in the command&lt;/li&gt;
&lt;li&gt;Unsetting &lt;code&gt;SSH_AUTH_SOCK&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Explicit &lt;code&gt;-i&lt;/code&gt; flags&lt;/li&gt;
&lt;li&gt;Testing with &lt;code&gt;ssh -T git@github.com&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Every time, GitHub saw the wrong identity.&lt;/p&gt;
&lt;h3&gt;
  
  
  Why This Happens
&lt;/h3&gt;

&lt;p&gt;SSH offers keys in order. GitHub accepts the &lt;strong&gt;first valid key at the authentication layer&lt;/strong&gt;, then checks repo access separately. If the wrong key authenticates first, you get "Repository not found" — which &lt;strong&gt;looks like a permissions error but is actually an identity error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The old deploy key had worked because it was configured under a custom SSH host alias in the config:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;Host&lt;/span&gt; docs-github
  &lt;span class="k"&gt;HostName&lt;/span&gt; github.com
  &lt;span class="k"&gt;IdentityFile&lt;/span&gt; ~/.ssh/old_deploy_key
  &lt;span class="k"&gt;IdentitiesOnly&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;That alias was gone too — the SSH config just had &lt;code&gt;Host *&lt;/code&gt; with &lt;code&gt;StrictHostKeyChecking no&lt;/code&gt;. Another piece of "cleanup" that was actually load-bearing infrastructure.&lt;/p&gt;
&lt;h3&gt;
  
  
  Problem 2: "Key Already In Use"
&lt;/h3&gt;

&lt;p&gt;We generated a fresh ed25519 key and tried to add it as a deploy key on GitHub.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"Key is already in use"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Deploy keys must be &lt;strong&gt;globally unique across all of GitHub&lt;/strong&gt;. The key we generated on one server was somehow already registered elsewhere — likely on another repo from a previous automation setup.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Rounds of SSH debugging.&lt;/strong&gt; Still no &lt;code&gt;git pull&lt;/code&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Workaround &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We stopped fighting SSH and took a different path:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Download repo as tarball via GitHub API&lt;/span&gt;
curl &lt;span class="nt"&gt;-L&lt;/span&gt; &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.github.com/repos/org/docs/tarball/main"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/site.tar.gz

&lt;span class="c"&gt;# 2. Upload to S3&lt;/span&gt;
aws s3 &lt;span class="nb"&gt;cp&lt;/span&gt; /tmp/site.tar.gz s3://tmp-bucket/restore.tar.gz

&lt;span class="c"&gt;# 3. Generate presigned URL (short expiry)&lt;/span&gt;
&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;aws s3 presign s3://tmp-bucket/restore.tar.gz &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--expires-in&lt;/span&gt; 300&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# 4. Pull onto server and extract to web root&lt;/span&gt;
curl &lt;span class="nt"&gt;-o&lt;/span&gt; /tmp/site.tar.gz &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$URL&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;tar &lt;/span&gt;xzf /tmp/site.tar.gz &lt;span class="nt"&gt;-C&lt;/span&gt; /var/www/site/ &lt;span class="nt"&gt;--strip-components&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Health check started passing. Did the same on the second server. &lt;strong&gt;Site was back.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;But this was a band-aid. The cron job would still fail every two minutes silently in the background.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Proper Fix &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;We generated brand new keys on each server — unique keys, never used anywhere else. Added them to the repo's deploy keys &lt;strong&gt;via the GitHub API&lt;/strong&gt; (faster and more reliable than navigating the UI while firefighting):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: token &lt;/span&gt;&lt;span class="nv"&gt;$TOKEN&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="s2"&gt;"https://api.github.com/repos/org/docs/keys"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"title":"server-1-deploy","key":"ssh-ed25519 AAAA...","read_only":true}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Created a dedicated SSH host alias in the config:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ssh"&gt;&lt;code&gt;&lt;span class="k"&gt;Host&lt;/span&gt; github-docs
  &lt;span class="k"&gt;HostName&lt;/span&gt; github.com
  &lt;span class="k"&gt;IdentityFile&lt;/span&gt; ~/.ssh/docs_deploy_key
  &lt;span class="k"&gt;IdentitiesOnly&lt;/span&gt; &lt;span class="no"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;&lt;code&gt;IdentitiesOnly yes&lt;/code&gt; is the critical piece.&lt;/strong&gt; It tells SSH: "use ONLY this key, don't try anything else in my keyring." Without it, SSH offers keys in order and GitHub accepts the first one that authenticates — even if that identity has no access to the repo you're trying to reach.&lt;br&gt;

&lt;/div&gt;



&lt;p&gt;Updated the git remote to use the new alias:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git remote set-url origin git@github-docs:org/docs.git
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Ran &lt;code&gt;git pull&lt;/code&gt;. "Already up to date." The cron job would now work every two minutes like it always had.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the AI Agent Accelerated the Recovery &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here's what I haven't mentioned yet: most of this recovery was &lt;strong&gt;driven through an AI agent session&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;When the site went down, I didn't start by SSH-ing into servers and running commands from memory. I opened a terminal session connected to our operational stack (AWS, GitHub, PagerDuty) and started asking:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"The docs site is down. Both backends are failing health checks. Check the load balancer target health and tell me what's happening."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Within seconds: both targets unhealthy, health check path returning 404. The PHP app was gone.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Check the GitHub repo — what was the last merge to main? Show me the diff."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The migration PR. Deleted the entire PHP directory. Now I knew the cause without logging into GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Generate a revert PR for that merge."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Done. But then the servers couldn't pull. So:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"SSH to the docs server and check why git pull is failing. Test the SSH connection to GitHub and tell me which identity it's using."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The agent diagnosed the identity mismatch — the puppet key authenticating first, the deploy key missing. It suggested the host alias fix with &lt;code&gt;IdentitiesOnly yes&lt;/code&gt; before I even thought of it.&lt;/p&gt;

&lt;p&gt;When we hit the "key already in use" dead end, the agent proposed the tarball workaround:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Download the repo as a tarball via GitHub API, upload to S3, generate a presigned URL, and pull it onto the server with curl."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Four commands. Site back. Then it generated the new deploy keys and added them via the GitHub API — no UI fumbling, no "key already in use" errors because it checked existing keys first.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Without the agent:&lt;/strong&gt; Extended downtime — SSH debugging alone would burn 20+ minutes of human context-switching between terminals, GitHub UI, and Stack Overflow.

&lt;p&gt;&lt;strong&gt;With the agent:&lt;/strong&gt; Most of the debugging was conversational. Ask → answer → next step. No tab switching. No copy-pasting SSH keys between windows. No Googling "GitHub deploy key already in use."&lt;/p&gt;

&lt;p&gt;The agent dramatically compressed the recovery time by eliminating the &lt;strong&gt;cognitive overhead&lt;/strong&gt; of troubleshooting under pressure. Every command was generated, every API call was formatted, every decision was informed by live data rather than memory. What would have been an hour-plus outage with manual debugging became a focused, conversational recovery.&lt;br&gt;

&lt;/p&gt;
&lt;/div&gt;



&lt;h2&gt;
  
  
  What We Learned &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Your deploy mechanism is infrastructure, not cleanup
&lt;/h3&gt;

&lt;p&gt;The deploy key. The SSH config. The cron job. The git remote URL. These are all &lt;strong&gt;load-bearing&lt;/strong&gt;. They look like leftover configuration but they're what keeps the site alive between merges.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Rule:&lt;/strong&gt; If deleting something would prevent your site from receiving future updates, it's infrastructure — regardless of how old or "legacy" it looks.&lt;br&gt;

&lt;/div&gt;


&lt;h3&gt;
  
  
  2. &lt;code&gt;main&lt;/code&gt; is production until it isn't
&lt;/h3&gt;

&lt;p&gt;If your servers deploy from &lt;code&gt;main&lt;/code&gt;, you &lt;strong&gt;cannot delete the application from main&lt;/strong&gt; until DNS points somewhere else. The migration and the cutover are two separate steps that must happen in order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Deploy new site to new infrastructure&lt;/li&gt;
&lt;li&gt;Verify new site works&lt;/li&gt;
&lt;li&gt;Switch DNS / load balancer to new infrastructure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Then&lt;/strong&gt; — and only then — clean up the old app from main&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We did step 1, skipped to step 4, and wondered why production broke.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. SSH key management on servers is deceptively complex
&lt;/h3&gt;

&lt;p&gt;A server with multiple keys in &lt;code&gt;~/.ssh/&lt;/code&gt; will offer them in an unpredictable order. GitHub accepts the first valid key at the authentication layer, then checks repo access &lt;strong&gt;separately&lt;/strong&gt;. If the wrong key authenticates first, you get "Repository not found" — which looks like a permissions error but is actually an &lt;strong&gt;identity error&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The fix is always: dedicated host alias + &lt;code&gt;IdentitiesOnly yes&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Have a non-git restore path documented
&lt;/h3&gt;

&lt;p&gt;When your deploy mechanism breaks, you need a way to get files onto the server that &lt;strong&gt;doesn't depend on the thing that's broken&lt;/strong&gt;. For us it was:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GitHub API tarball → S3 → presigned URL → curl on server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's ugly. It works in three minutes. Document it before you need it.&lt;/p&gt;

&lt;h3&gt;
  
  
  5. API calls beat UI clicking during incidents
&lt;/h3&gt;

&lt;p&gt;We wasted time trying to add deploy keys through the GitHub web UI (hitting "key already in use" with no helpful error context). Switching to the API was &lt;strong&gt;one curl command and done&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;During an outage, every minute of fumbling in a UI is a minute your users see a 503.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Irony
&lt;/h2&gt;

&lt;p&gt;The migration itself was fine. The code was correct. The new static site worked beautifully in staging.&lt;/p&gt;

&lt;p&gt;It was the deployment plumbing — the invisible infrastructure that makes &lt;code&gt;git push&lt;/code&gt; turn into a live website — that nobody thought to preserve.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The most dangerous deletions aren't the ones that break the build. They're the ones that break the deploy.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Vinothsingh Elumalai, a Platform Engineering leader managing infrastructure for a global SaaS platform. I write about the unglamorous operational work that keeps systems alive — especially the parts where things go wrong in ways nobody anticipated.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is part of my &lt;a href="https://dev.to/velumal09/series/ai-native-sre"&gt;AI-Native SRE&lt;/a&gt; series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/velumal09" class="crayons-btn crayons-btn--primary"&gt;Follow for more war stories&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>devops</category>
      <category>git</category>
      <category>sre</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How an AI Terminal Assistant Became My Team's Most Productive Engineer - Opencode + Claude + MCP</title>
      <dc:creator>Vinothsingh Elumalai</dc:creator>
      <pubDate>Wed, 24 Jun 2026 18:31:54 +0000</pubDate>
      <link>https://dev.to/velumal09/how-an-ai-terminal-assistant-became-my-teams-most-productive-engineer-opencode-claude-mcp-362i</link>
      <guid>https://dev.to/velumal09/how-an-ai-terminal-assistant-became-my-teams-most-productive-engineer-opencode-claude-mcp-362i</guid>
      <description>&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Moment That Changed Everything&lt;/li&gt;
&lt;li&gt;What It Actually Is&lt;/li&gt;
&lt;li&gt;The Setup Nobody Believes Is This Simple&lt;/li&gt;
&lt;li&gt;Focused Sessions — One Agent, One Mission&lt;/li&gt;
&lt;li&gt;Sub-Agents With Specific Skill Sets&lt;/li&gt;
&lt;li&gt;Building MCPs for Your Own Stack&lt;/li&gt;
&lt;li&gt;What We've Actually Achieved&lt;/li&gt;
&lt;li&gt;How It Became a Force Multiplier for Incident Response&lt;/li&gt;
&lt;li&gt;From OpenCode to FRIDAY — The Agent That Investigates Incidents Autonomously&lt;/li&gt;
&lt;li&gt;From FRIDAY to JARVIS — Thinking About Write-Path Autonomy&lt;/li&gt;
&lt;li&gt;Deleting 130,000 Accounts Without Writing Code&lt;/li&gt;
&lt;li&gt;Learning the Entire Product in Conversations&lt;/li&gt;
&lt;li&gt;Why This Is Different From ChatGPT&lt;/li&gt;
&lt;li&gt;The Uncomfortable Truth&lt;/li&gt;
&lt;li&gt;What's Next&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Moment That Changed Everything &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It was 11pm on a Tuesday. A cache migration in our production environment had just caused thousands of authentication failures for two of our largest enterprise customers. Our VP of Product wanted answers. Our support team was fielding escalations. And our engineers were alt-tabbing between AWS console, Datadog, GitHub, Azure DevOps, and PagerDuty trying to piece together what happened.&lt;/p&gt;

&lt;p&gt;Three weeks later, when we needed to attempt the same change again, an engineer typed this into a terminal:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"Review the ADO change ticket, compare the MOP against the actual ElastiCache configuration in prod region, check the K8s config repo for how Redis env vars are wired on the Green cluster, and tell me if this approach avoids the token validation failure that caused the previous customer impact."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Fourteen seconds later&lt;/strong&gt;, the system had pulled the work item, queried AWS ElastiCache across four regions, read the Kubernetes configuration from GitHub, cross-referenced the deployment patches, and delivered a precise technical assessment  including a risk it identified that the team hadn't documented: in-flight tokens during the 30–60 second Global Accelerator propagation window.&lt;/p&gt;

&lt;p&gt;That system is &lt;strong&gt;OpenCode&lt;/strong&gt; — an AI-powered CLI assistant connected to our entire operational stack through the MC(Model Context Protocol). And it has fundamentally changed how a 20-person platform engineering team manages infrastructure serving thousands of enterprise tenants and processing millions of authentication requests daily.&lt;/p&gt;




&lt;h2&gt;
  
  
  What It Actually Is &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;OpenCode is deceptively simple in concept. A terminal application on an engineer's laptop. You type questions or tasks in plain English. It responds with answers pulled from &lt;strong&gt;live production systems&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  Engineer (terminal)
        │
        ▼
    OpenCode (Claude AI)
        │
        ▼
    MCP Servers
   ╱  │  │  │  ╲
  ▼   ▼  ▼  ▼   ▼
 AWS  DD  GH ADO PD  RD

 AWS = Amazon Web Services (prod + non-prod)
 DD  = Datadog (logs, metrics, monitors)
 GH  = GitHub (repos, PRs, code)
 ADO = Azure DevOps (tickets, sprints, wikis)
 PD  = PagerDuty (incidents, schedules)
 RD  = Rundeck (jobs, executions)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The magic is in those MCP servers. Each one is a lightweight connector to a backend platform. When you ask a question, the AI doesn't guess — it makes &lt;strong&gt;real API calls&lt;/strong&gt; against &lt;strong&gt;real systems&lt;/strong&gt; and works with &lt;strong&gt;real data&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Ask &lt;em&gt;"what's our AWS spend this month?"&lt;/em&gt; — it queries Cost Explorer. Ask &lt;em&gt;"which tenant generates the most provisioning traffic?"&lt;/em&gt; — it aggregates Datadog logs. Ask &lt;em&gt;"what did that PR change in the K8s config repo?"&lt;/em&gt; — it reads the actual file diff from GitHub. Ask all three in the same sentence and it does them in parallel.&lt;/p&gt;

&lt;p&gt;No pre-built dashboards. No saved queries. No runbooks to follow. You just &lt;strong&gt;ask&lt;/strong&gt;.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Setup Nobody Believes Is This Simple &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The entire configuration is a single JSON file. Each MCP server gets a block: here's the server binary, here's the credentials, connect.&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;"mcpServers"&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;"aws-prod"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"aws-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"AWS_PROFILE"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"prod"&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;span class="nl"&gt;"datadog"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"datadog-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"DD_API_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;"DD_APP_KEY"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;span class="nl"&gt;"github"&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;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"github-mcp-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"env"&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;"GITHUB_TOKEN"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&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;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;The AI model never sees the credentials. It calls tools by name — &lt;em&gt;"search logs in Datadog"&lt;/em&gt; or &lt;em&gt;"describe EKS clusters"&lt;/em&gt;  and the MCP server handles authentication, pagination, error handling, and response formatting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Adding a new system takes about ten minutes.&lt;/strong&gt; Write a config block, provide credentials, restart.&lt;/p&gt;


&lt;h2&gt;
  
  
  Focused Sessions — One Agent, One Mission &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here's something that changes how you think about AI assistants: &lt;strong&gt;you can create focused sessions with a single purpose&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Right now, as I write this article, I have an OpenCode session that's been running for days as a &lt;strong&gt;documentation advisor&lt;/strong&gt;. It's reviewed my architecture docs, drafted technical articles, generated formal roadmap documents, and is tracking project milestones. When I start a new conversation about something unrelated, I can tell the session: &lt;em&gt;"This session is reserved for documentation work only"&lt;/em&gt; — and it keeps me focused.&lt;/p&gt;

&lt;p&gt;This pattern works for any focused workstream:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Session&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;th&gt;Tools Used&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Documentation Advisor&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Article drafting, roadmap generation, technical writing&lt;/td&gt;
&lt;td&gt;Doc Agent, GitHub, web search&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Incident Responder&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Active incident investigation and RCA&lt;/td&gt;
&lt;td&gt;Datadog, GitHub, PagerDuty, AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cost Analyst&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Monthly spend review, waste identification&lt;/td&gt;
&lt;td&gt;AWS (Cost Explorer, EC2, RDS, S3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Sprint Planner&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Ticket creation, backlog grooming, capacity planning&lt;/td&gt;
&lt;td&gt;Azure DevOps, GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security Reviewer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Code review, vulnerability assessment&lt;/td&gt;
&lt;td&gt;GitHub, AWS (IAM, SecurityHub)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each session maintains context across the entire conversation. The AI remembers what you discussed 3 hours ago. It builds on previous findings. It doesn't start from zero every time.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;This is the real power:&lt;/strong&gt; Not one assistant that does everything poorly. Multiple focused sessions, each purpose-built for a specific mission, with the right tools connected and the right context loaded.&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Sub-Agents With Specific Skill Sets &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Beyond focused sessions, you can create &lt;strong&gt;sub-agents&lt;/strong&gt; — specialized configurations trained for specific domains:&lt;/p&gt;

&lt;h3&gt;
  
  
  The Doc Agent
&lt;/h3&gt;

&lt;p&gt;Generates formal documents — postmortems, RCA reports, roadmaps, technical specs. It knows document templates, formatting standards, and outputs polished Word/PDF files.&lt;/p&gt;

&lt;p&gt;I used this to generate formal migration roadmaps, architecture documents, and execution playbooks — all properly formatted, ready to share with leadership.&lt;/p&gt;

&lt;h3&gt;
  
  
  The ADO Agent
&lt;/h3&gt;

&lt;p&gt;Creates, updates, and queries Azure DevOps work items. It understands your project structure, sprint cadence, and ticket hierarchy (Epic → Feature → Task).&lt;/p&gt;

&lt;p&gt;One prompt: &lt;em&gt;"Create a Feature under the cleanup Epic with 8 tasks — one per batch"&lt;/em&gt; — and 9 tickets exist with proper hierarchy, descriptions, and assignments.&lt;/p&gt;

&lt;h3&gt;
  
  
  The AWS Agent
&lt;/h3&gt;

&lt;p&gt;Queries across all regions, all services. Cost analysis, resource inventory, security posture review. Runs in read-only mode with separate IAM profiles for prod vs. non-prod.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Incident Agent
&lt;/h3&gt;

&lt;p&gt;Connected to PagerDuty + Datadog + GitHub. When an alert fires, it pulls the monitor definition, searches logs, checks recent deployments, and synthesizes findings. This is the agent that eventually became &lt;strong&gt;FRIDAY&lt;/strong&gt; — but more on that later.&lt;/p&gt;

&lt;h3&gt;
  
  
  The GitHub Agent
&lt;/h3&gt;

&lt;p&gt;Code review, PR analysis, repository search. It reads actual code and configs, not summaries. When someone asks &lt;em&gt;"what changed in the proxy config last week?"&lt;/em&gt; — it reads every commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Build Your Own
&lt;/h3&gt;

&lt;p&gt;Any system with an API can become an MCP server. The pattern is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Find or build an MCP server&lt;/strong&gt; for the platform (many exist: AWS, Datadog, GitHub, PagerDuty, Slack, Jira, Confluence...)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If one doesn't exist&lt;/strong&gt; — build a lightweight one. An MCP server is just a program that exposes tools via the MCP protocol. A basic one is ~100 lines of Python.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add it to your config&lt;/strong&gt; — one JSON block with the command and credentials&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Restart&lt;/strong&gt; — the AI can now query that system
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# A minimal custom MCP server (simplified):
&lt;/span&gt;&lt;span class="nd"&gt;@mcp.tool&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;query_my_system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Query our internal API&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://internal-api.company.com/search&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;q&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;API_KEY&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;The principle:&lt;/strong&gt; If your tech stack has an API, you can make it conversational. DNS provider? MCP server. Internal CMDB? MCP server. Terraform state? MCP server. The AI becomes as capable as the tools you connect to it.&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  What We've Actually Achieved &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This isn't a proof of concept. Here's what production operational work looks like with OpenCode:&lt;/p&gt;

&lt;h3&gt;
  
  
  The &amp;gt;$100K/Month Cost Discovery
&lt;/h3&gt;

&lt;p&gt;Finance asked: &lt;em&gt;"What does each customer cost us?"&lt;/em&gt; In shared infrastructure where a single proxy pod serves all tenants — the conventional answer is &lt;em&gt;"we can't really tell you."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;We asked OpenCode. One session:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Pulled monthly billing from AWS Cost Explorer: &lt;strong&gt;$308,763&lt;/strong&gt; across four regions&lt;/li&gt;
&lt;li&gt;Discovered database Storage IO alone was &lt;strong&gt;$40,985/month&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Switched to Datadog, aggregated &lt;strong&gt;149 million proxy log entries&lt;/strong&gt; from 7 days&lt;/li&gt;
&lt;li&gt;Broke down by tenant: top customers = &lt;strong&gt;43% of all platform traffic&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Identified two accounts consuming &lt;strong&gt;60% of all activity&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Found &lt;strong&gt;$&amp;gt;100,000/month in addressable waste&lt;/strong&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output: a &lt;strong&gt;361-line Word document&lt;/strong&gt; with every number traced to an API response. Not estimates. Not SWAGs. Production telemetry.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Unused Resources Audit
&lt;/h3&gt;

&lt;p&gt;Across two AWS accounts and four regions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;unassociated Elastic IPs&lt;/strong&gt; (including legacy BYOIP blocks)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;load balancers&lt;/strong&gt; attached to decommissioned clusters&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;duplicate NAT gateways&lt;/strong&gt; in the same subnets&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;temporary RDS instance&lt;/strong&gt; someone forgot about&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Lambda functions&lt;/strong&gt; on end-of-life Node.js runtimes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Output: an Excel workbook, color-coded, with subtotals. Combined waste: ~$3,200/month plus the $97K overlap.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Cache Migration Pre-Mortem
&lt;/h3&gt;

&lt;p&gt;When the retry was planned, one prompt produced a full technical assessment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Read the ADO ticket for the method of procedure&lt;/li&gt;
&lt;li&gt;Queried ElastiCache for current topology&lt;/li&gt;
&lt;li&gt;Read 20KB of Kubernetes YAML from GitHub&lt;/li&gt;
&lt;li&gt;Identified a risk the team hadn't documented: in-flight tokens during the 30-60 second traffic propagation window&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Total time: 14 seconds.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How It Became a Force Multiplier for Incident Response &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The first time I used OpenCode during a live incident, I realized something: &lt;strong&gt;the AI was doing incident investigation faster and more consistently than our engineers.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not because it's smarter — because it doesn't context-switch.&lt;/p&gt;

&lt;p&gt;A human investigating an incident opens:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;PagerDuty → read the alert&lt;/li&gt;
&lt;li&gt;Datadog → search for the service, find the error spike&lt;/li&gt;
&lt;li&gt;GitHub → check if someone deployed something&lt;/li&gt;
&lt;li&gt;Cross-reference timestamps between all three tools&lt;/li&gt;
&lt;li&gt;Form a hypothesis&lt;/li&gt;
&lt;li&gt;Drill deeper — check affected tenants, error paths, queue depths&lt;/li&gt;
&lt;li&gt;Write up findings&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That's &lt;strong&gt;15-45 minutes&lt;/strong&gt; for an experienced engineer. More for a junior. And the cognitive overhead of switching between tools while sleep-deprived leads to missed signals and wrong conclusions.&lt;/p&gt;

&lt;p&gt;With OpenCode, the same investigation is one conversation:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"PagerDuty alert fired on proxy 5xx errors in EU. Check Datadog for error rates by backend and affected tenants. Check GitHub for any recent deployments to the primary EU cluster. What changed?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;90 seconds to 3 minutes.&lt;/strong&gt; Every time. No context switching. No missed signals. No investigating the wrong region.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;The realization:&lt;/strong&gt; If the AI can do this interactively in my terminal session, it can do it &lt;strong&gt;autonomously&lt;/strong&gt; when triggered by a PagerDuty webhook. It doesn't need me to type the question — it can formulate the question itself from the alert payload.

&lt;p&gt;That realization created FRIDAY.&lt;br&gt;

&lt;/p&gt;
&lt;/div&gt;





&lt;h2&gt;
  
  
  From OpenCode to FRIDAY — The Agent That Investigates Incidents Autonomously &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dev.to/velumal09/how-i-built-an-autonomous-incident-investigation-agent-that-reduced-mttr-by-65-42ae"&gt;FRIDAY&lt;/a&gt; is essentially &lt;strong&gt;OpenCode's incident investigation pattern, extracted into a Lambda that runs without a human typing the questions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The evolution:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Stage&lt;/th&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Human Involvement&lt;/th&gt;
&lt;th&gt;Response Time&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Before&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5 dashboards + manual investigation&lt;/td&gt;
&lt;td&gt;100% human&lt;/td&gt;
&lt;td&gt;15-45 minutes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;OpenCode&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AI-assisted investigation (human asks)&lt;/td&gt;
&lt;td&gt;Human types the prompt&lt;/td&gt;
&lt;td&gt;90 seconds&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FRIDAY&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Autonomous investigation (webhook triggers)&lt;/td&gt;
&lt;td&gt;Human reads the findings&lt;/td&gt;
&lt;td&gt;90 seconds (automated)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same tools. Same reasoning pattern. Same output format. But no human in the loop for the investigation phase — the on-call engineer wakes up to &lt;strong&gt;finished analysis&lt;/strong&gt; instead of a raw alert.&lt;/p&gt;

&lt;p&gt;Results after months in production:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;65% MTTR reduction&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;85% AI tool adoption&lt;/strong&gt; across the engineering team (up from 20%)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~80% reduction&lt;/strong&gt; in false escalations&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  From FRIDAY to JARVIS — Thinking About Write-Path Autonomy &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Once FRIDAY proved that an AI agent could reliably investigate production incidents (read-only), the natural question was: &lt;strong&gt;can it also fix things?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not incidents — those require human judgment in the moment. But &lt;strong&gt;vulnerability remediation&lt;/strong&gt; — the routine security fixes that follow a predictable pattern&lt;/p&gt;

&lt;p&gt;JARVIS is designed to handle that 80% — the routine fixes where the remediation is well-understood and the verification is automatable. Human approval gates at every stage. Automatic rollback if anything breaks.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;The progression:&lt;/strong&gt; OpenCode showed that AI + MCP tools can reason across multiple systems. FRIDAY proved it can do this autonomously for investigation. JARVIS extends it to autonomous remediation — with guardrails. Each step builds trust for the next.&lt;br&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Deleting 130k Accounts Without Writing Code &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Here's something that surprised even me: &lt;strong&gt;a complex tenant cleanup operation was largely driven through OpenCode sessions — by someone who didn't write the rake task.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The rake task existed. But executing it required understanding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which accounts to target (CSV generation from production queries)&lt;/li&gt;
&lt;li&gt;How to configure the runner (batch sizes, offsets, phase tracking)&lt;/li&gt;
&lt;li&gt;How to monitor progress (Datadog dashboard interpretation)&lt;/li&gt;
&lt;li&gt;How to troubleshoot when things broke (a 48K-user account hung the process, a zombie process ran for 35 hours, a metrics API bug caused silent data loss)&lt;/li&gt;
&lt;li&gt;How to communicate status (ADO tickets, Teams updates, DBA coordination)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OpenCode handled all of this conversationally:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What's the current status of Phase 2? Check the Rundeck execution and the Datadog dashboard."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"Create a task under the cleanup Feature for Phase 4 execution. Include the batch count, estimated timeline, and dependencies."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The runner seems stuck. Check processes on the worker for any rake tasks. What's happening?"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;"The DBA says the events database CPU spiked. Pull the top queries from the RDS monitoring dashboard. Cross-reference the account IDs with our cleanup CSV."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Each of these would normally require logging into 2-3 systems, running manual queries, and synthesizing results. With OpenCode, it's a conversation.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;The insight:&lt;/strong&gt; OpenCode doesn't just help experts go faster. It enables &lt;strong&gt;non-experts to execute complex operations&lt;/strong&gt; by providing the context and tool access they'd otherwise lack. You don't need to know how to read a Datadog dashboard if you can ask &lt;em&gt;"are there any errors related to our cleanup?"&lt;/em&gt;&lt;br&gt;

&lt;/div&gt;





&lt;h2&gt;
  
  
  Learning the Entire Product in Conversations &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When I joined the team, understanding the full platform took months. Multiple microservices.  AWS regions. EKS clusters. Proxy backends. RabbitMQ queues. Aurora databases. Redis caches. &lt;/p&gt;

&lt;p&gt;No single engineer understands all of it. The knowledge is distributed across dozens of people, hundreds of documents, and thousands of configuration files.&lt;/p&gt;

&lt;p&gt;OpenCode changed how new team members (and existing ones exploring unfamiliar areas) learn the platform:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"How does the push notification service work? What's its architecture? Where does it run, what does it depend on?"&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The AI reads the K8s config repo, checks which clusters the service is deployed to, reads the deployment YAML for dependencies (RabbitMQ queues, SNS topics, Redis), and synthesizes a technical overview — &lt;strong&gt;from live configuration, not stale documentation&lt;/strong&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"What happens when a user logs in via SAML? Trace the request path from the browser through the proxy to the backend services."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It reads the proxy backend configuration from GitHub, identifies the routing rules, checks which services handle SAML assertions, and traces the dependency chain — all from actual config files and Datadog service maps.&lt;/p&gt;

&lt;p&gt;This isn't replacing documentation. It's &lt;strong&gt;making the infrastructure self-documenting&lt;/strong&gt;. The source of truth isn't a wiki page someone wrote 18 months ago — it's the live configuration that the AI reads in real-time.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why This Is Different From ChatGPT &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Every engineer has pasted error messages into ChatGPT. That's not what this is.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;ChatGPT&lt;/th&gt;
&lt;th&gt;OpenCode + MCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Data source&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;General training data&lt;/td&gt;
&lt;td&gt;Live production systems via API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Specificity&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;"A 401 error usually means..."&lt;/td&gt;
&lt;td&gt;"Your API gateway generated 1.3 million of them yesterday"&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Infrastructure&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Doesn't know your systems&lt;/td&gt;
&lt;td&gt;Queries your actual AWS, Datadog, GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Freshness&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Training cutoff&lt;/td&gt;
&lt;td&gt;Real-time data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Hallucination&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Common for specifics&lt;/td&gt;
&lt;td&gt;Can't hallucinate API responses&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Action&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Suggests what to do&lt;/td&gt;
&lt;td&gt;Does it (queries, aggregates, cross-references)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The model doesn't need to be told which tools to use. Ask &lt;em&gt;"is the cache migration approach safe?"&lt;/em&gt; and it independently decides to: read the ADO ticket, query ElastiCache, read the K8s config, compare env var wiring, and synthesize. The engineer didn't specify any of those steps.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Uncomfortable Truth &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The uncomfortable truth is that most of what this system does &lt;strong&gt;isn't hard&lt;/strong&gt;. Any senior engineer can query AWS Cost Explorer, aggregate Datadog logs, read a GitHub PR, and review an ADO ticket.&lt;/p&gt;

&lt;p&gt;The hard part is doing all of them &lt;strong&gt;in the same mental context, in the same hour, without losing the thread&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;An engineer investigating the cache migration opens AWS in one tab, Datadog in another, GitHub in a third, ADO in a fourth, terminal in a fifth. Copy cache endpoint addresses, paste into GitHub search, cross-reference with K8s config, check ADO for the deployment timeline, look at Datadog for the error spike. Context switches. Tab switches. Copy-paste. Scroll. Search. Repeat.&lt;/p&gt;

&lt;p&gt;The system doesn't eliminate the need for engineering judgment. The engineer still decides whether the approach is safe, whether the risk is acceptable, whether the cost model makes sense. What the system eliminates is &lt;strong&gt;the mechanical overhead of gathering the information needed to make those decisions&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;That overhead, across a 20-person team managing multi-region production infrastructure for a global identity platform, adds up to something significant.&lt;/p&gt;




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

&lt;p&gt;We're six MCP servers in. The gaps are obvious: DNS management, direct Kubernetes cluster access for kubectl operations, Confluence for documentation. Each one is a JSON config block and a credential away from being connected.&lt;/p&gt;

&lt;p&gt;But the more interesting trajectory isn't more connectors — it's more autonomy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌────────────────────────────────────────────────────────┐
│  THE PROGRESSION                                        │
│                                                         │
│  Stage 1: Answer questions (OpenCode — today)           │
│     "What caused the 401 errors?"                       │
│                                                         │
│  Stage 2: Investigate autonomously (FRIDAY — live)      │
│     PagerDuty webhook → full analysis in 90 seconds     │
│                                                         │
│  Stage 3: Remediate autonomously (JARVIS — designing)   │
│     Vulnerability finding → PR → deploy → verify        │
│                                                         │
│  Stage 4: Predict and prevent (future)                  │
│     Detect anomaly → correlate → alert before impact    │
└────────────────────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each stage builds trust for the next. Read-only first. Then write-path with approval gates. Then proactive monitoring. Then autonomous prevention.&lt;/p&gt;

&lt;p&gt;The technology is ready for all of it. The trust model is what needs to catch up. We run AWS in read-only mode for a reason. But the trajectory is clear.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
For now, we'll settle for the fact that when Finance asks &lt;em&gt;"what does our biggest customer cost us?"&lt;/em&gt; — we answer with a number that came from production telemetry, not a spreadsheet someone made up.&lt;br&gt;

&lt;/div&gt;






&lt;p&gt;&lt;/p&gt;
  The complete OpenCode + MCP ecosystem
  &lt;br&gt;
&lt;strong&gt;Current MCP Servers (6):&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;AWS Production (IAM profile: prod, read-only)&lt;/li&gt;
&lt;li&gt;AWS Non-Production (IAM profile: non-prod, read-only)&lt;/li&gt;
&lt;li&gt;Datadog (logs, metrics, monitors, dashboards)&lt;/li&gt;
&lt;li&gt;GitHub (org repos, PRs, commits, code search)&lt;/li&gt;
&lt;li&gt;Azure DevOps (work items, sprints, wikis, pipelines)&lt;/li&gt;
&lt;li&gt;PagerDuty (incidents, schedules, escalation policies)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Sub-Agents Built:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doc Agent (postmortems, RCAs, roadmaps → Word/PDF)&lt;/li&gt;
&lt;li&gt;Incident Agent (FRIDAY — autonomous, Lambda-based)&lt;/li&gt;
&lt;li&gt;ADO Agent&lt;/li&gt;
&lt;li&gt;AWS Agent&lt;/li&gt;
&lt;li&gt;PD Agent&lt;/li&gt;
&lt;li&gt;Github Agent&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The beauty of this setup is that you can hook up as many tools as you want and create sub-agents for each of them — or just have one agent connected to everything. There's no right answer. Some engineers on my team prefer a single session with all 6 MCP servers connected — they ask about AWS costs, then pivot to a GitHub PR review, then check a PagerDuty schedule, all in one conversation. Others prefer focused agents: an AWS-only session for cost analysis, a Datadog-only session for incident investigation, a GitHub-only session for code review. The system doesn't impose a pattern and it adapts to how you think. Start with one MCP server. Connect your observability platform, or your ticketing system, or your cloud provider — whichever one you spend the most time context-switching into. Once you see the AI pull live data from it in a conversation, you'll immediately know which system to connect next. Within a week, you'll wonder how you ever operated without it&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Articles in the AI-Native SRE Series:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://dev.to/velumal09/how-i-built-an-autonomous-incident-investigation-agent-that-reduced-mttr-by-65-42ae"&gt;FRIDAY — Autonomous Incident Investigation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;JARVIS — Autonomous Vulnerability Remediation (upcoming)&lt;/li&gt;
&lt;li&gt;Tenant Cleanup — Live Debugging at Scale (upcoming)&lt;/li&gt;
&lt;li&gt;Platform Command Center (upcoming)&lt;/li&gt;
&lt;li&gt;Rundeck Migration — Legacy Jobs to Cloud-Native (upcoming)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;This article&lt;/strong&gt; — the origin story
&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;/p&gt;


&lt;p&gt;&lt;em&gt;I'm Vinothsingh Elumalai, a Platform Engineering leader building AI-native operations at enterprise scale. I lead infrastructure for a global IAM/SSO platform serving millions of users across multiple AWS regions. This article is the origin story of everything in my &lt;a href="https://dev.to/velumal09/series/ai-native-sre"&gt;AI-Native SRE&lt;/a&gt; series.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Connect with me on &lt;a href="https://linkedin.com/in/vinothsingh-elumalai-88967251" rel="noopener noreferrer"&gt;LinkedIn&lt;/a&gt; — I write about the intersection of AI, DevOps, and the future of platform engineering.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/velumal09" class="crayons-btn crayons-btn--primary"&gt;Follow for the Full Series&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>ai</category>
      <category>sre</category>
      <category>productivity</category>
      <category>aws</category>
    </item>
    <item>
      <title>How I Built FRIDAY ? An Autonomous Incident Investigation Agent That Reduced MTTR by 65%</title>
      <dc:creator>Vinothsingh Elumalai</dc:creator>
      <pubDate>Thu, 18 Jun 2026 04:22:12 +0000</pubDate>
      <link>https://dev.to/velumal09/how-i-built-an-autonomous-incident-investigation-agent-that-reduced-mttr-by-65-42ae</link>
      <guid>https://dev.to/velumal09/how-i-built-an-autonomous-incident-investigation-agent-that-reduced-mttr-by-65-42ae</guid>
      <description>&lt;h2&gt;
  
  
  Series: AI-Native SRE
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Problem Every On-Call Engineer Knows&lt;/li&gt;
&lt;li&gt;What FRIDAY Does&lt;/li&gt;
&lt;li&gt;Architecture Overview&lt;/li&gt;
&lt;li&gt;Key Design Decisions&lt;/li&gt;
&lt;li&gt;The Tool-Use Loop: How FRIDAY Reasons&lt;/li&gt;
&lt;li&gt;The Training System: Pre-Built Knowledge&lt;/li&gt;
&lt;li&gt;Handling Edge Cases&lt;/li&gt;
&lt;li&gt;Results&lt;/li&gt;
&lt;li&gt;Lessons Learned&lt;/li&gt;
&lt;li&gt;Try It Yourself&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Problem Every On-Call Engineer Knows &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;It's 2:47 AM. Your phone buzzes and it's a P1 alert. You open your laptop, bleary-eyed, and begin the familiar ritual:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open PagerDuty → read the alert title&lt;/li&gt;
&lt;li&gt;Open Datadog → search for the service, find the error spike&lt;/li&gt;
&lt;li&gt;Open GitHub → check if someone deployed something&lt;/li&gt;
&lt;li&gt;Cross-reference timestamps between all three tools&lt;/li&gt;
&lt;li&gt;Form a hypothesis&lt;/li&gt;
&lt;li&gt;Drill deeper — check affected tenants, error paths, queue depths&lt;/li&gt;
&lt;li&gt;Write up findings for the team&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This process takes &lt;strong&gt;15–45 minutes&lt;/strong&gt; for an experienced engineer. For a junior on-call? Sometimes hours. And the cognitive overhead of context-switching between 3-4 tools while sleep-deprived leads to missed signals, false conclusions, and longer outages.&lt;/p&gt;

&lt;p&gt;I asked myself:&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
What if an AI agent could do Steps 1–7 autonomously in under 3 minutes — and deliver structured findings to your team before the on-call engineer even opens their laptop?&lt;br&gt;

&lt;/div&gt;


&lt;p&gt;So I built one. It's been running in production for months, investigating real incidents on a platform serving &lt;strong&gt;30+ million end users&lt;/strong&gt; across multiple AWS regions. We call it &lt;strong&gt;FRIDAY&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What FRIDAY Does &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;When a PagerDuty alert fires, FRIDAY:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Receives the webhook&lt;/strong&gt; in real-time via API Gateway&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Locks the target region&lt;/strong&gt; from the alert metadata (never investigates the wrong region)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Checks GitHub first&lt;/strong&gt; — finds what changed before the alert (deployments, config changes, PRs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queries Datadog&lt;/strong&gt; — error rates, affected tenants, application exceptions, queue depths&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Synthesizes findings&lt;/strong&gt; — correlates code changes with observability signals&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Delivers a structured report&lt;/strong&gt; to Microsoft Teams as an Adaptive Card&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The entire investigation takes &lt;strong&gt;under 2 minutes&lt;/strong&gt;. The on-call engineer wakes up to a complete analysis instead of a raw alert.&lt;/p&gt;




&lt;h2&gt;
  
  
  Architecture Overview &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌──────────────┐     ┌────────────────┐     ┌─────────────────────┐
│  PagerDuty   │────▶│  API Gateway   │────▶│  Lambda (Sync)      │
│  Webhook     │     │  (Validate)    │     │  Parse + Self-Invoke│
└──────────────┘     └────────────────┘     └─────────┬───────────┘
                                                       │ Async
                                                       ▼
                                            ┌─────────────────────┐
                                            │  Lambda (Async)      │
                                            │  Investigation Agent │
                                            │                      │
                                            │  ┌────────────────┐ │
                                            │  │ Amazon Bedrock  │ │
                                            │  │ Claude Opus     │ │
                                            │  │ (Tool-Use Loop) │ │
                                            │  └───────┬────────┘ │
                                            │          │          │
                                            │    ┌─────┼─────┐   │
                                            │    ▼     ▼     ▼   │
                                            │ GitHub Datadog  S3  │
                                            └─────────┬───────────┘
                                                      │
                                                      ▼
                                            ┌─────────────────────┐
                                            │  Microsoft Teams    │
                                            │  (Adaptive Card)    │
                                            └─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Key Design Decisions &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;
&lt;h3&gt;
  
  
  1. Two-Lambda Architecture (Sync + Async)
&lt;/h3&gt;

&lt;p&gt;API Gateway has a &lt;strong&gt;30-second hard timeout&lt;/strong&gt;. A thorough AI investigation takes 60–180 seconds. The solution: the sync Lambda validates the webhook, parses the alert, and immediately self-invokes asynchronously returning &lt;code&gt;200 OK&lt;/code&gt; to PagerDuty within 2 seconds.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# Sync handler: validate, parse, self-invoke, return immediately
&lt;/span&gt;&lt;span class="n"&gt;lambda_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;FunctionName&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;function_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;InvocationType&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Event&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Fire and forget
&lt;/span&gt;    &lt;span class="n"&gt;Payload&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;_async_investigate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;alert_payload&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;alert_payload&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="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;statusCode&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;body&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Investigation started&lt;/span&gt;&lt;span class="sh"&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 async Lambda runs the full investigation without timeout pressure.&lt;/p&gt;
&lt;h3&gt;
  
  
  2. GitHub First, Datadog Second
&lt;/h3&gt;

&lt;p&gt;This is counterintuitive. Most engineers and most AI systems jump straight to observability data when an alert fires. But in my experience, &lt;strong&gt;80%+ of acute incidents are caused by a preceding change&lt;/strong&gt;: a deployment, a config update, a replica count change, a memory limit modification.&lt;/p&gt;

&lt;p&gt;FRIDAY is instructed to check GitHub &lt;em&gt;before&lt;/em&gt; touching Datadog:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;MANDATORY FIRST STEP — GitHub (Step 0):
Before touching Datadog, you MUST run these calls in parallel:
1. github_search_repos — find the repo for the alerted service
2. github_list_commits — find commits in the 2 hours before 
   the alert fired

A deployment or config change is the most likely root cause.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Why this matters:&lt;/strong&gt; When the AI correlates "this PR merged 12 minutes before the error spike" with "5xx errors started at exactly the merge timestamp" — it produces findings that are immediately actionable. This single design decision dramatically improved root cause accuracy.&lt;br&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Region Lock — Preventing Wrong-Region Investigation
&lt;/h3&gt;

&lt;p&gt;Our platform spans multiple AWS regions. A naive agent querying "all 5xx errors" would mix signals from healthy and unhealthy regions, producing confused analysis.&lt;/p&gt;

&lt;p&gt;FRIDAY's first action is always to &lt;strong&gt;lock a target region&lt;/strong&gt; from the alert metadata:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;🌍 Region: Description — resolved from alert hostname

Every subsequent Datadog query includes:
kube_cluster_name:region-az-* (scoped to affected region only)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This eliminated an entire class of false-positive findings where the AI would cite errors from an unrelated region.&lt;/p&gt;
&lt;h3&gt;
  
  
  4. Structured Output Contract
&lt;/h3&gt;

&lt;p&gt;FRIDAY's output isn't freeform text. It follows a strict section contract that the Teams integration parses into visual containers:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gu"&gt;## EXECUTIVE SUMMARY&lt;/span&gt;
[2-3 sentences — what happened, who's affected, what changed]

&lt;span class="gu"&gt;## KEY FINDINGS&lt;/span&gt;
[Bulleted evidence from GitHub + Datadog]

&lt;span class="gu"&gt;## WHAT CHANGED&lt;/span&gt;
[Specific commit/PR with timestamp and author]

&lt;span class="gu"&gt;## ERROR BREAKDOWN&lt;/span&gt;
[Service-by-service error counts with affected tenants]

&lt;span class="gu"&gt;## ROOT CAUSE&lt;/span&gt;
[Confirmed / Suspected / Unknown — with evidence chain]

&lt;span class="gu"&gt;## CUSTOMER IMPACT&lt;/span&gt;
[Affected tenants, operations, scope]

&lt;span class="gu"&gt;## RECOMMENDED ACTIONS&lt;/span&gt;
[Specific next steps for the on-call engineer]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The on-call engineer can glance at the Teams card and immediately know: &lt;em&gt;what happened, who's affected, what likely caused it, and what to do next&lt;/em&gt;  without reading a wall of text.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Tool-Use Loop: How FRIDAY Reasons &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;FRIDAY uses Claude's tool-use capability in a multi-round loop. The AI doesn't execute a fixed script — it &lt;strong&gt;reasons&lt;/strong&gt; about each alert independently, deciding which tools to call based on what it's learned so far.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;round_num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MAX_TOOL_ROUNDS&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;  &lt;span class="c1"&gt;# Max 25 rounds
&lt;/span&gt;    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;bedrock_client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;converse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;modelId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;anthropic.claude-opus&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;toolConfig&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tools&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;TOOL_DEFINITIONS&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;stop_reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;tool_use&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# Execute tools, append results, continue reasoning
&lt;/span&gt;        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tool_call&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;content_blocks&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
                &lt;span class="n"&gt;tool_call&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;input&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;tool_results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;stop_reason&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;end_turn&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# AI has concluded — extract findings
&lt;/span&gt;        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;extract_final_report&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;content_blocks&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Available Tools
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github_search_repos&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find which repo owns a service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github_list_commits&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;What changed before the alert&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github_get_file&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Read actual deployment configs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;github_search_code&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find all producers/consumers of a queue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datadog_log_search&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Find specific error messages&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datadog_log_aggregate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Count errors by backend/tenant/path&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datadog_query_metrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Queue depth, CPU, memory, latency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;datadog_get_monitor&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Understand what threshold triggered&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The AI typically uses &lt;strong&gt;8–15 tool calls per investigation&lt;/strong&gt;, batching parallel calls when possible to minimize round-trip time.&lt;/p&gt;


&lt;h2&gt;
  
  
  The Training System: Pre-Built Knowledge &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;A cold investigation — where the AI knows nothing about your infrastructure — is slow and imprecise. FRIDAY includes a &lt;strong&gt;deterministic training mode&lt;/strong&gt; that pre-builds architectural knowledge:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;train&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Deterministic training:
    ~13 targeted API calls, then one Bedrock synthesis call.

    Collects: cluster-service maps, HAProxy backends, 
    chronic error baselines, recent planned work.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Phase 1: Targeted data collection (no AI — pure API calls)
&lt;/span&gt;    &lt;span class="n"&gt;collected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_input&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;TRAINING_CALLS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;collected&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;execute_tool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tool_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tool_input&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 2: Single AI synthesis call
&lt;/span&gt;    &lt;span class="n"&gt;knowledge_doc&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;synthesize_knowledge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Phase 3: Save to S3 — injected into system prompt
&lt;/span&gt;    &lt;span class="nf"&gt;save_to_s3&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;knowledge_doc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The knowledge document contains:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cluster → Service map&lt;/strong&gt; — What runs where&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Chronic error baselines&lt;/strong&gt; — Background noise to ignore (not incidents)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recent planned work&lt;/strong&gt; — Deployments and migrations that explain expected errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend inventory&lt;/strong&gt; — Every backend serving traffic&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
&lt;strong&gt;Key insight:&lt;/strong&gt; Knowledge injection &amp;gt; Larger context windows. A &lt;em&gt;synthesized&lt;/em&gt; knowledge document — curated, current, and actionable — is more effective than dumping raw infrastructure documentation into the prompt. It captures &lt;em&gt;real state&lt;/em&gt;, not &lt;em&gt;aspirational state&lt;/em&gt;.&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Handling Edge Cases &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Planned Work vs. Real Incidents
&lt;/h3&gt;

&lt;p&gt;One of the hardest problems: distinguishing planned maintenance from real outages. During a Kubernetes cluster migration, you &lt;em&gt;expect&lt;/em&gt; 5xx errors as traffic drains. FRIDAY handles this through:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Knowledge injection&lt;/strong&gt; — Training mode captures recent PRs tagged as planned work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Real-time PR correlation&lt;/strong&gt; — During investigation, it reads PR bodies for keywords like "decommission", "drain", "planned"&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Explicit classification&lt;/strong&gt; — If a 5xx spike coincides with a merged "failover" PR, FRIDAY reports:&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;"This alert coincides with planned cluster decommission. Errors are expected during traffic drain. No incident action required."&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Force-Completion Under Round Limits
&lt;/h3&gt;

&lt;p&gt;What happens when an investigation is complex and approaching the 25-round tool limit? FRIDAY has a &lt;strong&gt;graceful degradation&lt;/strong&gt; mechanism:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;rounds_remaining&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;user_content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;STOP CALLING TOOLS. Write your FINAL report &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;NOW using all data collected so far. Mark &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;uncertain findings as &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Suspected&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; rather &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;than skipping them.&lt;/span&gt;&lt;span class="sh"&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;This ensures every investigation produces a report — even if incomplete — rather than timing out silently.&lt;/p&gt;
&lt;h3&gt;
  
  
  Deduplication
&lt;/h3&gt;

&lt;p&gt;PagerDuty retries webhooks. FRIDAY handles this at two levels:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Webhook-level&lt;/strong&gt; — In-memory cache of webhook IDs (survives Lambda warm starts)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident-level&lt;/strong&gt; — S3 marker files prevent re-investigating the same incident&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  Results &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;After running in production for several months:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before FRIDAY&lt;/th&gt;
&lt;th&gt;After FRIDAY&lt;/th&gt;
&lt;th&gt;Improvement&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mean Time to First Analysis&lt;/td&gt;
&lt;td&gt;15–45 min&lt;/td&gt;
&lt;td&gt;90 sec–3 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~90% faster&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MTTR (overall)&lt;/td&gt;
&lt;td&gt;~60 min&lt;/td&gt;
&lt;td&gt;~15 min&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;65% reduction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;AI tool adoption (team)&lt;/td&gt;
&lt;td&gt;20%&lt;/td&gt;
&lt;td&gt;85%&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;4x increase&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Alert noise (false escalations)&lt;/td&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;~80% reduction&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auto-generated postmortems&lt;/td&gt;
&lt;td&gt;0%&lt;/td&gt;
&lt;td&gt;100% of P1/P2&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Eliminated manual RCA drafts&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
The most impactful change isn't the speed — it's the &lt;strong&gt;consistency&lt;/strong&gt;. A human engineer at 3 AM makes mistakes: investigates the wrong region, misses a recent deployment, forgets to check queue depths. FRIDAY follows the same rigorous methodology every time.&lt;br&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Lessons Learned &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Prompt Engineering IS Architecture
&lt;/h3&gt;

&lt;p&gt;The system prompt is the most important file in the codebase. It's not instructions — it's the agent's &lt;strong&gt;operating manual&lt;/strong&gt;. Ours is ~5,000 words covering:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Environment topology (region mappings, cluster roles, service dependencies)&lt;/li&gt;
&lt;li&gt;Investigation methodology (step-by-step procedures)&lt;/li&gt;
&lt;li&gt;Critical rules (what NOT to do — as important as what to do)&lt;/li&gt;
&lt;li&gt;Output format contract&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Invest in your prompt like you invest in your architecture docs.&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. "GitHub First" Was the Single Biggest Win
&lt;/h3&gt;

&lt;p&gt;Before this rule, the AI would spend 10+ rounds querying Datadog, building elaborate theories about traffic patterns — then discover a config change was merged 5 minutes before the alert. Now it finds the root cause in rounds 1-2 for ~80% of change-induced incidents.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. You Need Guardrails, Not Just Capabilities
&lt;/h3&gt;

&lt;p&gt;FRIDAY is explicitly told it &lt;strong&gt;does NOT take remediation actions&lt;/strong&gt;. It investigates, analyzes, and reports. A human validates and acts. This is not a limitation — it's a &lt;strong&gt;design choice that builds trust&lt;/strong&gt;. When on-call engineers trust the AI's analysis, they act on it faster.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Separate Investigation from Notification
&lt;/h3&gt;

&lt;p&gt;The two-Lambda pattern (sync for webhook receipt, async for investigation) is essential. Don't let API Gateway timeouts dictate your AI agent's investigation depth.&lt;/p&gt;




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

&lt;p&gt;We're extending this pattern to &lt;strong&gt;autonomous security remediation&lt;/strong&gt; — an agent that ingests vulnerability findings, generates IaC fixes, deploys through GitOps, verifies no impact, and requests human approval before proceeding. Same tool-use architecture, different domain.&lt;/p&gt;


&lt;div class="crayons-card c-embed"&gt;

  &lt;br&gt;
The future of SRE isn't "AI-assisted." It's &lt;strong&gt;AI-native&lt;/strong&gt;: systems designed from the ground up with autonomous agents as first-class participants in the operational loop.&lt;br&gt;

&lt;/div&gt;





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

&lt;p&gt;The pattern is reproducible with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Amazon Bedrock&lt;/strong&gt; (Claude Opus or Sonnet for cost-sensitive use)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any webhook source&lt;/strong&gt; (PagerDuty, Opsgenie, Datadog)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any observability platform&lt;/strong&gt; with an API (Datadog, Grafana, New Relic)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any source control&lt;/strong&gt; (GitHub, GitLab)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Any chat platform&lt;/strong&gt; (Teams, Slack)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The hard part isn't the code — it's the &lt;strong&gt;system prompt&lt;/strong&gt;. That's where your SRE expertise lives. The AI is the execution engine; your knowledge of your infrastructure is what makes it useful.&lt;/p&gt;




&lt;p&gt;&lt;/p&gt;
  What does FRIDAY stand for?
  &lt;br&gt;
FRIDAY is named after Tony Stark's AI assistant in the Marvel universe. Because if I'm going to be on-call at 2 AM, I at least deserve a butler. ☕

&lt;p&gt;The name also works as a backronym: &lt;strong&gt;F&lt;/strong&gt;irst &lt;strong&gt;R&lt;/strong&gt;esponder for &lt;strong&gt;I&lt;/strong&gt;ncident &lt;strong&gt;D&lt;/strong&gt;iagnostics and &lt;strong&gt;A&lt;/strong&gt;nal*&lt;em&gt;Y&lt;/em&gt;*sis — but honestly, we just thought the Marvel reference was cooler.&lt;br&gt;
&lt;/p&gt;

&lt;br&gt;
&lt;p&gt;&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I'm Vinothsingh Elumalai, a Platform Engineering leader building AI-native operations at enterprise scale. I lead the Platform team for a global IAM/SSO platform serving 30M+ users. Currently exploring how agentic AI transforms SRE from reactive firefighting to autonomous, closed-loop operations.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is Part 1 of my &lt;strong&gt;AI-Native SRE&lt;/strong&gt; series. Part 2 will cover JARVIS — an autonomous vulnerability remediation agent that fixes security findings through GitOps with human approval gates.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://linkedin.com/in/vinothsingh-elumalai-88967251" class="crayons-btn crayons-btn--primary" rel="noopener noreferrer"&gt;Connect on LinkedIn&lt;/a&gt;
&lt;/p&gt;

</description>
      <category>aiops</category>
      <category>sre</category>
      <category>cloudnative</category>
      <category>aws</category>
    </item>
  </channel>
</rss>
