Testin my Blog
Testing my Blog
By THECODEDANIEL
2025
print("hello world")
Testing my Blog
By THECODEDANIEL
2025
print("hello world")
The Real Problem: The Gap Between Past Data and Present Issues
You’re running a React app in production. You have monitoring tools in place. You check the dashboard regularly. And yet.
Tuesday morning, you deploy. Everything looks good in staging. Users are happy.
By Thursday, things have changed.
Your app’s Largest Contentful Paint (LCP) jumps from 1.2s to 2.8s.
But you didn’t notice. Your users did.
By Friday, your app store reviews are filled with complaints: “This app is so slow.”
It’s too late now.
At this point, your monitoring tool tells you: “Yes, looking at the past hour’s data, LCP has indeed increased.”
But that’s just reporting after the fact.
“Monitoring” and “Alerting” Are Two Different Things—And Your Tools Are Missing One
You probably already have some form of monitoring in place:
What all of these have in common: they tell you “what happened” by looking at historical data.
In other words:
Monitoring = Looking at past data to identify problems after they occur
What you actually need is:
Alerting = Knowing immediately when a problem is happening right now
Existing tools excel at monitoring, but their alerting is limited to “notifications based on pre-configured metrics”—and even then, there’s a delay of minutes to tens of minutes while data aggregates.
During those minutes:
React teams have the tools to understand what happened, but lack the tools to know it’s happening.
Why This Gap Exists
Traditional monitoring and APM tools are designed for one purpose: detailed root cause analysis.
As a result, they require time to aggregate, analyze, and normalize data—which is why they end up showing you historical performance data rather than real-time signals.
What’s missing from the ecosystem is a dedicated tool that answers: “Is there a problem happening right now?”
The typical React team’s tool stack looks like this:
What You Actually Need: Simple Real-Time Alerting
The good news: you don’t need anything complex.
That’s it. With just these, your team can react immediately when production performance degrades.
The Answer: RPAlert Fills That Gap
We built RPAlert to solve exactly this problem.
RPAlert detects real-time performance degradation in your React app and sends instant alerts to Slack or Discord—nothing more, nothing less.
It’s the real-time alerting layer that fills the gap in your existing monitoring stack.
Getting Started in 1 Minute
npm install rpalert-sdk
// app.tsx or root layout
import { RPAlertProvider } from "rpalert-sdk/react";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<RPAlertProvider apiKey="YOUR_API_KEY">
{children}
</RPAlertProvider>
</body>
</html>
);
}
Once installed, RPAlert automatically:
What You’ll Actually See
Your Discord/Slack channel receives a message like this:
⚠️ LCP Alert — my-shop.com
LCP: 4.2s | Threshold: 2.5s | +68% over limit
Page: /products/winter-sale
Detected: 11:43 PM - Mar 25
App: my-shop.com
One message. Complete context. No noise.
Beyond real-time alerts, RPAlert also gives you a dashboard to track trends:
Performance trends over time:
RPAlert Is Not a “Monitoring Tool”—It’s an “Alerting Layer”
This is important: RPAlert is not trying to replace Datadog or New Relic.
Rather:
Think of RPAlert as a smoke detector. It tells you there’s a fire, but you still need your existing tools to find it and extinguish it.
The winning combination: RPAlert + your existing monitoring stack
This two-layer approach finally gives React teams a complete workflow: detect immediately, analyze deeply.
Pricing: Start Free, Scale as You Grow
Free plan:
Pro ($29.99/month):
Max ($49.00/month):
What Your Team Gets
Frontend engineers:
Product teams:
DevOps / Infrastructure:
Everyone:
Get Started Today
RPAlert is free to try. No credit card required.
It takes 5 minutes to set up.
Visit rpalert.com, create an app, drop the SDK into your React app, and experience real-time performance alerting for the first time.
That 30-second advantage between problem and awareness? It’s the difference between a graceful fix and a support crisis.
Questions?
Drop a comment below. We’d love to hear what production performance challenges your React teams are dealing with.
Studying for the AWS Solutions Architect Associate exam felt… repetitive.
I was going through practice tests, selecting answers, checking results — but something was missing.
I wasn’t actually learning.
Most platforms tell you if you’re right or wrong, but they don’t really help you understand why. And after a while, it just becomes passive memorization.
So I thought:
What if learning AWS felt more like Netflix… and less like a textbook?
🧠 The Idea
Instead of static quizzes, I wanted something interactive.
Something where:
each question feels like a small “episode”
you pause and think before answering
and then get a clear explanation, like a post-scene breakdown
That’s when I decided to build a simple AI-powered learning app using AWS PartyRock.
⚙️ What I Built
I created a Netflix-style AI AWS SAA Coach that:
Generates AWS exam-style questions
Supports beginner and intermediate levels
Lets you answer in a real exam-like flow
Gives instant explanations after each answer
Helps you learn from mistakes instead of just scoring
The goal was simple:
👉 turn passive studying into active learning
🎥 Demo
I recorded a short walkthrough showing how it works in practice:
👉 https://www.youtube.com/watch?v=cMg6FF2ZbmQ
📸 How It Looks
💡 What I Learned Building This
This project made me realize something important:
Learning cloud concepts isn’t just about information — it’s about interaction.
When you:
think before answering
see immediate feedback
understand mistakes
You remember things much better.
🚧 It’s Still a Beta
Right now, the app focuses on:
beginner
intermediate questions
But after sharing it and getting feedback, one thing became clear:
👉 The AWS SAA exam is heavily based on real-world, multi-service scenarios
So the next step is to expand this into:
advanced-level questions
scenario-based challenges
multiple AWS services combined (VPC + S3 + Lambda, etc.)
Basically:
more real exam-style thinking
🚀 What’s Next
I want to evolve this into something that:
simulates real AWS exam scenarios
adapts to your weak areas
and keeps the “interactive learning” feel
🙌 Would Love Your Feedback
This started as a small experiment, but I think the idea has potential.
If you’re preparing for AWS SAA or working with AWS:
👉 What topics or scenarios did you find most challenging?
🍿 Final Thought
What if learning complex topics didn’t feel like studying…
…but more like watching and interacting with a series?
Recruitment agencies process personal data at industrial scale. Every CV submission, every speculative application, every candidate database search involves personal data — and UK GDPR applies to all of it.
Lawful Bases
Talent Pools
Retaining a candidate CV after the vacancy closes requires explicit consent. This must be:
Sharing CVs with Clients
Retention Schedule
Job Board Sourcing
When contacting candidates sourced from job boards or LinkedIn, provide your privacy notice at or before first contact (Article 14 UK GDPR).
This guide was produced by Custodia — AI-powered GDPR compliance for small businesses. Scan your recruitment website free.
Overview
In this tutorial, you’ll learn why HTTP requests or API calls made directly from the browser fail with a “Failed to Fetch” error, and how to fix it using the proxy pattern.
Background
If you’ve ever tried to make an HTTP request or API calls to an external server directly from a frontend JavaScript app, you’ve likely seen this error:
It shows up in the browser console, but the request never goes through. It can feel confusing because the same call works fine in Postman or curl.
The root cause is not your code. It is a browser security mechanism called CORS, and understanding it is the first step to fixing it.
Same-Origin Policy
Browsers enforce a rule called the Same-Origin Policy. It restricts web pages from making requests to a different origin than the one that served the page.
Three things define an origin:
Protocol — http or https
Domain — localhost or example.com
Port — 3000, 8080, etc.
If any of these three differ between your frontend and the server you’re calling, the browser treats it as a cross-origin request.
For example:
| Frontend origin | API origin | Same origin? |
|---|---|---|
http://localhost:3000 |
http://localhost:3000 |
✅ Yes |
http://127.0.0.1:5500 |
https://www.youtube.com |
❌ No |
Cross-Origin Resource Sharing (CORS)
CORS is the mechanism that controls whether a cross-origin request is allowed.
When your browser makes a cross-origin request, it first sends a preflight request to ask the server: “Do you allow requests from my origin?” If the server doesn’t respond with the right headers — Access-Control-Allow-Origin — The browser blocks the request entirely and throws the “Failed to Fetch” error.
💡 Note: This is a browser restriction, not an API restriction. The same request works from a server, Postman, or curl because those environments don’t enforce the Same-Origin Policy.
Prerequisites
To follow along, make sure you have:
A basic understanding of HTML and JavaScript
Node.js v18 or higher installed
VS Code with the Live Server extension installed
Project Structure
We’ll be working with a simple YouTube Video Info app — it takes a YouTube URL and attempts to fetch the page directly from the browser. It’s a straightforward example that clearly demonstrates the “Failed to Fetch” CORS error.
Clone the broken version of the app:
git clone https://github.com/manueldezman/youtube-info.git
cd youtube-info
The project structure looks like this:
broken-version/
├── index.html # HTML structure
├── styles.css # Styling
└── app.js # Frontend logic — calls YouTube directly
To start the app:
Open the project folder in VS Code.
Click Go Live in the bottom right corner to start the Live Server(as shown below).
Your browser will open automatically at http://127.0.0.1:5500.
How a Direct Browser Call Triggers the CORS Error
Paste any YouTube URL into the input field and click Fetch Info. You’ll see the button spin for a moment, and then an error appears.
To understand the error, open DevTools by right-clicking anywhere on the page and selecting Inspect, as shown in the media below.

