<?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: Sudharsana Viswanathan</title>
    <description>The latest articles on DEV Community by Sudharsana Viswanathan (@sudharsana_viswanathan_46).</description>
    <link>https://dev.to/sudharsana_viswanathan_46</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3811606%2F20116722-5eff-4c1a-b5ae-da368bd8c42d.png</url>
      <title>DEV Community: Sudharsana Viswanathan</title>
      <link>https://dev.to/sudharsana_viswanathan_46</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sudharsana_viswanathan_46"/>
    <language>en</language>
    <item>
      <title>From $0 to $35,000 in 6 Hours: How an API Leak and GCP Billing Lag Broke Our Startup</title>
      <dc:creator>Sudharsana Viswanathan</dc:creator>
      <pubDate>Sat, 21 Mar 2026 01:09:48 +0000</pubDate>
      <link>https://dev.to/sudharsana_viswanathan_46/from-0-to-35000-in-6-hours-how-an-api-leak-and-billing-lag-broke-our-startup-g6e</link>
      <guid>https://dev.to/sudharsana_viswanathan_46/from-0-to-35000-in-6-hours-how-an-api-leak-and-billing-lag-broke-our-startup-g6e</guid>
      <description>&lt;h1&gt;1.5 Million Requests, 1 Leaked Key: How We Burned $35,000 on Gemini in 6 Hours&lt;/h1&gt;


&lt;p&gt;The "experimental phase" of a project is supposed to be the fun part. For us, as a dedicated &lt;strong&gt;AWS-native shop&lt;/strong&gt;, we recently decided to branch out and test the &lt;strong&gt;Gemini 3.1 Pro Image model&lt;/strong&gt; on Google Cloud Platform (GCP).&lt;/p&gt;


&lt;p&gt;We did what every fast-moving team does: linked a business card, grabbed an API key, and started building. 20 days later, we had a &lt;strong&gt;$35,000 bill&lt;/strong&gt;, a panicked CEO, and a very expensive lesson in how GCP’s default quotas and billing latency work.&lt;/p&gt;


&lt;p&gt;If you are "just experimenting" with AI APIs, read this before you wake up to a five-figure surprise.&lt;/p&gt;





&lt;h2&gt;The "Perfect Storm" Timeline&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;The attack wasn't sophisticated, but it was relentless. Because we were experimenting, we hadn't yet applied our standard enterprise-grade security protocols to this new environment.&lt;/p&gt;


&lt;ul&gt;

    &lt;li&gt;

&lt;strong&gt;03:00 AM EST:&lt;/strong&gt; An unrestricted API key is leaked (likely via a compromised development environment). An automated botnet begins hammering our Gemini 3.1 Pro Image endpoint.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;08:00 AM EST:&lt;/strong&gt; Our CEO receives an automated billing alert: &lt;strong&gt;$11,000&lt;/strong&gt;.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;08:15 AM EST:&lt;/strong&gt; The team scrambles. We rotate the keys and disable project billing immediately. We honestly thought we stopped the bleeding at $11k.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;11:00 AM EST:&lt;/strong&gt; &lt;strong&gt;The "Billing Ghost" appears.&lt;/strong&gt; Because GCP billing data lags by 3–5 hours, the dashboard continues to climb as the morning's requests are finally processed.&lt;/li&gt;

  &lt;/ul&gt;


&lt;blockquote&gt;
&lt;br&gt;
    &lt;strong&gt;Final Damage:&lt;/strong&gt; 1.5 million requests. &lt;strong&gt;$35,000 USD burned.&lt;/strong&gt;&lt;br&gt;
  &lt;/blockquote&gt;





&lt;h2&gt;Why It Happened: The Default Quota Trap&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Coming from the AWS ecosystem, we were shocked by how extensive the default quotas are in GCP. When you enable the &lt;strong&gt;Generative Language API&lt;/strong&gt;, the default "Requests Per Minute" (RPM) is often set high enough to allow a botnet to drain a startup's bank account before the first cup of coffee is even brewed.&lt;/p&gt;


&lt;p&gt;Combined with a high-limit business card, the system did exactly what it was told to do: &lt;strong&gt;Scale.&lt;/strong&gt;&lt;/p&gt;





