<?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: Prismix</title>
    <description>The latest articles on DEV Community by Prismix (@max_98b3db49c06de66802dcd).</description>
    <link>https://dev.to/max_98b3db49c06de66802dcd</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%2F3939773%2F02ea64f5-7067-445a-9fd0-d86f2f343ee0.png</url>
      <title>DEV Community: Prismix</title>
      <link>https://dev.to/max_98b3db49c06de66802dcd</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/max_98b3db49c06de66802dcd"/>
    <language>en</language>
    <item>
      <title>Which AI APIs go down most? Data from 6 weeks monitoring 77 services</title>
      <dc:creator>Prismix</dc:creator>
      <pubDate>Fri, 17 Jul 2026 10:56:37 +0000</pubDate>
      <link>https://dev.to/max_98b3db49c06de66802dcd/which-ai-apis-go-down-most-data-from-6-weeks-monitoring-77-services-7c9</link>
      <guid>https://dev.to/max_98b3db49c06de66802dcd/which-ai-apis-go-down-most-data-from-6-weeks-monitoring-77-services-7c9</guid>
      <description>&lt;p&gt;Every developer who has shipped an AI-powered feature knows the moment. Your logs light up with 500s or timeouts, your users are reporting failures, and your first instinct is to open a new tab and type "is OpenAI down." The status page loads green. You stare at it for a second. Then you go check Twitter.&lt;/p&gt;

&lt;p&gt;That gap between "something is clearly wrong" and "the status page admits something is wrong" is where real incidents live — and it's what motivated us to build &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;Prismix&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  How we collect the data
&lt;/h2&gt;

&lt;p&gt;For the past six weeks, Prismix has been polling the official status pages and running direct API health probes against &lt;strong&gt;77 AI services&lt;/strong&gt; every five minutes. That includes the obvious ones — OpenAI, Anthropic, Gemini, Mistral, Groq, Perplexity, GitHub Copilot, DeepSeek — plus the growing wave of image, audio, and video generation services: ElevenLabs, Runway, Replicate, Stability AI, and dozens more.&lt;/p&gt;

&lt;p&gt;Each probe records response latency, HTTP status codes, and whether the official status page matches what we're actually seeing. The result is a dataset of thousands of polling cycles per service, spanning incidents both small and significant.&lt;/p&gt;

&lt;p&gt;Here's what we found.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI leads in incident volume — Anthropic leads in resolution speed
&lt;/h2&gt;

&lt;p&gt;By raw incident count, &lt;strong&gt;OpenAI has more status events than any other provider in our dataset&lt;/strong&gt;. That's not a knock on their reliability — it's a function of surface area. OpenAI runs the most products, has the most API surface, and serves the most traffic. More moving parts means more opportunities for something to report degraded.&lt;/p&gt;

&lt;p&gt;What's interesting is the contrast with Anthropic. Anthropic logs fewer incidents by count, but the pattern that stands out is &lt;strong&gt;resolution time&lt;/strong&gt;. When Anthropic posts an "investigating" status, it tends to move to "resolved" faster than the category average. Whether that reflects a smaller blast radius, tighter incident runbooks, or simply fewer services in play, the outcome is the same: shorter mean time to resolution.&lt;/p&gt;

&lt;h2&gt;
  
  
  The "investigating" phase is where developers panic — but it usually ends fast
&lt;/h2&gt;

&lt;p&gt;When a status page flips from green to "investigating," developers go into triage mode. Do we fall back to a different model? Do we queue requests and wait? Do we page someone?&lt;/p&gt;

&lt;p&gt;The data suggests: &lt;strong&gt;in more than 80% of cases, "investigating" → "resolved" completes within two hours.&lt;/strong&gt; Most incidents are shorter than that. Catastrophic multi-hour outages exist — we've recorded several — but they're the exception, not the pattern.&lt;/p&gt;