Your console should look like this:
The Cause of the Error
Your frontend is running at http://127.0.0.1:5500 (Live Server). YouTube is at https://www.youtube.com. These are two completely different origins — different protocols, different domains, different ports. The browser sends a preflight request to YouTube asking if cross-origin requests are allowed. YouTube doesn’t return the Access-Control-Allow-Origin header for direct page requests, so the browser blocks the request entirely before it even reaches YouTube.
Open app.js and look at the fetchInfo function:
async function fetchInfo() {
const url = document.getElementById('video-url').value.trim();
/* ⚠️ Direct browser-to-YouTube call — triggers CORS error */
const res = await fetch(url);
const html = await res.text();
...
}
The fetch(url) call goes directly to https://www.youtube.com from the browser, which triggers the CORS block. The request never reaches YouTube, and the app fails silently.
How to Fix the Error Using a Proxy Server
The fix is to stop calling YouTube directly from the browser and instead route the request through your own backend.
Your frontend is running at http://127.0.0.1:5500. YouTube is at https://www.youtube.com. These are two different origins — that’s why CORS blocks the request.
The solution is to introduce a Node.js proxy server that sits between the two. Your frontend calls your own backend at http://localhost:3000/fetch. The Node.js server calls YouTube server-to-server — no browser, no CORS enforcement — fetches the page, extracts the video title and description from the HTML meta tags, and returns clean data back to the frontend.
Here’s how to add the proxy to the project.
Step 1 — Create server.js
In the project root, create a new file called server.js:
broken-version/
├── index.html
├── styles.css
├── app.js
└── server.js ← add this
Step 2 — Add the proxy code
Paste the following into server.js:
const http = require('http');
const https = require('https');
const url = require('url');
const PORT = 3000;
function extractTitle(html) {
var match = html.match(/<title>([^<]*)</title>/i);
return match ? match[1].replace(' - YouTube', '').trim() : null;
}
function extractMeta(html, property) {
var match = html.match(new RegExp('<meta[^>]*(?:name|property)=["']' + property + '["'][^>]*content=["']([^"']*)["']', 'i'));
if (match) return match[1];
match = html.match(new RegExp('<meta[^>]*content=["']([^"']*)["'][^>]*(?:name|property)=["']' + property + '["']', 'i'));
return match ? match[1] : null;
}
const server = http.createServer(function(req, res) {
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
if (req.method === 'OPTIONS') {
res.writeHead(200);
res.end();
return;
}
var parsed = url.parse(req.url, true);
var videoUrl = parsed.query.url;
if (parsed.pathname !== '/fetch') {
res.writeHead(404, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Not found' }));
return;
}
if (!videoUrl) {
res.writeHead(400, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: 'Missing url parameter' }));
return;
}
https.get(videoUrl, { headers: { 'User-Agent': 'Mozilla/5.0 (compatible; proxy/1.0)' } }, function(youtubeRes) {
var body = '';
youtubeRes.on('data', function(chunk) { body += chunk; });
youtubeRes.on('end', function() {
var title = extractTitle(body) || extractMeta(body, 'og:title') || 'N/A';
var description = extractMeta(body, 'og:description') || extractMeta(body, 'description') || 'N/A';
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ title: title, description: description }));
});
}).on('error', function(e) {
res.writeHead(500, { 'Content-Type': 'application/json' });
res.end(JSON.stringify({ error: e.message }));
});
});
server.listen(PORT, function() {
console.log('Proxy server running at http://localhost:' + PORT);
});
This server runs on port 3000. It receives the YouTube URL from the frontend, fetches the page HTML server-to-server, extracts the title and description from the meta tags, and returns clean JSON back to the frontend.
Step 3 — Update app.js
In app.js, find the direct fetch call:
/* ⚠️ Direct browser-to-YouTube call — triggers CORS error */
const res = await fetch(url);
const html = await res.text();
const title = html.match(/<title>([^<]*)</title>/i);
document.getElementById('title').textContent = title ? title[1].replace(' - YouTube', '') : 'N/A';
document.getElementById('author').textContent = 'N/A';
output.style.display = 'block';
Replace it with:
/* ✅ Calls the local Node.js proxy — not YouTube directly */
const res = await fetch('http://localhost:3000/fetch?url=' + encodeURIComponent(url));
const data = await res.json();
document.getElementById('title').textContent = data.title || 'N/A';
document.getElementById('author').textContent = data.description || 'N/A';
output.style.display = 'block';
These also remove the lines that tried to parse the raw HTML; they are no longer needed since the proxy returns clean JSON.
Step 4 — Start the proxy server
Open a new terminal in the project folder and run:
node server.js
You should see:

Leave this terminal running. Keep Live Server running in VS Code at the same time.
Step 5 — Test it
Go back to your browser at http://127.0.0.1:5500, paste a YouTube URL, and click Fetch Info.
The “Failed to Fetch” error is gone. The request now flows from the browser to your own proxy server at localhost:3000, which fetches YouTube server-to-server and returns the video title and description to the browser.
Summary
In this tutorial, you have learnt why HTTP requests made directly from the browser fail with a “Failed to Fetch” error — and how to fix it using the proxy pattern.
The key takeaway is this: browsers enforce the Same-Origin Policy, which blocks cross-origin requests to servers that don’t return the right CORS headers. The proxy pattern solves this by routing your requests through your own backend — no browser restrictions, no exposed secrets.
This pattern works for any external server, YouTube, payment APIs, AI platforms, or anything else your frontend needs to talk to securely.
While this tutorial uses a YouTube URL fetch to demonstrate the error, the same proxy pattern applies when calling any external API — whether it’s an AI platform like Gemini or OpenAI, a payment API like Stripe, or any other service that blocks direct browser requests. The only difference is that, with APIs, your proxy also handles authentication by securely storing the API key in environment variables on the server, keeping it out of the browser entirely.
Connect with me on my socials if you have any questions or want to follow along with future tutorials.
Thank you for reading, and I look forward to seeing you next time!
cors #javascript #nodejs #webdev #frontend #proxy #apidevelopment
Back in 2023, I wrote a post titled “The upcoming SaaS bubble burst” where I argued that AI would enable individual developers to replicate SaaS products at a fraction of the cost, turning high-margin businesses into commodities.
I was wrong about the timeline. It’s happening right now.
The Legal Hack That Started It All
In 1982, a company called Phoenix Technologies wanted to create IBM PC-compatible computers. The problem? IBM’s BIOS was copyrighted. Their solution was a “clean room” process: one team reverse-engineered the BIOS and wrote a functional specification, then a completely separate team—who had never seen the original code—implemented a new BIOS from scratch based solely on that specification.
It worked. Courts ruled it legal because the second team independently created the code; they never copied anything. This became established legal precedent.
Fast forward to March 2025: a satirical (but functional) service called Malus.sh appeared, offering “Clean Room as a Service.” The name itself—Latin for “evil”—was a joke, but the concept was deadly serious. Pay them, upload your dependency manifest, and their AI systems would reimplement your open source dependencies under any license you wanted. GPL becomes MIT. AGPL becomes proprietary.
The service was presented at FOSDEM as a warning to the open source community. The Hacker News discussion exploded with over 1,400 comments debating whether this was the end of copyleft or just a clever thought experiment.
Around the same time, someone attempted exactly this with the chardet Python library—using Claude to rewrite it from LGPL to MIT. The open source community was furious.
But here’s what truly terrifies me: this is unstoppable.
The Two Directions of Liberation
There are two scenarios playing out simultaneously:
1. Open Source → Commercial (GPL → MIT → Proprietary)
Companies have always hated copyleft licenses like GPL and AGPL because they require sharing modifications. If you can reimplement the software cleanly, you eliminate that obligation. No more “viral” licensing concerns. No more open source compliance headaches.
2. Commercial → Open Source
This is the scenario most people aren’t talking about. SaaS applications don’t expose their source code, but they do expose their behavior. Every button click, every API response, every error message is observable. Feed that to an LLM, produce a specification, have another LLM implement it. The source code was never “seen.”
For SaaS, the clean room defense is even stronger because there’s literally no source code to contaminate the process.
Why This Is Unstoppable
I know what you’re thinking: “But the LLMs were trained on that code! They’ve seen it!”
You’re right. Someone demonstrated that Claude can reproduce chardet’s source code verbatim from memory, including the license headers. The training data is contaminated.
But here’s the thing: the architecture can be fixed.
Imagine a two-LLM system:
Or a three-LLM system. Or more. Each hop makes the provenance harder to trace. Add different base models, different hosting providers, different jurisdictions. Good luck proving in court that the final output was “copied.”
For SaaS, it’s even simpler. Point an AI agent at the UI. Let it click around, observe responses, document behavior. Feed that documentation to a clean model. Where’s the infringement?
The legal standard for clean room implementation was designed for humans with imperfect memories working for months. When AI can do it in hours with perfect documentation, the entire framework breaks down.
The Government Dilemma
Governments will eventually have to respond. But their options are all bad:
Software patents: The only real way to protect ideas (not just expression) is patents. But broad software patents would stall innovation even more than copyright does. We already tried this in the 2000s with patent trolls. Nobody wants to go back.
Stronger copyright enforcement: Unenforceable across borders. The moment one country allows this, the “liberated” code can be downloaded legally from servers in that jurisdiction.
Do nothing: Tech companies lose their moats. VC-funded SaaS collapses.
I expect different regions to react differently:
At the end of the day, if one country in the world allows AI-powered clean room reimplementation, you’ll be able to download that “liberated” code from that country legally.
The Ironic Outcome: Everything Becomes Open Source
Here’s the twist I didn’t see coming: GPL exists to ensure software stays free forever. Richard Stallman created it because he believed users should have the freedom to run, study, modify, and share software.
AI clean rooms might achieve exactly that outcome—just not in the way anyone intended.
Think about it:
The end state? Everything converges to effectively public domain. You can’t maintain a proprietary advantage when anyone can recreate your software in hours. You can’t maintain copyleft when it can be circumvented just as easily.
Source code becomes a common good. Not because of ideology, but because protection becomes technically impossible.
What Can You Actually Sell?
When code has no scarcity, what’s left?
Convenience. That’s it.
You can run the software yourself for free. Set up your own servers, handle updates, manage disaster recovery, deal with security patches—or pay someone a monthly fee to do it for you.
But here’s the problem: when self-hosting becomes trivial (thanks to agentic SRE and AI-powered infrastructure management), convenience becomes less valuable. Margins compress. The race to the bottom accelerates.
Winners and Losers
The Real Winners: Cloud Infrastructure Providers
AWS, GCP, Azure. They own the hardware, the data centers, the network infrastructure. Whether you’re running open source or proprietary software, you’re paying them for compute. They win regardless of who owns the code.
In the short term, there might be shock to the system if an AI company like OpenAI fails spectacularly. That could damage cloud valuations temporarily. But long term? I’m bullish.
The Losers: Pure SaaS Companies
Any SaaS company whose value proposition is primarily “we wrote software that does X” is in trouble. If your moat is code, you no longer have a moat.
And here’s the brutal reality: most SaaS companies were never designed for low-margin economics. They have massive operating costs—large engineering teams, expensive offices, bloated sales organizations, venture debt—all predicated on the assumption of 70-80% gross margins. When margins collapse to 20-30% (or lower), the math simply doesn’t work. They can’t cut costs fast enough. Many will go bankrupt.
This isn’t a slow decline. SaaS companies with high burn rates and no data moat will face an existential crisis the moment a credible open source alternative appears. And with AI, that alternative can appear overnight.
The Exception: Data Moats
Some SaaS companies will survive—specifically, the ones that control proprietary data that can’t be recreated:
If your software generates or aggregates unique data that can’t be reproduced, you have something AI can’t replicate. If your software is just features, you’re toast.
The Next Frontier: Open Source Hardware
I cannot speak for Richard Stallman, but I believe the vision behind GPL was to ensure that software would be free forever—like in the early days of computing when code was shared openly.
AI-powered clean rooms may finally get us there, ironically through market forces rather than ideology.
The next frontier is open source hardware. The designs can be liberated just like software, but manufacturing remains controlled by corporations with factories, supply chains, and regulatory approvals. Still, open hardware could finally kill proprietary drivers—another piece of the dream.
I personally believe this trajectory is better for consumers. Software becomes cheaper. Innovation accelerates. The tax on digital goods imposed by intellectual property regimes gradually evaporates.
Final Thoughts
The SaaS bubble I predicted in 2023 is bursting. The mechanism is just different than I expected—not market forces alone, but a fundamental breakdown in the ability to protect software as property.
In 5-10 years, I expect:
Is this good? Is this bad? Honestly, I don’t know. But I do know it’s happening. And the teams that prepare for a world where code has no scarcity will be the ones that thrive.
What do you think? Am I too pessimistic about SaaS? Too optimistic about open source? I’d love to hear your perspective in the comments.
If you found this interesting, you might also enjoy my previous posts on Agent Driven Development and the original SaaS bubble prediction from 2023.
This article was originally published on LucidShark Blog.
RSA Conference 2026 is running right now in San Francisco, and the headline finding from the AI security track is blunt: 100% of tested AI coding environments are vulnerable to prompt injection attacks. That includes Claude Code, Cursor, Windsurf, GitHub Copilot, Roo Code, JetBrains Junie, Cline, and every other major tool developers are using to ship code today.
Researcher Ari Marzouk disclosed a shared attack chain – Prompt Injection → Agent Tools → Base IDE Features – that results in 24 assigned CVEs and an AWS advisory (AWS-2025-019). The RSAC session “When AI Agents Become Backdoors: The New Era of Client-Side Threats” demonstrates how Cursor, Claude Code, Codex CLI, and Gemini CLI can be transformed into persistent backdoors through this chain.
This is not a theoretical concern. It is happening on stage at the most-attended security conference in the world, right now. If your engineering team is shipping AI-generated code – and most are – you need to understand what this means in practice.
What the Attack Chain Actually Looks Like
The prompt injection → agent tools → IDE chain works because modern AI coding tools operate with deep system access. They read your file system, execute commands, manage git, call external APIs. The trust boundary between “AI assistant” and “privileged local process” is essentially nonexistent in most implementations.
Here is the sequence researchers demonstrated:
The persistence piece is what separates this from classic prompt injection. Standard injection attacks are session-scoped. Memory-poisoned agentic systems carry the foothold forward indefinitely. Researchers found instances where injected instructions were recalled and executed days or weeks after the initial compromise.
Separately, Cursor and Windsurf are built on outdated Chromium/Electron versions, exposing approximately 1.8 million developers to 94+ known browser CVEs. CVE-2025-7656 – a patched Chromium flaw – was successfully weaponized against current Cursor and Windsurf releases. This is a different class of problem: supply chain negligence rather than model-level vulnerability, but equally exploitable.
The Vibe Coding Connection
“Vibe coding” is the conference’s other villain narrative this year, and rightly so. The Moltbook breach – 1.5 million API keys, 35,000 emails, an entire database exposed in under three minutes – is being cited by speaker after speaker as the canonical example of what happens when you deploy AI-generated code without meaningful review.
The problem is structural, not individual. Baxbench benchmarking data presented at RSAC confirms that no flagship model is reliably producing secure code at scale. The base rate of security defects in AI-generated code is high enough that “review it carefully” is not a process – it is wishful thinking without tooling to back it up.
Unit 42 provided the number that should concentrate minds: mean time to exfiltrate data has collapsed from nine days in 2021 to two days in 2023 to roughly 30 minutes by 2025. When your attacker moves in 30 minutes, the 20-minute cloud code review that runs after you merge is not a defense.
Anthropic’s Response: Code Review for Claude Code
Anthropic launched Code Review for Claude Code on March 9, 2026 – two weeks before RSAC. The product dispatches multiple AI agents in parallel on each PR, cross-verifies their findings, and surfaces ranked issues as inline annotations. By Anthropic’s internal numbers, substantive review comments on PRs went from 16% to 54% after deploying it.
It is a real product solving a real problem. But the pricing model and architecture create three gaps that matter for high-velocity teams:
- **Cost at scale:** Reviews average $15–$25 per PR, billed on token usage. A team merging 50 PRs per week spends $750–$1,250 per week on review alone. That is $40,000–$65,000 per year for review coverage, before you add the human review hours that still happen on top of it. CodeRabbit offers unlimited PR reviews at $24/month per user by comparison.
- **Timing:** Typical completion time is 20 minutes per review. Anthropic's architecture runs post-push, not pre-commit. By the time the review lands, the code is already in your branch history, your CI artifacts, and possibly triggering downstream pipelines.
- **Zero Data Retention incompatibility:** Code Review is explicitly unavailable for organizations with Zero Data Retention enabled. If your security posture requires ZDR - common in fintech, healthcare, and defense - you cannot use this product at all.
None of this is a criticism of Anthropic’s engineering. It reflects a fundamental tension between cloud-based agentic review and the constraints of production-grade security programs.
The Threat Model Is Pre-Commit, Not Post-Merge
Here is the thing the RSAC findings make clear: the highest-value intervention point is not PR review. It is the quality gate that runs before the code leaves your machine.
If an AI coding tool can be manipulated into writing a hardcoded credential, a disabled Row Level Security policy, or an unvalidated deserialization path, you want to catch that before it touches a PR. Once it is in a PR, you have already:
- Pushed the code to a remote server
- Made it visible in your organization's PR history
- Potentially triggered webhooks, notifications, or CI pipelines
- Created a git object that persists even after the branch is deleted
Pre-commit, pre-push quality gates running locally eliminate the entire class of “the AI wrote something dangerous and I did not notice” failures before they become an event. No network round-trips, no per-review billing, no ZDR conflicts, no 20-minute wait.
What a Local Gate Actually Checks
A production-grade local quality gate needs coverage across multiple domains simultaneously. Security scanning alone is not sufficient – the RSAC findings show that attackers are exploiting misconfigurations, outdated dependencies, and infrastructure settings, not just code-level bugs.
The minimum viable gate for an AI-assisted workflow in 2026 should cover:
- **SAST (Static Application Security Testing):** Catches injection vulnerabilities, hardcoded secrets, unsafe function calls, and known vulnerability patterns in source code.
- **SCA (Software Composition Analysis):** Scans dependencies for known CVEs. AI-generated code frequently pulls in dependencies without validating their security posture.
- **IaC validation:** Checks Terraform, CloudFormation, Kubernetes manifests, and Dockerfiles for misconfigurations. The Moltbook breach trace directly to disabled RLS - an infrastructure configuration, not a code bug.
- **Container scanning:** Validates base images and installed packages against known vulnerability databases.
- **Type checking and linting:** Not glamorous, but AI models produce type errors and lint violations at a rate that compounds significantly at scale. Catching them locally keeps the feedback loop tight.
- **Coverage enforcement:** AI-generated code frequently lacks test coverage. Enforcing a coverage floor locally prevents the "it works in my demo" ship-it mentality.
- **Duplication detection:** AI models sometimes generate near-identical implementations of existing functions. Catching duplication early prevents maintenance debt from compounding.
Running all of this post-merge is too late. Running it in a cloud service at $25/PR is too expensive and too slow. Running it locally on every commit, with results committed to git as a QUALITY.md health report, gives you a continuous, auditable record of your codebase’s security posture.
MCP Integration Closes the Loop with Claude Code
The RSAC prompt injection findings describe Claude Code as a vulnerable surface. That is accurate and worth taking seriously. But the same MCP integration that creates the attack surface also enables the defense.
When a local quality gate integrates with Claude Code via MCP, the feedback loop becomes: AI writes code → local scanner finds the issue → AI fixes the issue – before the code ever leaves the developer’s machine. The AI is not just generating code; it is operating inside a quality constraint that catches its own errors in real time.
This is the architecture the RSAC prompt injection findings implicitly argue for: don’t try to patch the model’s behavior, impose external constraints that validate output before it ships. The model does not need to be secure; the system does.
The Practical Takeaway from RSAC 2026
The conference’s headline finding – that every AI IDE is vulnerable – does not mean you stop using these tools. It means you stop treating them as trusted final authors of production code.
The teams that will emerge from this period with clean security records are not the ones running the most sophisticated cloud-based post-merge review. They are the ones who built a quality gate into the commit workflow itself, so that AI-generated code is continuously validated against security, correctness, and coverage standards before it ever becomes someone else’s problem.
The investment is a one-time configuration, not a recurring per-PR cost. The latency is seconds, not 20 minutes. The data never leaves the machine.
If you are shipping AI-generated code and you do not have a local quality gate, RSAC 2026 is a reasonable moment to change that.
✅ Get Started with LucidShark LucidShark provides local-first security scanning for AI-generated code. Install it once, integrate with Claude Code, and catch vulnerabilities before they reach production. curl -fsSL https://raw.githubusercontent.com/toniantunovi/lucidshark/main/install.sh | bash ./lucidshark scan –all Configure your checks in lucidshark.yml , run lucidshark scan , and get a QUALITY.md health report committed directly to your repo. Works with Python, TypeScript, JavaScript, Java, Rust, Go, and more. Apache 2.0, no server required. See full installation guide →
Your MacBook is more than a laptop — it’s mission control. The difference between devs who feel scattered and devs who feel in command often comes down to the apps running in the background.
After years of tweaking my setup, here are the 7 Mac apps that turned my MacBook into a proper developer command center.
1. Raycast — The Universal Launcher
Raycast replaced Spotlight and never looked back. It’s a launcher, clipboard manager, snippet expander, and window manager rolled into one. The extension ecosystem is wild — I use it to search GitHub repos, manage Jira tickets, and convert units without ever opening a browser. If your fingers leave the keyboard, you’re doing it wrong.
Price: Free (Pro $8/mo)
2. Warp — The Terminal, Reinvented
Warp is what happens when you build a terminal from scratch in 2026 instead of iterating on a 40-year-old design. Block-based output, AI command suggestions, and collaborative sharing make it feel like a modern IDE for your shell. The input editor alone (with proper cursor movement and selections) is worth the switch.
Price: Free (Teams plans available)
3. Rectangle — Pixel-Perfect Window Management
Rectangle gives you keyboard shortcuts for snapping windows to halves, thirds, quarters, and custom sizes. It’s open source, lightweight, and does exactly one thing perfectly. I keep my terminal on the left half, editor on the right, and documentation in a quarter tile. No mouse required.
Price: Free (open source)
4. TokenBar — Real-Time LLM Cost Tracking
TokenBar sits in your menu bar and tracks every token you send to OpenAI, Anthropic, and other LLM APIs in real time. If you’re using AI coding assistants, agents, or building LLM-powered features, you need visibility into what you’re actually spending. One glance at your menu bar tells you exactly where your budget stands — no dashboards, no spreadsheets.
Price: $5 lifetime
5. Monk Mode — Feed-Level Distraction Blocking
Monk Mode doesn’t block entire websites — it blocks the feeds inside them. You can still use YouTube for tutorials but the recommendation feed disappears. Same for Twitter, Reddit, LinkedIn. It’s surgical. Most blockers are all-or-nothing; Monk Mode lets you keep the useful parts of the web while removing the infinite scrolls that eat your afternoon.
Price: $15 lifetime
6. CleanShot X — Screenshots That Actually Communicate
CleanShot X handles screenshots, screen recordings, scrolling captures, and annotations. The “Quick Access” overlay lets you grab a previous capture instantly, and the built-in annotation tools mean you never need to open Preview or Figma just to draw an arrow. For bug reports, documentation, and async communication, it’s essential.
Price: $29 one-time
7. Bartender — Tame the Menu Bar
Bartender hides the menu bar icons you don’t need and shows the ones you do. When you’re running 7+ menu bar apps (and you will be after this list), your menu bar gets cluttered fast. Bartender keeps it clean by tucking secondary icons behind a single click while keeping your critical status indicators visible.
Price: $16 one-time
The Command Center Effect
None of these apps are flashy. They won’t impress anyone at a demo. But together, they create an environment where information flows to you passively, distractions stay out of your peripheral vision, and every action is a keyboard shortcut away.
That’s what a command center is — not a fancy monitor setup, but a system where your tools work for you instead of demanding your attention.
What’s in your Mac dev setup? Drop your favorites below 👇
We just finished Sprint 0 of a project to rebuild a LinkedIn campaign management platform from scratch — using AI agents as the primary developers, operating under a strict agile methodology enforced by an MCP (Model Context Protocol) server. This post is the honest record: what we attempted, what we actually built, what failed, and how AI participated in every phase.
What Is This Project?
ORCHESTRATE is a marketing platform that manages content scheduling across LinkedIn pages. The V2 system — a 102-tool MCP server with React UI, Docker deployment, and 4 active LinkedIn pages — has been running in production. V3 is an ambitious expansion: YouTube integration, podcast generation, audio narration, AI-assisted news generation, and multi-channel publishing at scale.
Sprint 0 was pure infrastructure. No new features. No UI changes. Just the foundation that V3 needs to exist.
What We Attempted
The original Sprint 0 plan had 5 stories covering:
Two stories were descoped mid-sprint (OAS-040 and OAS-041 were reconstituted as OAS-042 and OAS-073) — the right call, since the original scope was too ambitious for a foundation sprint.
What We Actually Built
18 tickets completed through full documentation-driven TDD. Every ticket went through 8 phases: write docs → bind docs → write failing tests → verify failures → implement → refactor → validate → done.
The concrete deliverables:
468 tests. 464 passing. 4 pre-existing Dev.to API failures (credential-related, not code bugs). Zero flaky tests.
What Worked
Documentation-Driven TDD is genuinely effective. Writing documentation before tests before code forces contract thinking. You discover edge cases during the doc phase — “what happens if the activity line is malformed JSON?” — before writing a single test. Every service emerged with cleaner interfaces than if we’d coded first.
In-memory architecture was the right Sprint 0 call. All services use TypeScript Maps and arrays — no database, no file I/O, no external dependencies. This made tests fast (~0.01s per test), deterministic (no flaky tests from I/O timing), and eliminated environment-specific configuration. The trade-off: zero data survives a process restart. That’s acceptable for Sprint 0 but becomes the primary risk for Sprint 1.
The audit trail pattern proved its value. The V2 Migration Bridge creates an append-only audit record for every migrated item, linking V2 source ID → V3 target ID with a SHA-256 checksum of the source data. This means rollback isn’t “delete everything” — it’s “trace each migrated record back to its source and remove precisely that.” The migration verifier can then validate the rollback was clean.
Stratified sampling in verification catches issues efficiently. Even at 10% sample rate, the verifier samples at least 1 record per entity type (posts, pages, activity), evenly spaced across the dataset. This means a single corrupted record in any entity type gets caught without scanning everything.
What Failed
Sprint planning overestimated capacity. We planned 5 stories and had to descope 2 mid-sprint. The DD TDD ceremony — 8 phases per ticket with evidence comments at each — adds real overhead. Our retrospective concluded that 18 infrastructure tickets is realistic velocity, but feature tickets (with more complex integration) should target 15-16.
No user-visible progress. Sprint 0 delivered zero features that users can see or interact with. The 4 LinkedIn pages continue operating on V2 infrastructure unchanged. This is correct engineering (build foundations first) but creates stakeholder communication challenges.
Test fixtures are duplicated. The V2 test data (pages, posts, activity lines) is copy-pasted across multiple test files. This is technical debt — a change to the fixture format requires updating every copy. Sprint 1 should extract shared fixtures to a tests/fixtures/ module.
Security is deferred. Credentials are stored in-memory with no encryption at rest. No integration with external secret managers. No access audit logging. This is acceptable while everything is in-memory (credentials vanish on restart anyway) but must be addressed before any production deployment with persistence.
The 4 Dev.to API test failures persisted all sprint. These tests fail because they hit a real external API that returns 422 errors — not code bugs, but they pollute the test report and should be fixed or explicitly skipped with documentation.
How AI Participated
This is where it gets interesting. Sprint 0 was executed entirely by AI agents operating under the ORCHESTRATE Agile MCP framework. Here’s what that means concretely:
The MCP server mechanically enforces methodology. It’s not a suggestion system — it blocks actions that violate the lifecycle. Try to write code without completing inception? Blocked. Try to skip the VERIFY phase in TDD? Blocked. Try to create a ticket without DONE criteria? Blocked. The AI agents operate within these constraints, not around them.
AI personas own specific domains. Each ticket is assigned a named AI persona based on content — Query Quinn (database) for migration work, Guard Ian (security) for credentials, Pip Line (DevOps) for infrastructure. The persona brings domain expertise and decision style to every phase of the ticket. This isn’t role-playing; it’s scoped expertise application.
The retrospective was AI-conducted. 11 AI personas spoke in turn order (infrastructure-closest first: Pip Line → Query Quinn → Guard Ian → … → Owen Pro), each giving an honest assessment of what they saw, what worked, what failed, and what they want changed. The retrospective identified 6 cross-persona themes and 3 unresolved tensions that will shape Sprint 1 planning.
Memory persists across conversations. Lessons learned and decisions made are stored in a program-level memory system. When Sprint 1 begins, the agents can recall “in-memory architecture was chosen for velocity but creates persistence risk” without re-discovering it. 5 lessons and 3 decisions from Sprint 0 are now stored and retrievable.
What AI can’t do (yet): The MCP’s recall_memory search is keyword-based, not semantic — specific technical queries return nothing while broad terms return everything. The TDD ceremony adds overhead that a human developer might shortcut judiciously; AI follows it literally every time. Context window exhaustion forces conversation restarts that create ramp-up overhead.
Provenance
Every claim in this post traces to source artifacts:
tool/mcp-server/src/services/ — v2-migration.ts, backup-manager.ts, migration-verifier.ts, credential-rotation-scheduler.tsThis post was drafted by an AI agent (Pip Line persona, Claude Opus 4.6) as ticket OAS-072-T5, following full DD TDD methodology. The draft was reviewed against three source documents before publication.
What’s Next
Sprint 1 priorities (decided in retrospective):
Target: 16 tickets. First real test of whether the velocity baseline from Sprint 0 holds when we add integration complexity.
This post is part of a series documenting the ORCHESTRATE Marketing Platform V3 build. Sprint 0 covered infrastructure. Sprint 1 will cover persistence, CI, and the first user-visible feature. All development is AI-agent-driven with full traceability.
There’s a dirty secret in mental wellness tech: most apps ignore the most powerful therapeutic tool humans have had for 15,000 years — their pets.
I spent the last 6 months building an AI layer on top of pet-assisted therapy data. What I found changed how I think about emotional AI entirely.
The Problem With Wellness Apps
Every burnout-prevention, anxiety-tracking, mood-journaling app follows the same playbook:
It doesn’t work long-term. Why? Because it’s self-referential. You’re asking a depressed brain to accurately report on its own depression.
Pets short-circuit this entirely.
What Dogs Know That Algorithms Don’t
A dog doesn’t ask you how you’re doing. It detects it — through micro-movements, scent, heart rate variability, breathing rhythm. Then it acts.
I started wondering: can we build that detection layer artificially?
import anthropic
import cv2
import mediapipe as mp
def analyze_user_state(video_frame):
"""
Rough sketch: use pose + facial landmarks to infer emotional state
then route to appropriate pet-companion response
"""
mp_face_mesh = mp.solutions.face_mesh
mp_pose = mp.solutions.pose
with mp_face_mesh.FaceMesh(static_image_mode=True) as face_mesh:
results = face_mesh.process(cv2.cvtColor(video_frame, cv2.COLOR_BGR2RGB))
if not results.multi_face_landmarks:
return {"state": "unknown", "confidence": 0.0}
landmarks = results.multi_face_landmarks[0]
# Eye aspect ratio for stress detection
# Brow furrow distance for anxiety
# Mouth corner deflection for mood
features = extract_facial_features(landmarks)
return classify_emotional_state(features)
def classify_emotional_state(features):
client = anthropic.Anthropic()
prompt = f"""
Given these facial feature measurements:
- Eye openness: {features['eye_ar']:.3f} (1.0 = wide open)
- Brow tension: {features['brow_distance']:.3f} (lower = more furrowed)
- Lip corner angle: {features['lip_angle']:.1f} degrees
Classify the emotional state and suggest a pet-companion interaction:
Return JSON: {{"state": str, "intensity": 0-10, "suggested_interaction": str}}
"""
response = client.messages.create(
model="claude-3-5-sonnet-20241022",
max_tokens=256,
messages=[{"role": "user", "content": prompt}]
)
return json.loads(response.content[0].text)
This is a simplified sketch — production needs proper privacy handling, consent flows, and on-device processing. But the concept holds.
The Surprising Results
When I ran this against session data (anonymized, consented), the AI companion responses that worked best weren’t the ones that addressed the emotional state directly.
They were the ones that redirected attention outward — exactly what a dog does when it drops a toy in your lap.
INTERACTION_MATRIX = {
"anxious": [
"Your virtual companion nudges you with a tennis ball 🎾",
"Time for a 5-minute 'walk' — step outside, we'll wait",
"[Pet name] is doing the head-tilt thing. Look."
],
"low_energy": [
"Lie on the floor for 2 minutes. Seriously. It works.",
"Your companion wants belly rubs. Who's really winning here?"
],
"stressed": [
"60-second breathing exercise — your pet's watching your chest rise",
"Name 3 things your pet would find interesting right now"
]
}
Low-tech responses. High emotional resonance.
Why This Matters for AI Developers
We tend to over-engineer emotion AI. We want sentiment models, voice analysis, wearable integration.
But the insight from pet therapy research is brutally simple:
Consistent, non-judgmental presence beats sophisticated intervention.
Your AI companion doesn’t need to be a therapist. It needs to be a dog.
The Architecture That Worked
User State Detection
↓
Emotional Routing Layer
↓
Response Selection (NOT advice-giving)
↓
Attention Redirection
↓
Micro-engagement Loop (2-5 min max)
No therapy. No diagnosis. No “have you tried mindfulness?” Just presence, playfulness, and pattern interruption.
What’s Next
I’m continuing this research with the team at MyPetTherapist — a platform that connects the science of animal-assisted therapy with AI-augmented wellness tools. If you’re building in this space or just curious about the intersection of pet behavior research and emotional AI, worth a look.
The takeaway for devs: Before you reach for a complex ML pipeline, ask — what would a dog do? Sometimes the answer is “drop a tennis ball and wag.” That’s valid UX.
What’s the simplest intervention you’ve shipped that had the biggest emotional impact? Drop it in the comments.