&lt;h2&gt;The "Never Again" Stack: Our 4-Step Mitigation Plan&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;Google Support has indicated they may consider a refund since this was a first-time incident, but they require a rigorous &lt;strong&gt;Remediation Plan&lt;/strong&gt;. Here is the "Fort Knox" setup we’ve implemented to ensure this stays a one-time mistake.&lt;/p&gt;


&lt;h3&gt;1. Real-Time Observability (Datadog Integration)&lt;/h3&gt;
&lt;br&gt;
  &lt;p&gt;Standard billing alerts are &lt;strong&gt;reactive&lt;/strong&gt;—they tell you what you &lt;em&gt;already&lt;/em&gt; spent. We needed to know what we are spending &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;We integrated &lt;strong&gt;Datadog&lt;/strong&gt; to monitor &lt;strong&gt;RPS (Requests Per Second)&lt;/strong&gt; and &lt;strong&gt;TPS (Transactions Per Second)&lt;/strong&gt; directly from our GCP logs.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;The Kill-Switch Alert:&lt;/strong&gt; If our Gemini request volume spikes 200% above the 10-minute moving average, Datadog triggers a PagerDuty alert immediately. We no longer wait for a billing email.&lt;/li&gt;

  &lt;/ul&gt;


&lt;h3&gt;2. Moving to Service Accounts (IAM &amp;gt; API Keys)&lt;/h3&gt;
&lt;br&gt;
  &lt;p&gt;"Naked" API keys are a massive liability. We are migrating all workloads to &lt;strong&gt;GCP Service Accounts&lt;/strong&gt;.&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;Instead of a static string that can be leaked, we use short-lived tokens and IAM roles.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;Local Dev:&lt;/strong&gt; Developers must now use &lt;code&gt;gcloud auth application-default login&lt;/code&gt; rather than generating a permanent, vulnerable key.&lt;/li&gt;

  &lt;/ul&gt;


&lt;h3&gt;3. Hard Quotas &amp;amp; AI Studio Spend Limits&lt;/h3&gt;
&lt;br&gt;
  &lt;p&gt;We realized "Unrestricted" is a dangerous default. We've tightened the screws on every point of entry:&lt;/p&gt;
&lt;br&gt;
  &lt;ul&gt;

    &lt;li&gt;

&lt;strong&gt;Hard Quotas:&lt;/strong&gt; We manually lowered our project-level quotas in the GCP Console to the bare minimum needed for production. If we hit the limit, the app returns a 429, but the bank account stays safe.&lt;/li&gt;

    &lt;li&gt;

&lt;strong&gt;AI Studio Limits:&lt;/strong&gt; For experimental keys, we now use &lt;strong&gt;Google AI Studio's spend limits&lt;/strong&gt;, which offer a much more granular "kill switch" compared to project-wide billing.&lt;/li&gt;

  &lt;/ul&gt;


&lt;h3&gt;4. The Proxy Layer&lt;/h3&gt;
&lt;br&gt;
  &lt;p&gt;Every request now flows through an &lt;strong&gt;Internal API Gateway&lt;/strong&gt;. This gateway acts as our final line of defense by validating user sessions and applying strict rate-limiting (e.g., 5 requests per minute per user) before it ever touches Google’s billable endpoints.&lt;/p&gt;





&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;br&gt;
  &lt;p&gt;We are currently in the 3–5 day "waiting window" to see if Google will waive the $35,000. While the stress has been immense, the experience forced us to build a production-grade security layer for our AI experiments.&lt;/p&gt;


&lt;p&gt;&lt;strong&gt;The takeaway?&lt;/strong&gt; If you’re an AWS shop trying out GCP, don’t treat it like a sandbox. Restrict your keys, lower your quotas, and for the love of your runway, &lt;strong&gt;monitor your RPS.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>gcp</category>
      <category>hacked</category>
      <category>aws</category>
    </item>
    <item>
      <title>Production AI Broke Because of a Model Deprecation — So I Built llm-model-deprecation</title>
      <dc:creator>Sudharsana Viswanathan</dc:creator>
      <pubDate>Sat, 07 Mar 2026 16:08:24 +0000</pubDate>
      <link>https://dev.to/sudharsana_viswanathan_46/production-ai-broke-because-of-a-model-deprecation-so-i-built-llm-model-deprecation-4925</link>
      <guid>https://dev.to/sudharsana_viswanathan_46/production-ai-broke-because-of-a-model-deprecation-so-i-built-llm-model-deprecation-4925</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Have you ever deployed an AI app, only to find it suddenly broken because OpenAI or Gemini deprecated a model you were using? 😱&lt;/p&gt;