&lt;p&gt;The practical implication: a retry loop with exponential backoff covering the first 30–60 minutes handles the majority of incidents transparently to end users. Full circuit-breaker logic and cross-provider routing matters for the tail, not the median.&lt;/p&gt;

&lt;h2&gt;
  
  
  Status pages lag reality by 10–20 minutes — consistently
&lt;/h2&gt;

&lt;p&gt;This is the finding that surprised us least but that developers most need to hear explicitly: &lt;strong&gt;official status pages are systematically late&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;We've recorded dozens of incidents where our API probes showed elevated error rates, degraded latency, or 429 storms well before the corresponding status page acknowledged anything. The typical lag is 10–20 minutes. In some cases it's longer.&lt;/p&gt;

&lt;p&gt;"Silent degradation" — where an API returns errors or slows down significantly before any public acknowledgment — is the default incident pattern, not an edge case. If your alerting depends solely on status page webhooks, you have a 10–20 minute blind spot by design.&lt;/p&gt;

&lt;h2&gt;
  
  
  The most stable services might surprise you
&lt;/h2&gt;

&lt;p&gt;The services with the &lt;strong&gt;fewest incidents in our dataset are Groq, Mistral, and Cerebras&lt;/strong&gt;. All three are newer entrants, run narrower API surfaces, and focus almost exclusively on inference rather than operating multi-product ecosystems. Fewer integrations, fewer failure domains.&lt;/p&gt;

&lt;p&gt;This isn't a permanent characteristic — as these platforms grow, complexity tends to follow — but right now, if raw uptime is the top priority for a workload, the smaller inference providers punch above their weight.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenAI and Anthropic incidents don't correlate
&lt;/h2&gt;

&lt;p&gt;One of the more useful findings for system design: &lt;strong&gt;OpenAI incident windows do not meaningfully overlap with Anthropic incident windows&lt;/strong&gt;. Their infrastructure, their scaling events, and their failure modes are largely independent.&lt;/p&gt;

&lt;p&gt;This is the empirical case for routing across providers. If you have a fallback path from an OpenAI call to an equivalent Anthropic call, the two failure probabilities multiply rather than add. The redundancy is real, not theoretical.&lt;/p&gt;

&lt;h2&gt;
  
  
  What this means for how you build
&lt;/h2&gt;

&lt;p&gt;A few practical conclusions from six weeks of data:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Design for the degraded state.&lt;/strong&gt; Most AI API failures are partial — elevated latency, elevated error rates, not a total blackout. Streaming with timeouts, graceful fallbacks to cached responses, and user-facing "AI is slow right now" messaging all perform better than assuming the API is binary up or down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Don't use the status page as your real-time signal.&lt;/strong&gt; Use it for incident communication and post-mortems. For real-time detection, you need your own probes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Route across independent failure domains.&lt;/strong&gt; The OpenAI/Anthropic correlation data supports this directly. Treating providers as interchangeable based purely on model capability misses the reliability dimension.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add status checks to your own monitoring
&lt;/h2&gt;

&lt;p&gt;Prismix exposes a public REST endpoint — no API key required:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;GET https://prismix.dev/api/v1/statuses
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It returns current status for all 77 services in a single JSON response. Drop it into your existing health check pipeline, your Grafana dashboard, or your on-call runbook.&lt;/p&gt;




&lt;p&gt;The dashboard itself is at &lt;strong&gt;&lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;prismix.dev&lt;/a&gt;&lt;/strong&gt; — free, no account required. If you're building on top of AI APIs and you're not watching the upstream services you depend on, this is the lowest-effort way to start.&lt;/p&gt;

&lt;p&gt;We'll keep publishing findings as the dataset grows. Six weeks is a start; six months will be more interesting.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>javascript</category>
      <category>devops</category>
    </item>
    <item>
      <title>We built a free MCP server so Claude can answer 'Is OpenAI down?' — here's how</title>
      <dc:creator>Prismix</dc:creator>
      <pubDate>Tue, 14 Jul 2026 09:11:17 +0000</pubDate>
      <link>https://dev.to/max_98b3db49c06de66802dcd/we-built-a-free-mcp-server-so-claude-can-answer-is-openai-down-heres-how-3op8</link>
      <guid>https://dev.to/max_98b3db49c06de66802dcd/we-built-a-free-mcp-server-so-claude-can-answer-is-openai-down-heres-how-3op8</guid>
      <description>&lt;p&gt;You're deep in a coding session. Something breaks. The model call returns nothing. Your first instinct is to open a new tab, navigate to the vendor's status page, wait for it to load, and try to figure out if "Degraded Performance" means your specific API call is affected or not.&lt;/p&gt;

&lt;p&gt;That context switch costs maybe 90 seconds. It feels longer.&lt;/p&gt;

&lt;p&gt;At Prismix we track live status for 77 AI services — OpenAI, Anthropic, Cursor, Mistral, Perplexity, GitHub Copilot, and dozens more — at &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;prismix.dev&lt;/a&gt;. We already had the data. The obvious next step was surfacing it where developers actually are: inside their AI assistant.&lt;/p&gt;

&lt;p&gt;So we built an MCP server.&lt;/p&gt;




&lt;h2&gt;
  
  
  The setup takes 30 seconds
&lt;/h2&gt;

&lt;p&gt;Add this to your &lt;code&gt;claude_desktop_config.json&lt;/code&gt;:&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;"prismix-status"&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://prismix.dev/api/v1/mcp"&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;Restart Claude Desktop. That's it. No API key. No account. No npm package to install or keep updated.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you can ask Claude now
&lt;/h2&gt;

&lt;p&gt;Once connected, Claude has live access to our status data:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;"Is OpenAI down right now?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Which AI services are currently having incidents?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"What's the status of Anthropic's API?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Has Cursor been having issues today?"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Show me all services with degraded performance"&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;"Is it just me or is GitHub Copilot acting up?"&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude reads the current status, the active incident description, and the affected components — and answers in plain language without you switching context.&lt;/p&gt;




&lt;h2&gt;
  
  
  How the MCP endpoint works on Cloudflare Workers
&lt;/h2&gt;

&lt;p&gt;The interesting engineering problem was making MCP work on Cloudflare Workers.&lt;/p&gt;

&lt;p&gt;Workers are edge functions — stateless, no persistent connections, maximum execution time measured in seconds. The MCP spec was originally designed with stdio transports and long-lived sessions in mind. Those assumptions don't hold at the edge.&lt;/p&gt;

&lt;p&gt;The solution was &lt;strong&gt;Streamable HTTP transport&lt;/strong&gt; — the newer MCP transport that works as a standard POST/GET HTTP exchange. Each request is fully self-contained: client sends a JSON-RPC message, server responds, connection closes.&lt;/p&gt;

&lt;p&gt;In Astro, the endpoint handles two methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET&lt;/code&gt; — returns the server manifest (name, version, available tools)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST&lt;/code&gt; — receives a tool call, fetches fresh status data from KV, returns the result
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APIRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;request&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;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tools/list&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TOOL_DEFINITIONS&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tools/call&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchCurrentStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// reads from Cloudflare KV&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;formatToolResponse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;The edge constraint turned out to be an advantage.&lt;/strong&gt; Because every request is stateless, there's nothing to go wrong between calls. No session to expire, no WebSocket to drop, no daemon to restart. The one tradeoff: MCP sessions that rely on server-sent state across calls need to re-fetch each time. For status data that's fine — we want fresh data anyway.&lt;/p&gt;




&lt;h2&gt;
  
  
  What people actually ask about
&lt;/h2&gt;

&lt;p&gt;Something we noticed after launching: through the MCP endpoint, &lt;strong&gt;Cursor and GitHub Copilot get queried constantly&lt;/strong&gt; — roughly on par with OpenAI. On the website it's mainly OpenAI and Anthropic.&lt;/p&gt;