&lt;p&gt;I did and it cost me hours of debugging, late-night panic, and a ton of lost productivity. Upgrading libraries when prod is down is no fun!&lt;/p&gt;

&lt;p&gt;If you’re building apps on LLMs like OpenAI, Anthropic, or Gemini, model deprecations aren’t just annoying. they’re dangerous.&lt;/p&gt;

&lt;p&gt;That’s why I created llm-model-deprecation, a lightweight Python library that alerts you before an LLM model disappears.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;LLM APIs evolve quickly:&lt;/p&gt;

&lt;p&gt;OpenAI retires older GPT-3.5 models.&lt;/p&gt;

&lt;p&gt;Gemini might tweak endpoint parameters without notice.&lt;/p&gt;

&lt;p&gt;Anthropic occasionally removes older Claude versions.&lt;/p&gt;

&lt;p&gt;If your production app depends on hardcoded model names, one day your API calls will start failing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Common consequences:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Broken chatbots&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Failed recommendation engines&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nightmarish debugging sessions&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;Instead of checking docs manually or waiting for an unexpected failure, I automated the process:&lt;br&gt;
✅ Track model deprecation status for OpenAI, Anthropic, Gemini&lt;/p&gt;

&lt;p&gt;✅ Receive early warnings before a model is deprecated&lt;/p&gt;

&lt;p&gt;✅ Integrate into CI/CD pipelines so your production app is always safe&lt;/p&gt;
&lt;h2&gt;
  
  
  Github Actions
&lt;/h2&gt;

&lt;p&gt;Run the same check in GitHub Actions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Check LLM deprecations
  uses: techdevsynergy/llm-model-deprecation@v1.1.0
  with:
    fail-on-deprecated: true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Options: path (project root to scan), fail-on-deprecated, version&lt;/p&gt;

&lt;h2&gt;
  
  
  CLI
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install llm-model-deprecation
llm-deprecation scan
llm-deprecation scan /path/to/project
llm-deprecation scan --fail-on-deprecated   # exit 1 if any found (for CI)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Library usage
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from llm_deprecation import DeprecationChecker, DeprecationStatus

checker = DeprecationChecker()

# Check by model id (searches all providers)
checker.is_deprecated("gpt-3.5-turbo-0301")   # True
checker.is_retired("gpt-3.5-turbo-0301")     # True
checker.status("gpt-4")                       # DeprecationStatus.ACTIVE

# With provider for exact match
checker.get("claude-2.0", provider="anthropic")
# -&amp;gt; ModelInfo(provider='anthropic or gemini or openai', model_id='claude-2.0', status=..., replacement='...', ...)

# List deprecated models
for m in checker.list_deprecated(provider="openai"):
    print(m.model_id, m.status.value, m.replacement)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Data Refresh (Weekly)
&lt;/h2&gt;

&lt;p&gt;I wrote web crawlers which runs every week to update/add model details. Registry is loaded from this &lt;a href="https://raw.githubusercontent.com/techdevsynergy/llm-deprecation-data/refs/heads/main/llm_deprecation_data.json" rel="noopener noreferrer"&gt;URL&lt;/a&gt;; if unreachable (e.g. offline), the built-in registry in the library is used. My company &lt;a href="https://reps.ai/" rel="noopener noreferrer"&gt;Reps.ai&lt;/a&gt; supports the cost here to keep this stable&lt;/p&gt;

&lt;h2&gt;
  
  
  Call to Action
&lt;/h2&gt;

&lt;p&gt;Try it today and never get caught by a model deprecation again:&lt;/p&gt;

&lt;p&gt;🔗 Check out &lt;a href="https://github.com/techdevsynergy/llm-model-deprecation" rel="noopener noreferrer"&gt;llm-model-deprecation&lt;/a&gt; on GitHub&lt;/p&gt;