&lt;p&gt;That makes sense in retrospect. Cursor and Copilot are editor-native tools. When they break, you're already in your editor. Asking Claude via MCP is the natural move — you're already mid-conversation with it.&lt;/p&gt;

&lt;p&gt;The right interface for developer tooling status is wherever the developer already is, not a page they navigate to.&lt;/p&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&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;"prismix-status"&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;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://prismix.dev/api/v1/mcp"&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;Full setup guide: &lt;strong&gt;&lt;a href="https://prismix.dev/mcp-server" rel="noopener noreferrer"&gt;prismix.dev/mcp-server&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Prismix is a free AI infrastructure status hub tracking 77 services. The dashboard, REST API, and MCP server are all free, no login required.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>ai</category>
      <category>cloudflare</category>
    </item>
    <item>
      <title>We built a free status monitor for 77 AI APIs. Here's what 6 weeks of data taught us.</title>
      <dc:creator>Prismix</dc:creator>
      <pubDate>Mon, 22 Jun 2026 09:59:03 +0000</pubDate>
      <link>https://dev.to/max_98b3db49c06de66802dcd/we-built-a-free-status-monitor-for-77-ai-apis-heres-what-6-weeks-of-data-taught-us-56ko</link>
      <guid>https://dev.to/max_98b3db49c06de66802dcd/we-built-a-free-status-monitor-for-77-ai-apis-heres-what-6-weeks-of-data-taught-us-56ko</guid>
      <description>&lt;p&gt;Every AI developer has been here: your app is throwing 503s, users are pinging you, and you have 12 browser tabs open — OpenAI status page, Anthropic status page, the GitHub Copilot health page, three different Discord servers — trying to figure out &lt;em&gt;is this me or is it them?&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That's the problem we set out to solve. &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;Prismix&lt;/a&gt; aggregates status from 77 AI services in one place. Six weeks of running it in production taught us some things that might save you time.&lt;/p&gt;




&lt;h2&gt;
  
  
  The problem is worse than you think
&lt;/h2&gt;

&lt;p&gt;AI APIs don't fail like traditional infrastructure. They fail in weird, partial ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Degraded performance&lt;/strong&gt; that passes your health checks but makes your product feel broken&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Regional outages&lt;/strong&gt; — OpenAI US-East is down while EU is fine, so half your users are affected&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent rate-limit cascades&lt;/strong&gt; — the API returns 429s but their status page says "operational" for another 20 minutes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Incident lag&lt;/strong&gt; — providers often post status updates 10–30 minutes after engineers are already aware&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The official status pages are optimistic by design. They're customer-facing communications tools, not real-time engineering dashboards. There's nothing wrong with this — but it means you need a different mental model for "is this service down?"&lt;/p&gt;




&lt;h2&gt;
  
  
  What 77 status pages look like in aggregate
&lt;/h2&gt;

&lt;p&gt;When you watch 77 AI services simultaneously, patterns emerge fast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenAI&lt;/strong&gt; is the most-watched service (and has the most incidents to watch). The pattern is almost always the same: &lt;code&gt;investigating&lt;/code&gt; → &lt;code&gt;identified&lt;/code&gt; → &lt;code&gt;monitoring&lt;/code&gt; → &lt;code&gt;resolved&lt;/code&gt;, typically in 45–90 minutes. The &lt;code&gt;investigating&lt;/code&gt; phase is where most developers panic — it looks bad but usually resolves without action on your end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Anthropic&lt;/strong&gt; runs noticeably clean compared to its API usage growth. Incidents are rarer and shorter. When they do happen, updates arrive faster than most providers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The long tail is interesting.&lt;/strong&gt; Services like Replicate, Runway, ElevenLabs, and Suno have incident patterns that don't correlate with OpenAI at all. If you're routing across multiple providers for redundancy, these are genuinely independent failure domains — worth knowing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The "silent degradation" problem is real.&lt;/strong&gt; Multiple times we've seen a service show "operational" on its status page while our uptime probe was timing out. This is the main reason Prismix shows a latency sparkline per service — the status page is authoritative for &lt;em&gt;announced&lt;/em&gt; incidents, but the probe catches &lt;em&gt;real&lt;/em&gt; ones.&lt;/p&gt;




&lt;h2&gt;
  
  
  What Prismix built (and why it's free)
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;Prismix&lt;/a&gt; pulls from official status pages, aggregates them into a single dashboard, and adds a few things that the individual pages don't have:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Per-service latency probes&lt;/strong&gt; — 24-hour sparklines showing actual response times, not just announced incidents. This catches the "silent degradation" cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-service incident timeline&lt;/strong&gt; — &lt;code&gt;/incidents&lt;/code&gt; shows everything that happened across all 77 services in one scrollable feed. Useful for postmortems ("was anything else degraded when our error rate spiked at 3pm Tuesday?").&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embeddable status badges&lt;/strong&gt; — put a live "OpenAI: operational" badge in your own app's status page with one line of HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Public REST API&lt;/strong&gt; — &lt;code&gt;GET /api/v1/statuses&lt;/code&gt; returns current status for all 77 services as JSON. No auth, no rate limit for reasonable use, CORS open. Free forever.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;RSS feed&lt;/strong&gt; — &lt;code&gt;/incidents.rss&lt;/code&gt; if you want AI incident updates in your feed reader.&lt;/p&gt;

&lt;p&gt;It's free because it runs entirely on Cloudflare's free tier (Workers + KV). The Pro tier ($10/mo) adds email and webhook alerts for services you care about, but the core dashboard stays free.&lt;/p&gt;




&lt;h2&gt;
  
  
  The technical part (because this is dev.to)
&lt;/h2&gt;

&lt;p&gt;The stack is Astro 5 SSR + Cloudflare Workers + KV. We wrote about the performance walls we hit &lt;a href="https://dev.to/max_98b3db49c06de66802dcd/4-perf-walls-i-hit-shipping-an-ai-hub-on-cloudflare-workers-kv-246"&gt;in a previous post&lt;/a&gt; — the short version is that 77 parallel KV reads per request is a bad idea and a single pre-aggregated snapshot blob is much better.&lt;/p&gt;

&lt;p&gt;One thing that surprised us: KV's free tier gives you 100,000 &lt;em&gt;reads&lt;/em&gt; per day but only 1,000 &lt;em&gt;writes&lt;/em&gt;. The cron job that refreshes status runs every 5 minutes, so every write is conditional — only write if the content actually changed. That dropped writes from ~8,400/day to ~600/day. Monitoring infrastructure has to be cheap to run, otherwise the incentive to keep it free disappears.&lt;/p&gt;




&lt;h2&gt;
  
  
  What we don't know yet — and why we're writing this
&lt;/h2&gt;

&lt;p&gt;Six weeks in, Prismix tracks 77 services with a clean incident timeline and growing usage. What we don't have yet is signal on what matters to &lt;em&gt;you&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Some things we're genuinely uncertain about:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Which services are missing?&lt;/strong&gt; The list is opinionated — mostly LLM APIs, popular AI tools, and infrastructure adjacent to them. We've probably missed something obvious in your stack.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Is the latency probe useful?&lt;/strong&gt; It tells you "this service is slow right now" but not "slow compared to what" — no historical baseline yet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What would make you actually use this every day?&lt;/strong&gt; A Slack bot? A PagerDuty integration? Something in your terminal?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If any of that resonates, drop a comment. Honest feedback shapes what gets built next.&lt;/p&gt;

&lt;p&gt;Live at &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;prismix.dev&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Also at Prismix: an &lt;a href="https://prismix.dev/mcp" rel="noopener noreferrer"&gt;MCP server directory&lt;/a&gt; with 500+ servers and a &lt;a href="https://prismix.dev/news" rel="noopener noreferrer"&gt;curated AI news feed&lt;/a&gt; — but the status monitoring is the part we're most curious to hear about.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>cloudflare</category>
      <category>webdev</category>
      <category>devops</category>
    </item>
    <item>
      <title>4 perf walls I hit shipping an AI hub on Cloudflare Workers KV</title>
      <dc:creator>Prismix</dc:creator>
      <pubDate>Tue, 19 May 2026 09:02:22 +0000</pubDate>
      <link>https://dev.to/max_98b3db49c06de66802dcd/4-perf-walls-i-hit-shipping-an-ai-hub-on-cloudflare-workers-kv-246</link>
      <guid>https://dev.to/max_98b3db49c06de66802dcd/4-perf-walls-i-hit-shipping-an-ai-hub-on-cloudflare-workers-kv-246</guid>
      <description>&lt;p&gt;Status pages don't aggregate. AI news lives in 60 RSS feeds. MCP servers are scattered across awesome-lists.&lt;/p&gt;

&lt;p&gt;So I built Prismix - one URL for all three - on Cloudflare Workers + Astro 5. Here's what broke and what fixed it.&lt;/p&gt;

&lt;p&gt;Live: &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;prismix.dev&lt;/a&gt;&lt;/p&gt;




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

&lt;p&gt;Three daily frustrations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;OpenAI / Anthropic status pages don't aggregate — I had 5 tabs open every morning&lt;/li&gt;
&lt;li&gt;AI news lives in 60 different RSS feeds and Twitter accounts&lt;/li&gt;
&lt;li&gt;MCP servers are scattered across awesome-lists with no canonical index&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Prismix solves all three on one page.&lt;/p&gt;




&lt;h2&gt;
  
  
  The stack
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Layer&lt;/th&gt;
&lt;th&gt;Choice&lt;/th&gt;
&lt;th&gt;Why&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Framework&lt;/td&gt;
&lt;td&gt;Astro 5 SSR&lt;/td&gt;
&lt;td&gt;Islands architecture, $0 hosting&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hosting&lt;/td&gt;
&lt;td&gt;Cloudflare Pages&lt;/td&gt;
&lt;td&gt;Free tier covers MVP&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Database&lt;/td&gt;
&lt;td&gt;Cloudflare Workers KV&lt;/td&gt;
&lt;td&gt;No DB to operate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Auth&lt;/td&gt;
&lt;td&gt;Self-rolled (email + GitHub)&lt;/td&gt;
&lt;td&gt;Saved $25/mo vs Clerk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Payments&lt;/td&gt;
&lt;td&gt;Ko-fi&lt;/td&gt;
&lt;td&gt;No Stripe overhead&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tests&lt;/td&gt;
&lt;td&gt;Vitest + MockKV&lt;/td&gt;
&lt;td&gt;1112 tests, runs in 8s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The whole thing costs $0 to run. That constraint forced 4 lessons.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 1 — KV writes are the rare resource
&lt;/h2&gt;

&lt;p&gt;Cloudflare's free tier gives you 100,000 KV reads/day but only &lt;strong&gt;1,000 writes&lt;/strong&gt;. I hit the wall at 1pm on day 12.&lt;/p&gt;

&lt;p&gt;The fix wasn't fewer writes - it was a diff-or-skip pattern: read the existing value, compare, only write if changed.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;setIfChanged&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;KVNamespace&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&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="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;existing&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// skip&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&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;Cron writes dropped from &lt;strong&gt;8,400/day → 600/day&lt;/strong&gt;. Reads are 100× more generous - trade them freely.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 2 - JSON.parse has a cliff at 1 MB
&lt;/h2&gt;

&lt;p&gt;The news index grew to 5,000 items. Each KV read returned a 3.2 MB JSON blob. SSR for &lt;code&gt;/news&lt;/code&gt; was taking 330ms just to parse.&lt;/p&gt;

&lt;p&gt;The fix was splitting the index into a "first page" slice (250 items, 165 KB) and a meta blob (facet counts, 12 KB). When the user hits &lt;code&gt;/news&lt;/code&gt; with no filters or pagination, we only read the slice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// hot path — 17ms&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;firstPage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;news:index:latest:firstpage:v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;meta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;news:index:latest:meta:v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// cold path (filters, sort, page&amp;gt;1) falls back to full index&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Parse time: &lt;strong&gt;330ms → 17ms&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 3 — CF Workers subrequest concurrency is per-request
&lt;/h2&gt;

&lt;p&gt;This one bit me hardest. &lt;code&gt;/mcp&lt;/code&gt; was rendering in 5.5s. Server-Timing showed 4.31s spent on KV reads.&lt;/p&gt;

&lt;p&gt;I assumed 60 parallel &lt;code&gt;kv.get()&lt;/code&gt; calls would run in parallel. They don't — Workers caps concurrent subrequests at ~6, so the rest queue.&lt;/p&gt;

&lt;p&gt;The fix: a denormalised snapshot blob updated by cron once a day.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Before: 60 parallel reads, serialised by concurrency limit → 4.31s&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;likes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;slugs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;kv&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="s2"&gt;`mcp:likes:&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)));&lt;/span&gt;

&lt;span class="c1"&gt;// After: 1 blob read → 30ms&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;snapshot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;kv&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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;mcp:bulk-engagement:v1&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;json&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Total &lt;code&gt;/mcp&lt;/code&gt; SSR time: &lt;strong&gt;5460ms → 380ms&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Lesson 4 — Even fast SSR feels broken without instant feedback
&lt;/h2&gt;

&lt;p&gt;After fixing perf, the site loaded in 200-400ms. Users still complained it was slow.&lt;/p&gt;

&lt;p&gt;The problem: the browser doesn't repaint the address bar until the new HTML arrives. For 200ms the user sees nothing — they click again, thinking the button didn't register.&lt;/p&gt;

&lt;p&gt;Two fixes:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pointerdown progress bar&lt;/strong&gt; — render a 2px green bar at the top of the screen on &lt;code&gt;pointerdown&lt;/code&gt;, before the navigation even fires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Astro &lt;code&gt;tap&lt;/code&gt; prefetch&lt;/strong&gt; — start fetching the next page on &lt;code&gt;pointerdown&lt;/code&gt;, finish during the click delay.
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pointerdown&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;link&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;target&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;closest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;a[href]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="nf"&gt;showProgressBar&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;Perceived load time dropped from "slow" to "instant" without a single SSR optimisation.&lt;/p&gt;




&lt;h2&gt;
  
  
  What didn't work
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Algolia for MCP search&lt;/strong&gt; — overkill; switched to in-memory tokenised index&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stripe&lt;/strong&gt; — Ko-fi's webhook + idempotency was 1 day vs Stripe's week&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clerk&lt;/strong&gt; — self-rolled OTP + GitHub OAuth was 3 days, $0/mo&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions &lt;code&gt;schedule:&lt;/code&gt;&lt;/strong&gt; — drifts by minutes, silently skips. Moved cron to cron-job.org&lt;/li&gt;
&lt;/ul&gt;




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

&lt;ul&gt;
&lt;li&gt;Per-service alert thresholds (Pro feature)&lt;/li&gt;
&lt;li&gt;AI news instant-notify via webhook (Discord / Slack)&lt;/li&gt;
&lt;li&gt;Public read API + SDK&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you've shipped on Cloudflare Workers and hit different walls, I'd love to hear what broke for you. Comments open.&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://prismix.dev" rel="noopener noreferrer"&gt;prismix.dev&lt;/a&gt;&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>webdev</category>
      <category>ai</category>
      <category>cloudflare</category>
    </item>
  </channel>
</rss>