&lt;p&gt;If this helps you, star the repo ⭐ — it motivates me to keep updating the library with new LLMs as they launch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Author
&lt;/h2&gt;

&lt;p&gt;Sudharsana Viswanathan, Engineering Lead at &lt;a href="https://reps.ai/" rel="noopener noreferrer"&gt;Reps.ai&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>llm</category>
      <category>python</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Never Get Caught by an LLM Deprecation Again: A Guide to llm-model-deprecation</title>
      <dc:creator>Sudharsana Viswanathan</dc:creator>
      <pubDate>Sat, 07 Mar 2026 13:22:17 +0000</pubDate>
      <link>https://dev.to/sudharsana_viswanathan_46/never-get-caught-by-an-llm-deprecation-again-a-guide-to-llm-model-deprecation-2opn</link>
      <guid>https://dev.to/sudharsana_viswanathan_46/never-get-caught-by-an-llm-deprecation-again-a-guide-to-llm-model-deprecation-2opn</guid>
      <description>&lt;p&gt;`&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to keep your apps on supported models with one Python package, a CLI, and a GitHub Action.&lt;/strong&gt;&lt;/p&gt;




&lt;p&gt;If you’ve ever had an integration break because OpenAI or Anthropic retired a model, you know the pain: sudden 404s, vague errors, and a scramble to find a replacement. Provider deprecation pages help, but they’re easy to miss when you’re shipping features. What you need is something that &lt;strong&gt;checks your code and config&lt;/strong&gt; for deprecated or retired models and tells you exactly what to change.&lt;/p&gt;

&lt;p&gt;That’s what &lt;strong&gt;llm-model-deprecation&lt;/strong&gt; does. It gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A &lt;strong&gt;Python library&lt;/strong&gt; to query deprecation status and get replacement suggestions&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;CLI&lt;/strong&gt; to scan a project for deprecated model references (great for CI and cron)&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;GitHub Action&lt;/strong&gt; so every push or PR can fail if you’re still using retired models&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The registry (OpenAI, Anthropic, Gemini, and more) is &lt;strong&gt;refreshed weekly&lt;/strong&gt;, so you’re not relying on stale data. Here’s how to use it in detail.&lt;/p&gt;




&lt;h2&gt;Why this matters&lt;/h2&gt;

&lt;p&gt;LLM providers regularly:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Deprecate&lt;/strong&gt; older models and set sunset dates&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Retire&lt;/strong&gt; models so they stop working entirely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recommend&lt;/strong&gt; newer, better, or cheaper replacements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If your app is hardcoded to &lt;code&gt;gpt-3.5-turbo-0301&lt;/code&gt; or &lt;code&gt;claude-2.0&lt;/code&gt;, one day those APIs will stop working. Catching that in CI or in a weekly scan is much cheaper than finding out in production. This package centralizes that check so you can automate it.&lt;/p&gt;




&lt;h2&gt;What the package does&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;llm-model-deprecation&lt;/strong&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads a &lt;strong&gt;registry&lt;/strong&gt; of model deprecation data (from a community-maintained source, with a built-in fallback).&lt;/li&gt;
&lt;li&gt;Lets you &lt;strong&gt;query&lt;/strong&gt; any model by ID (and optionally provider) to see if it’s active, legacy, deprecated, or retired.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scans&lt;/strong&gt; your project files (Python, JSON, YAML, env files, TypeScript, etc.) for known deprecated model IDs and reports what it finds.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The data is &lt;strong&gt;updated weekly&lt;/strong&gt;, so the library and CLI stay in sync with provider announcements. You don’t have to maintain the list yourself.&lt;/p&gt;




&lt;h2&gt;Installation&lt;/h2&gt;

&lt;p&gt;From PyPI:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pip install llm-model-deprecation
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want the library to load the registry from a URL using &lt;code&gt;requests&lt;/code&gt; (slightly more robust than the default stdlib), use the optional extra:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pip install "llm-model-deprecation[fetch]"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That’s it. No config files or API keys required for the checker or the CLI.&lt;/p&gt;




&lt;h2&gt;Using the library&lt;/h2&gt;

&lt;p&gt;After installing, you get a &lt;strong&gt;DeprecationChecker&lt;/strong&gt; that’s ready to use. It loads the registry automatically (online first, then built-in fallback if offline).&lt;/p&gt;

&lt;h3&gt;Basic checks&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;from llm_deprecation import DeprecationChecker, DeprecationStatus

checker = DeprecationChecker()

# Is this model deprecated or retired?
checker.is_deprecated("gpt-3.5-turbo-0301")   # True
checker.is_retired("gpt-3.5-turbo-0301")      # True

# What’s the status?
checker.status("gpt-4")   # DeprecationStatus.ACTIVE
checker.status("gpt-3.5-turbo-0613")   # DeprecationStatus.RETIRED
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The checker searches &lt;strong&gt;all providers&lt;/strong&gt; when you pass only a model ID. So you don’t need to remember whether a name is OpenAI or Anthropic.&lt;/p&gt;

&lt;h3&gt;Getting full details&lt;/h3&gt;

&lt;p&gt;When you need the full record (replacement suggestion, sunset date, notes):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;info = checker.get("claude-2.0", provider="anthropic")
if info:
    print(info.model_id)       # claude-2.0
    print(info.status)        # e.g. RETIRED
    print(info.replacement)   # e.g. claude-opus-4-6
    print(info.sunset_date)    # when it was retired
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Use &lt;code&gt;provider="openai"&lt;/code&gt;, &lt;code&gt;provider="anthropic"&lt;/code&gt;, or &lt;code&gt;provider="gemini"&lt;/code&gt; when you want to pin the provider; otherwise the first matching model ID across providers is returned.&lt;/p&gt;

&lt;h3&gt;Listing all deprecated models&lt;/h3&gt;

&lt;p&gt;To iterate over everything that’s deprecated or retired (optionally per provider):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;for m in checker.list_deprecated(provider="openai"):
    print(f"{m.model_id} → {m.status.value}, replace with: {m.replacement}")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Handy for dashboards, docs, or internal tooling.&lt;/p&gt;

&lt;h3&gt;Understanding status values&lt;/h3&gt;

&lt;p&gt;The registry uses four statuses:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1hvrd8zr9zj1nl8e3t0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fs1hvrd8zr9zj1nl8e3t0.png" alt=" " width="800" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Your code should treat &lt;strong&gt;deprecated&lt;/strong&gt; and &lt;strong&gt;retired&lt;/strong&gt; as “must fix”; &lt;strong&gt;legacy&lt;/strong&gt; as “plan to migrate.”&lt;/p&gt;

&lt;h3&gt;Adding or overriding models&lt;/h3&gt;

&lt;p&gt;If you have internal or beta models, or want to override the registry, you can register them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;from datetime import date
from llm_deprecation import DeprecationChecker
from llm_deprecation.models import ModelInfo, DeprecationStatus

checker = DeprecationChecker()
checker.register(ModelInfo(
    provider="openai",
    model_id="gpt-4-old",
    status=DeprecationStatus.DEPRECATED,
    sunset_date=date(2026, 1, 1),
    replacement="gpt-4o",
    notes="Internal alias; migrate by Q1 2026.",
))

# Now your code and the CLI will see this model
assert checker.is_deprecated("gpt-4-old")
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The scanner (CLI and library) will pick up these models when it searches the project.&lt;/p&gt;




&lt;h2&gt;Using the CLI&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;&lt;code&gt;llm-deprecation&lt;/code&gt;&lt;/strong&gt; command scans a directory for references to deprecated or retired models. It’s the same logic as the library, but you can run it from the shell, in CI, or from a cron job.&lt;/p&gt;

&lt;h3&gt;Basic scan&lt;/h3&gt;

&lt;p&gt;From the project root:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;llm-deprecation scan
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Or target a specific path:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;llm-deprecation scan /path/to/your/app
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Example output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Scanning project...
⚠ openai:gpt-3.5-turbo-0301 → retired
⚠ anthropic:claude-2.0 → retired
⚠ openai:text-embedding-ada-002 → deprecated soon
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Each line is a &lt;strong&gt;provider:model_id&lt;/strong&gt; plus whether it’s “deprecated soon” or “retired.” No noise—just what you need to fix.&lt;/p&gt;

&lt;h3&gt;Options&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;--fail-on-deprecated&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;Exit with code 1 if any deprecated or retired models are found. Use this in CI so the pipeline fails until the codebase is updated.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;-q&lt;/code&gt; / &lt;code&gt;--quiet&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;Skip the “Scanning project...” line. Useful when you’re parsing output or piping.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# CI-style: fail the job if anything is deprecated or retired
llm-deprecation scan --fail-on-deprecated

# Quiet run (e.g. in a script)
llm-deprecation scan -q
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;What gets scanned&lt;/h3&gt;

&lt;p&gt;The CLI looks at common code and config file types, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Code:&lt;/strong&gt; &lt;code&gt;.py&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.ts&lt;/code&gt;, &lt;code&gt;.tsx&lt;/code&gt;, &lt;code&gt;.jsx&lt;/code&gt;, &lt;code&gt;.mjs&lt;/code&gt;, &lt;code&gt;.cjs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Config:&lt;/strong&gt; &lt;code&gt;.json&lt;/code&gt;, &lt;code&gt;.yaml&lt;/code&gt;, &lt;code&gt;.yml&lt;/code&gt;, &lt;code&gt;.env&lt;/code&gt;, &lt;code&gt;.toml&lt;/code&gt;, &lt;code&gt;.ini&lt;/code&gt;, &lt;code&gt;.cfg&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docs:&lt;/strong&gt; &lt;code&gt;.md&lt;/code&gt;, &lt;code&gt;.rst&lt;/code&gt;, &lt;code&gt;.txt&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It skips directories like &lt;code&gt;.git&lt;/code&gt;, &lt;code&gt;node_modules&lt;/code&gt;, &lt;code&gt;.venv&lt;/code&gt;, &lt;code&gt;venv&lt;/code&gt;, &lt;code&gt;__pycache__&lt;/code&gt;, and &lt;code&gt;dist&lt;/code&gt;, so you don’t get false positives from dependencies or build artifacts.&lt;/p&gt;

&lt;p&gt;Because the &lt;strong&gt;model data is refreshed weekly&lt;/strong&gt;, running the CLI regularly (e.g. in CI or cron) means you see new deprecations soon after they’re added to the registry.&lt;/p&gt;




&lt;h2&gt;Using the GitHub Action&lt;/h2&gt;

&lt;p&gt;You can run the same check on every push or pull request with the official action.&lt;/p&gt;

&lt;h3&gt;Minimal workflow&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;name: CI
on: [push, pull_request]

jobs:
  llm-check:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Check LLM deprecations
        uses: techdevsynergy/llm-model-deprecation@v1.1.0
        with:
          fail-on-deprecated: true
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If the scan finds any deprecated or retired models, the step fails and the run is red. Fix the reported models, push again, and the check passes.&lt;/p&gt;

&lt;h3&gt;Action inputs&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjauxp54e1c9numdbrhs6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjauxp54e1c9numdbrhs6.png" alt=" " width="800" height="223"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Example with options:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- name: Check LLM deprecations
  uses: techdevsynergy/llm-model-deprecation@v1.1.0
  with:
    path: "."
    fail-on-deprecated: "true"
    version: "1.1.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Where to add it&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single repo:&lt;/strong&gt; Add the step to your main CI workflow (e.g. on &lt;code&gt;push&lt;/code&gt; and &lt;code&gt;pull_request&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monorepo:&lt;/strong&gt; Use &lt;code&gt;path&lt;/code&gt; to scan only the app that uses LLMs (e.g. &lt;code&gt;path: "services/ai"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Release gates:&lt;/strong&gt; Run the same job on the &lt;code&gt;main&lt;/code&gt; branch or on release tags so you never ship with deprecated models.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The action installs &lt;code&gt;llm-model-deprecation&lt;/code&gt; from PyPI and runs &lt;code&gt;llm-deprecation scan&lt;/code&gt; under the hood. Because the registry is &lt;strong&gt;updated weekly&lt;/strong&gt;, your CI automatically benefits from new deprecation data without changing the workflow.&lt;/p&gt;




&lt;h2&gt;Data source and weekly updates&lt;/h2&gt;

&lt;p&gt;The package does &lt;strong&gt;not&lt;/strong&gt; ship with a static, frozen list. It uses:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A &lt;strong&gt;default URL&lt;/strong&gt; that serves a community-maintained registry (e.g. &lt;a href="https://github.com/techdevsynergy/llm-deprecation-data" rel="noopener noreferrer"&gt;techdevsynergy/llm-deprecation-data&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;A &lt;strong&gt;built-in fallback&lt;/strong&gt; in the library for when the network is unavailable (e.g. air-gapped or CI with no outbound access).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That registry is &lt;strong&gt;refreshed weekly&lt;/strong&gt; with the latest deprecations and retirements from provider docs (OpenAI, Anthropic, Google Gemini, etc.). So:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Library:&lt;/strong&gt; Each time you create a &lt;code&gt;DeprecationChecker()&lt;/code&gt; or run the CLI, it can load the latest data (or the fallback).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CI / Action:&lt;/strong&gt; Each run can see the current week’s data, so new deprecations show up in your pipeline shortly after they’re published.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You don’t need to configure anything for this; it’s the default behavior.&lt;/p&gt;




&lt;h2&gt;Putting it together: recommended workflow&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install&lt;/strong&gt;&lt;br&gt;&lt;code&gt;pip install llm-model-deprecation&lt;/code&gt; (or with &lt;code&gt;[fetch]&lt;/code&gt; if you prefer).&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;In code&lt;/strong&gt;&lt;br&gt;When choosing or validating a model ID (e.g. from config or user input), call &lt;code&gt;checker.is_deprecated(model_id)&lt;/code&gt; or &lt;code&gt;checker.get(model_id)&lt;/code&gt; and warn or block if deprecated/retired.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;In CI&lt;/strong&gt;&lt;br&gt;Add the GitHub Action with &lt;code&gt;fail-on-deprecated: true&lt;/code&gt; so no PR or push can merge with deprecated/retired model references.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Optionally in cron&lt;/strong&gt;&lt;br&gt;Run &lt;code&gt;llm-deprecation scan /path/to/app --fail-on-deprecated&lt;/code&gt; on a schedule and send the output to Slack or email if something appears.&lt;/p&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;p&gt;&lt;strong&gt;Stay updated&lt;/strong&gt;&lt;br&gt;Upgrade the package occasionally so you get the latest CLI and library behavior; the registry itself is refreshed weekly on the server side.&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;




&lt;h2&gt;Summary&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;llm-model-deprecation&lt;/strong&gt; gives you a Python API, a CLI, and a GitHub Action to keep your app off deprecated and retired LLM models.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;registry is refreshed weekly&lt;/strong&gt;, so you’re not relying on outdated data.&lt;/li&gt;
&lt;li&gt;Use the &lt;strong&gt;library&lt;/strong&gt; to check model IDs in code; use the &lt;strong&gt;CLI&lt;/strong&gt; for ad-hoc or scripted scans; use the &lt;strong&gt;Action&lt;/strong&gt; to enforce the check on every push or PR.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can install it with &lt;code&gt;pip install llm-model-deprecation&lt;/code&gt;, add one step to your workflow, and stop worrying about surprise model retirements.&lt;/p&gt;




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



&lt;ul&gt;


&lt;li&gt;&lt;a href="https://github.com/marketplace/actions/llm-model-deprecation-check" rel="noopener noreferrer"&gt;Github Actions&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href="https://github.com/techdevsynergy/llm-model-deprecation" rel="noopener noreferrer"&gt;GitHub: techdevsynergy/llm-model-deprecation&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href="https://pypi.org/project/llm-model-deprecation/" rel="noopener noreferrer"&gt;PyPI: llm-model-deprecation&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href="https://developers.openai.com/api/docs/deprecations" rel="noopener noreferrer"&gt;OpenAI API deprecations&lt;/a&gt;&lt;/li&gt;


&lt;li&gt;&lt;a href="https://docs.anthropic.com/en/docs/resources/model-deprecations" rel="noopener noreferrer"&gt;Anthropic model deprecations&lt;/a&gt;&lt;/li&gt;


&lt;/ul&gt;`

</description>
      <category>llm</category>
      <category>devops</category>
      <category>githubactions</category>
      <category>openai</category>
    </item>
  </channel>
</rss>
